Compare commits

..

528 Commits

Author SHA1 Message Date
9e75ee09bb fix(deps): update garronej_modules_update 2023-03-18 09:11:03 +00:00
93fdcb8739 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2023-03-16 13:33:01 +01:00
aca926e202 Fix link script command 2023-03-16 13:31:56 +01:00
9941027b10 Update package.json 2023-03-15 12:45:58 +01:00
9104de4290 Merge pull request #263 from mkreuzmayr/main
Fix start container script paths for windows
2023-03-15 12:45:43 +01:00
5dc692809c Fix start container script paths for windows 2023-03-15 10:07:01 +01:00
8dc1d1bd21 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2023-03-13 10:47:10 +01:00
fe588485a9 Update changelog 2023-03-13 10:47:02 +01:00
19ef1d7025 Bump version 2023-03-13 10:44:46 +01:00
62523a8662 Merge pull request #260 from InseeFrLab/lordvlad/issue257
Run keycloakify behind corporate proxy
2023-03-13 10:44:08 +01:00
6e97665e2e Merge branch 'main' into lordvlad/issue257 2023-03-09 18:33:18 +01:00
4988680353 Update description 2023-03-09 18:30:58 +01:00
c5de5c20c7 Bump version 2023-03-08 23:21:44 +01:00
1a0fee1aa2 Make things cleaner 2023-03-08 23:21:32 +01:00
06a44603cd Release candidate 2023-03-08 22:32:45 +01:00
e48459762e Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2023-03-08 22:28:46 +01:00
235ebeae97 Bump version 2023-03-08 22:25:10 +01:00
dfe909606e Deprecate useFormValidationSlice 2023-03-08 22:24:51 +01:00
6fd0c7726c Merge branch 'lordvlad/issue257' of github.com:InseeFrLab/keycloakify into lordvlad/issue257
* 'lordvlad/issue257' of github.com:InseeFrLab/keycloakify:
  Only test build on LTS node version
  Update dependency evt to ^2.4.15
  Update README.md
  Bump version
  Avoid passing unessesary realm values in the error.ftl page
2023-03-08 10:25:10 +01:00
819e045811 feat(proxy): respect XDG_CACHE_HOME if set 2023-03-08 10:24:52 +01:00
1ba780598d Relase candidate 2023-03-07 18:18:37 +01:00
aeb0cb3110 Only test build on LTS node version 2023-03-07 18:18:04 +01:00
88923838c5 Bump version 2023-03-07 17:29:30 +01:00
df9f6fd7fd Merge branch 'main' into lordvlad/issue257 2023-03-07 17:16:24 +01:00
98e46d6ac9 Update dependency evt to ^2.4.15 2023-03-07 17:07:49 +01:00
daff614fb4 Update README.md 2023-03-07 17:07:48 +01:00
5ea324c7f2 Bump version 2023-03-07 17:07:48 +01:00
23fedbf94a Avoid passing unessesary realm values in the error.ftl page 2023-03-07 17:07:45 +01:00
593d66d8d6 style: remove unused dependency 2023-03-07 16:45:17 +01:00
851dcd5bf7 Run keycloakify behind corporate proxy
Fixes #257

Use make-fetch-happen for the download step. This lib will use `PROXY`
and `HTTPS_PROXY` and `NO_PROXY` env vars out of the box.

Additionally we'll try and get proxy config from npm. Unfortunately,
the most straightforward options is to call npm config to do this, since
npm  config is not easily extracted as a lib and we don't want to
replicate the resolution mechanisms.
2023-03-07 16:43:12 +01:00
2e919681ae Update dependency evt to ^2.4.15 2023-03-07 10:14:46 +00:00
5da68cd48c Update README.md 2023-03-05 23:37:37 +01:00
27fdaeff46 Bump version 2023-02-27 11:55:39 +01:00
53c0079656 Use extract instead of subtype to ease copy paste into theme repo 2023-02-27 11:55:25 +01:00
93780b77e0 Bump version 2023-02-27 11:32:14 +01:00
b712ed0421 Avoid using tsafe utils to avoid forcing user to install tsafe 2023-02-27 11:32:00 +01:00
ee96f1b345 Bump version 2023-02-27 11:29:23 +01:00
d13464df3d Get rid of the ReactComponent type, classes based component are no longer used 2023-02-27 11:29:05 +01:00
6bde2e4d96 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2023-02-27 10:39:44 +01:00
0a4953c020 Bump version 2023-02-27 10:39:37 +01:00
96c488880c Abstract away Template logic 2023-02-27 10:39:22 +01:00
7e0adf3f66 Update README.md 2023-02-26 17:32:35 +01:00
09f716440a Bump version 2023-02-26 16:41:47 +01:00
2251c84171 Use the new syntax for importing as type 2023-02-26 16:37:06 +01:00
5cfe78dcd1 Update prettier config 2023-02-26 15:39:03 +01:00
6a48325132 Be more relax on the type safety to avoir headache 2023-02-26 15:37:52 +01:00
294be0a79a see prev commit 2023-02-26 15:36:52 +01:00
c94b264b44 Don't need a dir for a single file 2023-02-26 15:36:35 +01:00
7220c4e3e3 Fix deepAssign 2023-02-26 15:35:57 +01:00
5aadeba2ec fix clsx 2023-02-26 15:35:30 +01:00
0f47a5b6ba Small Template refactor 2023-02-25 20:11:55 +01:00
36f32d28f2 Stop auto updating powerhooks 2023-02-25 19:21:55 +01:00
6d69ccf229 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2023-02-25 19:21:17 +01:00
37073b42be Avoir introducing breaking changes for CSS only setup 2023-02-25 19:19:46 +01:00
837501c948 Refactor 2023-02-25 18:26:39 +01:00
b300966fa8 Refactor and get rid of unessesary dependencies 2023-02-25 18:11:23 +01:00
730eb06c84 fix(deps): update dependency powerhooks to ^0.26.2 2023-02-14 12:08:41 +00:00
aca8d3f4b7 fix(deps): update dependency powerhooks to ^0.26.1 2023-02-08 16:38:28 +00:00
b5b3af4659 Bump version 2023-02-07 01:32:36 +01:00
6cd231426d Import Blob from node builtins 2023-02-07 01:32:20 +01:00
0c7cd1cd75 Bump version 2023-02-07 01:21:17 +01:00
2425704ead Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2023-02-07 01:20:33 +01:00
4e22159206 Bump version 2023-02-07 01:20:26 +01:00
52cf1ba02c Fix tsafe related warnings 2023-02-07 01:20:12 +01:00
516e84182f fix(deps): update dependency powerhooks to ^0.26.0 2023-02-05 15:10:42 +00:00
a3a9853e18 bump version 2023-02-05 14:58:53 +01:00
08e26600fd Use keycloakify as bundler by default 2023-02-05 14:58:38 +01:00
7793c2c6ba Update package.json 2023-02-05 14:41:32 +01:00
9e826d16dd Merge pull request #241 from lordvlad/mvn-begone
Mvn begone addendum
2023-02-05 14:41:13 +01:00
80618bbd9c Merge branch 'main' into mvn-begone 2023-02-05 13:36:52 +01:00
38ad47ea75 use hand-crafted promise, pipeline does not resolve properly 2023-02-05 13:32:24 +01:00
45ed359bef fix keycloak theme source path for internal bundler 2023-02-05 13:31:34 +01:00
fcc26c3e7a now that main is a promise, we shuold catch errors 2023-02-05 13:31:03 +01:00
d4ff6b1f40 fix: bundler fix missing directory 2023-02-05 12:59:05 +01:00
557de34eea fix: bundler fix missing change 2023-02-05 12:56:01 +01:00
e034dc4d90 Merge branch 'mvn-begone' of github.com:lordvlad/keycloakify into mvn-begone
* 'mvn-begone' of github.com:lordvlad/keycloakify:
  fix(deps): update garronej_modules_update
  Update README.md
  Rollback via update
  Bump version
  keycloak test script: use env to launch bash
  fix(deps): update dependency powerhooks to ^0.22.0
  Update dependency powerhooks to ^0.21.0
  Relase candidate
  fmt
  Update README.md
  Bump version
  Update src/bin/tools/downloadAndUnzip.ts
  Bump version
  #232
  Bump version
  keycloak test script: use env to launch bash
  fix(deps): update dependency powerhooks to ^0.22.0
  Update dependency powerhooks to ^0.21.0
2023-02-05 12:35:15 +01:00
cfbd1e5e4b fix(bundler): fix type mismatch introduced in last-minute 'fixes' 2023-02-05 12:34:48 +01:00
0df661819f Bump version 2023-02-04 20:51:06 +01:00
1a9f6d10d4 Actually run the top level await 2023-02-04 20:50:53 +01:00
a787215c95 Bump version 2023-02-04 20:39:38 +01:00
64ab400af5 Temporarly restore mvn as default bundler 2023-02-04 20:38:50 +01:00
a463878bf2 Bump version 2023-02-04 20:22:45 +01:00
9f72024c61 Merge pull request #240 from InseeFrLab/mvn-begone
Mvn begone
2023-02-04 19:47:36 +01:00
243fbd4dc9 Set the artifactId name in the build option 2023-02-04 19:36:42 +01:00
4e6a290693 Make new node based bundler the default 2023-02-04 18:02:39 +01:00
ac05d529ca Minor fixes 2023-02-04 17:44:02 +01:00
b38d79004a Merge branch 'main' into mvn-begone 2023-02-03 14:42:05 +01:00
f4a547df11 introduce options to choose a bundle strategy
Pick from 'none', 'keycloakify' or 'mvn', default to 'mvn'. 'none' will
not create a jar, 'keycloakify' will create a jar file using only tools
available to native nodejs, no additional  system library required.
Choosing 'mvn' will behave as before, starting maven in a subprocess.

The bundler can be chosen in `package.json` or via `KEYCLOAKIFY_BUNDLER`
env var.

This commit also adds `KEYCLOAKIFY_GROUP_ID` and
`KEYCLOAKIFY_ARTIFACT_ID` env vars, which will be used to
define group id and artifact id in pom.xml and pom.properties, if given.
2023-02-03 14:28:06 +01:00
2b87c35058 introduce utils for creating a jar archive 2023-02-03 14:06:24 +01:00
b11833e450 fix typo 2023-02-03 13:48:32 +01:00
fa8e119514 fix(deps): update garronej_modules_update 2023-02-01 15:16:03 +00:00
677cb5c330 Update README.md 2023-01-27 15:46:30 +01:00
6e74c79bfe Merge pull request #233 from InseeFrLab/windows_compat
Windows compat
2023-01-27 15:45:31 +01:00
54474f5908 Merge branch 'main' into windows_compat 2023-01-27 15:45:25 +01:00
99cc0f519b Rollback via update 2023-01-27 01:13:16 +01:00
92a01f89ef Bump version 2023-01-27 01:12:46 +01:00
fd83a0c743 keycloak test script: use env to launch bash
This minor change allows users to use the latest version of `bash` on Mac OS.

`/bin/bash` is very old on Mac OS, and many users will have `bash` from MacPorts or Homebrew. This change allows such users to be able to use the newer `bash` installation.
2023-01-27 01:12:46 +01:00
988e46c875 fix(deps): update dependency powerhooks to ^0.22.0 2023-01-27 01:12:46 +01:00
f081c2fc20 Update dependency powerhooks to ^0.21.0 2023-01-27 01:12:46 +01:00
b4b376a1a5 Relase candidate 2023-01-27 01:09:11 +01:00
0db4179d47 fmt 2023-01-27 00:32:41 +01:00
795b7c6234 Update README.md 2023-01-27 00:27:46 +01:00
091b9a57f5 Bump version 2023-01-27 00:22:28 +01:00
564e1422ac Merge pull request #226 from lordvlad/fix-win-build
windows compatibility
2023-01-27 00:20:12 +01:00
8ed4ed3fc4 Update src/bin/tools/downloadAndUnzip.ts 2023-01-26 22:29:51 +01:00
29fe4566a7 style: remove unused variable 2023-01-26 22:20:16 +01:00
ae3bfb28ed refactor: follow suggesion to make methods read a bit more sync 2023-01-26 22:00:31 +01:00
14aab97d8a Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2023-01-26 10:50:01 +01:00
52d7a47cd7 Bump version 2023-01-26 10:48:57 +01:00
f338dcbeed #232 2023-01-26 10:48:24 +01:00
dcec058a22 Bump version 2023-01-23 02:57:12 +01:00
2bdc6b156b Merge pull request #231 from rome-user/patch-1
keycloak test script: use env to launch bash
2023-01-23 02:56:32 +01:00
84ca9e6b81 keycloak test script: use env to launch bash
This minor change allows users to use the latest version of `bash` on Mac OS.

`/bin/bash` is very old on Mac OS, and many users will have `bash` from MacPorts or Homebrew. This change allows such users to be able to use the newer `bash` installation.
2023-01-22 17:28:27 -08:00
11cb0fd2db Merge pull request #230 from InseeFrLab/renovate_main-garronej_modules_update
Update dependency powerhooks to ^0.22.0 (main)
2023-01-18 00:58:38 +01:00
3f620ffb6f fix(deps): update dependency powerhooks to ^0.22.0 2023-01-16 18:23:50 +00:00
1a0e05d073 rewrite download and unzip to use nodejs native methods 2023-01-16 14:42:20 +01:00
a4d2de23a1 Update dependency powerhooks to ^0.21.0 2023-01-16 02:38:07 +00:00
85cecc9811 fix(build): _properly_ fix bin paths 2023-01-12 22:56:02 +01:00
9899f742a8 fix(build): also rewrite bin paths in dist/package.json 2023-01-12 22:51:48 +01:00
b5484740b7 fix(build): remove dependency on *nix chown 2023-01-12 22:27:22 +01:00
016b15b437 Bump version 2023-01-10 09:05:33 +01:00
6fb936798e https://github.com/InseeFrLab/keycloakify/issues/217#issuecomment-1376849781 2023-01-10 09:05:19 +01:00
a692b87843 Bump version 2023-01-08 15:01:12 +01:00
19663885a4 Merge pull request #222 from InseeFrLab/pr/lordvlad/221
Pr/lordvlad/221
2023-01-08 14:59:22 +01:00
49b87777f9 Fmt 2023-01-08 14:57:18 +01:00
d4523bb1e6 Merge branch 'main' into patch-1 2023-01-08 12:22:14 +01:00
e3200899e2 fix: replace rm system calls with nodejs native functions; closes #219 2023-01-08 12:19:41 +01:00
36c7a1ab9e Bump version 2023-01-08 00:14:01 +01:00
c54fbd5eca Merge pull request #218 from pedrodsRocha1/improve-secure-login-flow
fix - handle username and password login errors the same way
2023-01-08 00:03:16 +01:00
bbe828071e fix - handle username and password login errors the same 2023-01-06 15:41:01 +01:00
23f6c7db00 Update garronej_modules_update 2022-11-29 18:31:14 +00:00
b1ea9e7a71 Update dependency powerhooks to ^0.20.27 2022-11-16 05:21:45 +00:00
fb71d0e272 Update dependency powerhooks to ^0.20.26 2022-11-13 22:11:59 +00:00
fa72a29999 Bump version 2022-11-11 15:49:05 +01:00
af77b31d54 Update default test container to Keycloak 20.0.1 2022-11-11 15:48:32 +01:00
8280dace26 Update garronej_modules_update 2022-10-25 03:18:01 +00:00
ecaf1c7b7c Bump version 2022-10-16 00:51:11 +02:00
8702ec29a8 Drop dependency to @emotion/react 2022-10-16 00:49:49 +02:00
d8206434bc Bump version 2022-10-15 15:39:56 +02:00
c71c2a8710 Fix breaking change of 6.8 2022-10-15 15:39:32 +02:00
e55b881017 Bump version 2022-10-15 14:22:46 +02:00
ab906ec417 #192: fix bad logic in ftl to js script 2022-10-15 14:22:11 +02:00
0b1ff529f7 Update garronej_modules_update 2022-10-14 17:37:32 +00:00
85a6835748 Fix CI 2022-10-13 12:10:08 +02:00
259271bc0f Update CI 2022-10-13 12:07:32 +02:00
b7bc0f178b Bump version 2022-10-13 12:03:24 +02:00
688455d0aa #191: Enable to only customize the Template 2022-10-13 11:58:31 +02:00
3c96d2ea42 Update garronej_modules_update 2022-10-13 01:16:45 +00:00
ab81481e5a Update garronej_modules_update 2022-10-11 05:10:22 +00:00
a429ad5dcf Bump version 2022-10-06 20:43:42 +02:00
5e1c5b510b Merge pull request #185 from Mstrodl/feature/mstrodl/webauthn-authenticate
Add support for `webauthn-authenticate.ftl`
2022-10-06 20:41:31 +02:00
9e63183f4b WebauthnAuthenticate: refactor authentication flow
Lots of weird syntax here, and we were using `useCallback` rather than
`useConstCallback`.
2022-10-06 14:25:04 -04:00
b1e740f026 Bump version 2022-10-06 01:09:00 +02:00
ce4ea55438 Add a big red warning when kcContext mock is enabled 2022-10-06 01:08:07 +02:00
18ab7cd22f Bump version 2022-10-06 00:37:51 +02:00
8807743daf Ignore mock when in Keycloak: https://github.com/InseeFrLab/keycloakify/discussions/186#discussioncomment-3809320 2022-10-06 00:36:46 +02:00
aad50377ff Merge pull request #187 from InseeFrLab/renovate_main-garronej_modules_update
Update dependency tss-react to ^4.3.4 (main)
2022-10-06 00:01:38 +02:00
4b3ae58ea7 Add support for webauthn-authenticate.ftl
Wow! This one sucks. Certainly more in need of review compared to
`login-username.ftl` and `login-password.ftl`...
2022-10-05 02:54:03 -04:00
ce2c68ecc9 Update dependency tss-react to ^4.3.4 2022-10-04 19:43:22 +00:00
0c155a7a2e Bump version 2022-10-04 21:42:47 +02:00
afddfe8b58 Merge pull request #184 from Mstrodl/feature/mstrodl/login-password
Add support for `login-password.ftl`
2022-10-04 21:38:55 +02:00
5fa0915271 Update changelog 2022-10-04 21:34:42 +02:00
6a0a170b17 Add support for login-password.ftl 2022-10-04 15:01:08 -04:00
4dde5b6e45 Bump version 2022-10-04 18:48:22 +02:00
4b93a1cb9e Merge pull request #183 from Mstrodl/feature/mstrodl/login-username 2022-10-04 18:43:02 +02:00
e3a0639a0c Add login-username support
Shown for the "Username Form" login step.

I would also like to work on:
- `login-password.ftl`
- `webauthn-authenticate.ftl`

But first want to see opinions on this!
2022-10-04 11:22:03 -04:00
4d3220820b Update dependency tss-react to ^4.3.3 2022-10-04 03:50:15 +00:00
a4ac9fb0f3 Update garronej_modules_update 2022-10-01 17:47:21 +00:00
1ff79ecf07 Update garronej_modules_update 2022-09-29 08:53:47 +00:00
1166b16420 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-09-27 21:35:52 +02:00
213224942f Bump version 2022-09-27 21:35:16 +02:00
ff16e66275 #177: Provide a simple way to disable fetching of default resources 2022-09-27 21:30:33 +02:00
3c338e983f Update garronej_modules_update 2022-09-14 16:33:35 +00:00
2c11ba6520 Bump version 2022-09-13 10:50:36 +02:00
9a21656706 Apply #164 on v6 2022-09-13 10:49:20 +02:00
e96ee5ba53 Bump version 2022-09-12 23:49:14 +02:00
b421633a8a Default test container use 19.0.1 2022-09-12 23:48:34 +02:00
e2e0d62560 Cleaner npm scripts 2022-09-11 01:53:56 +02:00
c71fb06940 Update garronej_modules_update 2022-09-10 20:14:00 +00:00
e2171af99c Bump version 2022-09-09 17:24:58 +02:00
8cebf049d4 Render Markdown in Terms 2022-09-09 17:24:43 +02:00
ef139ed1cc Bump version 2022-09-09 14:37:41 +02:00
d717de006a Update kcContext def 2022-09-09 14:37:27 +02:00
a44f091878 Bump version 2022-09-09 12:56:31 +02:00
1b37ba5339 Feat idp-review-user-profile.ftl #164 2022-09-09 12:56:09 +02:00
bbaa90e997 Rename misnamed default exports, removing doInsertPasswordFields 2022-09-09 10:24:50 +02:00
86e6c4a419 Bump version (changelog ignore) 2022-09-09 02:10:18 +02:00
4159883791 Feature update-user-profile.ftl #164 2022-09-09 02:07:49 +02:00
d8b00da3a1 Update tss-react 2022-09-08 15:27:41 +02:00
a24945bc1b Bump version 2022-09-08 15:18:21 +02:00
158759493f Merge pull request #170 from Tasyp/feature/silent
feat: add silent flag
2022-09-08 15:17:45 +02:00
36e32d6ddc Update src/bin/download-builtin-keycloak-theme.ts 2022-09-08 15:13:21 +02:00
84908e2ec0 Update src/bin/generate-i18n-messages.ts 2022-09-08 15:13:15 +02:00
a2dc51d811 Update src/bin/create-keycloak-email-directory.ts 2022-09-08 15:13:09 +02:00
fb3b0e2c29 fix: make sure external assets flag is a boolean 2022-09-08 15:46:27 +03:00
1a3e4c68bb test: update tests to include silent flag 2022-09-08 15:43:03 +03:00
11b2342da0 feat: add silent flag 2022-09-08 13:52:10 +03:00
80d4a808d3 Update readme 2022-09-07 13:45:34 +02:00
da4146eb59 Bump version (changelog ignore) 2022-09-07 13:40:18 +02:00
a0be35db8b Fix compat with StrictMode react 18 2022-09-07 13:39:54 +02:00
14db9cd523 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-09-07 12:02:35 +02:00
0c315385dd Update fix tests 2022-09-07 12:00:23 +02:00
c0a0eb02fb Remove Open collectivity 2022-09-07 11:59:42 +02:00
ee407c32ad Create FUNDING.yaml 2022-09-07 11:53:18 +02:00
9262d21829 Bump version 2022-09-07 11:50:41 +02:00
a13f710325 Important fix for --external-assets 2022-09-07 11:50:24 +02:00
eac1a6036f Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-09-07 11:26:18 +02:00
987f3d7586 Bump version (changelog ignore) 2022-09-07 11:26:10 +02:00
875322669c Rename isAppAndKeycloakServerSharingSameDomain to areAppAndKeycloakServerSharingSameDomain #145 2022-09-07 11:25:46 +02:00
33a264b3d0 Update README.md 2022-09-07 00:32:38 +02:00
c059eff170 Update README 2022-09-06 19:14:39 +02:00
b4a22fc9dd Fix readme 2022-09-06 19:13:46 +02:00
6d1cbdc463 Bump version 2022-09-06 19:12:59 +02:00
2bfbba4daf Upgrade tss-react 2022-09-06 17:43:30 +02:00
21ffe82bde Bump version 2022-09-06 17:40:06 +02:00
8e6f597027 Fix bug with --external-assets 2022-09-06 17:39:47 +02:00
16c5065560 Bump version 2022-09-05 00:09:07 +02:00
c4b985f1a4 Fix replacers 2022-09-05 00:08:50 +02:00
042747c7d2 Bump version 2022-09-04 23:19:53 +02:00
e4a46f31de Make it allright not to provide validators object on mock data 2022-09-04 23:19:33 +02:00
6d9e62d2b4 Remove unessesary log 2022-09-04 21:48:46 +02:00
9caaa507b1 Bump version 2022-09-01 22:35:15 +02:00
5c7d3c5b44 lib target ES2017 instead of ES2020 2022-09-01 22:35:01 +02:00
8bac57d87a Bump version 2022-09-01 21:31:41 +02:00
b8d759cd63 Minor refactor for dryness 2022-09-01 21:31:27 +02:00
da72e3e5ac Bump version (changelog ignore) 2022-09-01 21:16:39 +02:00
2afd36fee0 Avoid fetching locale twitch (react 18 useEffect) 2022-09-01 21:16:25 +02:00
b7e75d8828 Bump beta version 2022-09-01 17:22:35 +02:00
30e20f4e7d Avoid redefining the properties 2022-09-01 17:22:15 +02:00
ce0ab8dccf Better linking script 2022-09-01 16:36:38 +02:00
5b20ab2f7c Upgrade to tss-react v4 2022-09-01 15:13:24 +02:00
daaaed43df Rename keycloakify-demo-app in keycloakify-starter 2022-09-01 14:58:59 +02:00
3a4bd791ad Fix release (changelog ignore) 2022-08-28 12:37:03 +07:00
eecddd7f6b Update CI (changelog ignore) 2022-08-28 12:31:58 +07:00
a34eaa136e Update ts-ci (changelog ignore) 2022-08-28 12:16:27 +07:00
53be8b5e96 Updat README 2022-08-28 12:10:45 +07:00
f0ae5ea908 Enable the CI to run on the v6 branch 2022-08-26 16:17:03 +07:00
9910556a8b Bump version (changelog ignore) 2022-08-26 15:43:50 +07:00
5997416e1b Update i18n API JSDoc comments 2022-08-26 15:43:32 +07:00
9a9fc56f85 Improve documentation comment i18n (changelog ignore) 2022-08-23 07:58:39 +07:00
2a5e919f29 Bump version (changelog ignore) 2022-08-22 17:18:09 +07:00
8031d51e15 Rename build-keycloak-theme -> keycloakify 2022-08-22 17:17:35 +07:00
56ce9c0d0d Bump version (changelog ignore) 2022-08-20 14:56:40 +07:00
8cd584cbd5 Implementation of #160 and #103 for v6 2022-08-20 14:56:20 +07:00
f5b87f4669 Fix option parsing 2022-08-20 14:04:47 +07:00
a1a65c5529 Prettier: switch to trailing coma: none 2022-08-20 11:44:48 +07:00
832434095e Restore tsproject.json 2022-08-16 14:45:18 +07:00
b85f1ef351 Merge branch 'v6' of https://github.com/InseeFrLab/keycloakify into v6 2022-08-16 14:42:05 +07:00
8bee5d788e #145 2022-08-16 14:41:06 +07:00
0752d857e2 Merge pull request #155 from schlich/hotfix-ci 2022-08-14 11:58:07 +07:00
07e4056694 change outDir to path at root per NPM CI error message 2022-08-13 23:00:09 -05:00
0eb4ab85b3 Fix lazy loading of css chunks #141 2022-08-02 21:00:52 +02:00
69ef47daf8 Bump beta version (changelog ignore) 2022-08-01 06:04:23 +02:00
6eaa1f69ac Fix dynamic imports 2022-08-01 06:03:48 +02:00
5aab75fae0 Only downoad terms on the Terms page 2022-08-01 04:54:02 +02:00
7407c98005 Stop self promotion in log 2022-08-01 04:49:48 +02:00
dcd4322e44 Fix CI 2022-08-01 04:06:10 +02:00
81a4d46b08 Bump beta version (changelog ignore) 2022-08-01 03:57:57 +02:00
e85895ab55 User switch for dynamic import of local 2022-08-01 03:57:24 +02:00
095bdb16ba Make new build setup compatible with enable short import path 2022-08-01 03:56:53 +02:00
68de7f897d Remove ts-node 2022-08-01 03:23:49 +02:00
51b4c6b1bd Merge branch 'main' into v6 2022-08-01 03:23:16 +02:00
6d4ac977c1 update yarn.lock 2022-08-01 03:14:30 +02:00
a73fc5ebc1 Bump beta version 2022-08-01 03:07:59 +02:00
3c8461a39f update lock file 2022-08-01 03:07:20 +02:00
de76d06e48 Fix build 2022-08-01 03:07:06 +02:00
a27c28c24f Avoid downloading the Terms Markdown twice in safe mode 2022-08-01 00:29:58 +02:00
ed234ec88b Bump version (changelog ignore) 2022-07-31 22:30:51 +02:00
7a0a046596 Refactor: Use hook instead of Context for i18n 2022-07-31 22:30:32 +02:00
0641151ca1 Fix specialization of i18n using global 2022-07-31 20:00:57 +02:00
c6dc2377fa output i18n messages to be imporable on a perl local basis 2022-07-31 19:03:20 +02:00
a3050b3983 squash 2022-07-31 19:00:57 +02:00
69c15bd473 New i18n with dynamic imports 2022-07-31 18:57:30 +02:00
2be40816b2 lib needs to be able to import bin 2022-07-31 00:41:25 +02:00
a98bb25133 Bump version (changelog ignore) 2022-07-30 01:49:33 +02:00
d130c23f5d Do not export components in the index 2022-07-30 01:49:02 +02:00
cd936ee4ef Pretier: Ignoore dist_test 2022-07-30 01:47:44 +02:00
67e3dca0c3 Minor refactor (changelog ignore) 2022-07-30 00:51:29 +02:00
de53f1ff40 Fix retrocompat with React 16 and TypeScript 3 https://github.com/garronej/tss-react/issues/95 2022-07-30 00:45:17 +02:00
d79081dee4 Ship /src/lib in ESM for enabeling dynamic imports 2022-07-30 00:42:38 +02:00
449f100bc0 Using <Suspense /> and React.lazy() 2022-07-30 00:30:57 +02:00
0612b2d0a4 Update garronej_modules_update 2022-07-30 00:30:57 +02:00
583a3e541a Fix readme error (changelog ignore) 2022-07-30 00:30:57 +02:00
9d8d30a864 Update ts-ci, remove changelog, use github release generated body instead 2022-07-30 00:30:57 +02:00
95cda8538f Bump version (changelog ignore) 2022-07-30 00:30:57 +02:00
b116f22152 Support for React.lazy() #141 🎉 2022-07-30 00:30:57 +02:00
ff2fb0d6dc Attempt to activate renovate on project's landingpage (changelog ignore) 2022-07-30 00:30:56 +02:00
020823e933 Update garronej_modules_update 2022-07-28 04:44:01 +00:00
5879972924 Fix readme error (changelog ignore) 2022-07-28 04:38:04 +02:00
8031294230 Update ts-ci, remove changelog, use github release generated body instead 2022-07-28 04:32:27 +02:00
e0a6935c49 Bump version (changelog ignore) 2022-07-28 04:27:38 +02:00
3d581a5454 Support for React.lazy() #141 🎉 2022-07-28 04:24:10 +02:00
317ad8386c Attempt to activate renovate on project's landingpage (changelog ignore) 2022-07-23 17:45:04 +02:00
7ad5011280 Merge pull request #142 from InseeFrLab/renovate/configure
Configure Renovate
2022-07-23 16:10:40 +02:00
76990702f0 Add renovate.json
update
2022-07-23 16:09:14 +02:00
9a27824fe9 Only run the unit test in the CI pipeline (changelog ignore) 2022-07-22 18:25:09 +02:00
d877d90bf3 Writing tests for #141 2022-07-22 18:20:50 +02:00
0b790c47e6 fmt (changelog ignore) 2022-07-22 17:34:52 +02:00
6b49c8dd95 complete exhausive unit testing of replacer (changelog ignore) 2022-07-22 17:33:53 +02:00
e56f9b144e Improve unit tests (changelog ignore) 2022-07-22 17:22:23 +02:00
3c82944daf improve replacer unit test (changelog ignore) 2022-07-22 16:38:44 +02:00
5e3070a6c4 Improve unit test (changelog ignore) 2022-07-22 15:35:23 +02:00
a3a0e9eebe Add closest thing to a migration guide from v4 to v5 (changelog ignore) 2022-07-21 19:49:10 +02:00
c6593f03bc Update changelog v5.7.3 2022-07-17 01:34:02 +00:00
54dc4f650c Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-07-17 03:30:10 +02:00
dec7af0381 Bump version (changelog ignore) 2022-07-17 03:29:17 +02:00
ae001eea54 update evt and powerhooks (changelog ignore) 2022-07-17 03:28:35 +02:00
4d0e17a11e Update changelog v5.7.1 2022-07-17 03:28:34 +02:00
c708e619e9 Update changelog v5.7.2 2022-07-13 01:30:23 +00:00
2cceb3c929 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-07-13 03:27:38 +02:00
aee8704691 Bump version (changelog ignore) 2022-07-13 03:27:29 +02:00
43af60237b #135 2022-07-13 03:26:46 +02:00
e615479b41 Update changelog v5.7.1 2022-07-11 17:25:30 +00:00
973fb4d2d5 Bump version (changelog ignore) 2022-07-11 19:18:42 +02:00
964feae846 #134 2022-07-11 19:18:15 +02:00
ea3d8a5634 Update changelog v5.7.0 2022-07-07 11:56:00 +00:00
48aab2d92a Bump version (changelog ignore) 2022-07-07 13:53:20 +02:00
00eab73954 Merge pull request #120 from revolunet/logout
feat: add logout-confirm
2022-07-07 13:40:17 +02:00
5f6f8b12bd fix: use kcMessages 2022-07-07 01:05:18 +02:00
c2d4d6fd49 fix: add translations FR 2022-07-07 01:05:18 +02:00
04b660ff9b feat: add logout-confirm 2022-07-07 01:05:15 +02:00
c292d926be Update changelog v5.6.5 2022-07-06 10:01:52 +00:00
23b83ceef7 Bump version (changelog ignore) 2022-07-06 11:58:43 +02:00
1324648db6 Merge pull request #133 from bardius/fix/Issue-131-include-all-nested-folders-in-artifact-unzip
fix: Issue-131: include all nested folders in artifact unzip
2022-07-06 11:56:00 +02:00
735bff3348 Merge pull request #132 from bardius/fix/Issue-130-fix-equality-detection-of-nested-ftl-object-properties
fix: Issue-130: fix equality detection of nested ftl object property 

2022-07-06 11:55:18 +02:00
05a6aee782 fix: Issue-131: include all nested folders in artifact unzip 2022-07-06 11:44:25 +03:00
c7349c2556 fix: Issue-130: fix equality detection of nested ftl object property paths 2022-07-06 11:38:47 +03:00
51f3d06752 Update changelog v5.6.4 2022-07-06 00:08:51 +00:00
31759d86ab Bump version (changelog ignore) 2022-07-06 02:05:45 +02:00
7c6eed99d2 Fix login-register-email.ftl 2022-07-06 02:05:08 +02:00
bc4b0ec17d Update to Keycloak 18.0.2 for the test container 2022-07-06 01:30:30 +02:00
f766348b87 Update changelog v5.6.3 2022-07-03 22:05:43 +00:00
82281303d0 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-07-04 00:02:47 +02:00
1caa17beb0 Bump version (changelog ignore) 2022-07-04 00:02:39 +02:00
1c4d346f9f update powerhooks 2022-07-04 00:02:19 +02:00
4320efb049 Update changelog v5.6.2 2022-07-03 18:07:07 +00:00
a756423768 Bump version (changelog ignore) 2022-07-03 20:03:35 +02:00
8525fc74c0 Update powerhooks and EVT 2022-07-03 20:03:19 +02:00
30c0cc5aa8 Update changelog v5.6.1 2022-07-03 14:01:24 +00:00
b3bbd7c07d Bump version (changelog ignore) 2022-07-03 15:58:41 +02:00
09d4ba2bb0 Refactor (avoid using else) changelog ignore 2022-07-03 15:58:00 +02:00
30315027c1 Merge pull request #128 from Ann2827/pull
Fix bugs on error.ftl template
2022-07-03 15:52:42 +02:00
05acefe70e fix: bugs on error.ftl template 2022-07-02 11:01:14 +03:00
6c14758e33 Merge pull request #52 from InseeFrLab/main
Update fork
2022-07-02 10:39:39 +03:00
b93ec20119 Update changelog v5.6.0 2022-06-28 21:39:13 +00:00
ce04646576 Update React (changelog ignore) #127 2022-06-28 23:36:16 +02:00
9282dfe491 Bump version (changelog ignore) 2022-06-28 21:53:02 +02:00
fca6280bcc Merge pull request #127 from aidangilmore/add-totp-support
feat: add login-config-totp.ftl page
2022-06-28 21:49:04 +02:00
cdeb575ec6 Fix unknown algorithm name lookup in LoginConfigTotp 2022-06-28 15:21:09 -04:00
271dbe4fb7 Add totp config support 2022-06-28 14:37:17 -04:00
9a0337114d Update changelog v5.5.0 2022-06-28 04:54:43 +00:00
2d28f4eb55 Attempt to fix ci (changelog ignore) 2022-06-28 06:51:49 +02:00
f673927e16 [CI]: update npm-install (changelog ignore) 2022-06-28 06:45:59 +02:00
52896b82a9 Update yarn.lock (changelog ignore) 2022-06-28 06:40:51 +02:00
9d53ecb0cd Bump version (changelog ignore) 2022-06-28 06:37:05 +02:00
aec3ac32e5 Make it possible to redirect to login by repacing the url (should be default in most case) 2022-06-28 06:36:30 +02:00
f150f1568e Update changelog v5.4.7 2022-06-19 21:33:05 +00:00
309189c55d Bump version (changelog ignore) 2022-06-19 23:30:38 +02:00
f68c54cd3a #121 2022-06-19 23:30:05 +02:00
bef8545161 Merge pull request #48 from InseeFrLab/main
Update fork
2022-06-18 17:17:08 +03:00
c21cd14ac2 fmt 2022-06-17 18:25:54 +02:00
275d7f0072 Create CONTRIBUTING.md 2022-06-17 17:00:55 +02:00
58c8306cf4 Enable users to link keycloak in their own app 2022-06-17 16:32:20 +02:00
f782b684ad Update changelog v5.4.6 2022-06-16 23:51:09 +00:00
092b2a5f52 Bump version (changelog ignore) 2022-06-17 01:45:32 +02:00
42b2d40ad6 Update powerhooks (changelog ignore) 2022-06-17 01:45:17 +02:00
3f6fe6cfc0 Use keycloak 18.0.1 i18n resources #120 2022-06-17 01:43:14 +02:00
1abf542a74 Update changelog v5.4.5 2022-06-14 21:07:14 +00:00
c4720ca03d Bump version (changelog ignore) 2022-06-14 23:04:59 +02:00
4316878cce Merge pull request #119 from dro-sh/fix-locale-on-useFormValidationSlice
pass locale to getGetErrors to get correct messages
2022-06-14 23:04:28 +02:00
c180d75a83 pass locale to getGetErrors to get correct messages 2022-06-14 21:52:18 +03:00
4a040b32c0 Display downloads by month (changelog ignore) 2022-06-11 03:36:03 +02:00
ea330a1eef Update changelog v5.4.4 2022-06-05 03:49:23 +00:00
2451ba0a77 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-06-05 05:46:26 +02:00
2c276a56e5 Bump version (changelog ignore) 2022-06-05 05:46:20 +02:00
708030b8b5 Update powerhooks (changelog ignore) 2022-06-05 05:46:03 +02:00
d5fc0582bc Update changelog v5.4.3 2022-06-01 23:37:41 +00:00
f9dce82c83 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-06-02 01:32:57 +02:00
e82602f994 Bump version (changelog ignore) 2022-06-02 01:32:49 +02:00
1d36395e5a Update EVT and powerhook (changelog ignore) 2022-06-02 01:32:26 +02:00
8f8857bc22 Update changelog v5.4.2 2022-06-01 22:21:23 +00:00
226247b3b6 Bump version (changelog ignore) 2022-06-02 00:15:25 +02:00
b2ea5014f3 Update evt (changelog ignore) 2022-06-02 00:15:10 +02:00
48bc416aa7 Update powerhooks (changelog ignore) 2022-06-02 00:14:36 +02:00
386e7203b2 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-06-01 05:51:41 +02:00
9bdb224631 Prevent rate limite in CI by authenticating 2022-06-01 05:51:33 +02:00
dd36aacbee Update changelog v5.4.1 2022-06-01 03:45:04 +00:00
6b57b1c720 Bump version (changelog ignore) 2022-06-01 05:42:23 +02:00
9e9e6d41ff Update dependencies (changelog ignore) 2022-06-01 05:38:12 +02:00
5140389502 Update changelog v5.4.0 2022-05-23 14:59:15 +00:00
fc6328131f Bump version (changelog ignore) 2022-05-23 16:51:58 +02:00
9de0083ca6 #109 2022-05-23 16:51:18 +02:00
f5231b840d Update changelog v5.3.2 2022-05-04 10:16:04 +00:00
afb6596c4b Bump version (changelog ignore) 2022-05-04 12:13:10 +02:00
dde9afef92 Merge pull request #101 from Romcol/bugfix/99
Issue #99 - Make replace less greedy in remplaceImportFromStatic
2022-05-04 12:12:06 +02:00
6595e9c3cb [IMP] Issue #99 - Make replace less greedy in remplaceImportFromStatic 2022-05-04 11:22:58 +02:00
c0e3b5fe06 Update changelog v5.3.1 2022-04-29 16:41:12 +00:00
6b8f3bbc51 Bump version (changelog ignore) 2022-04-29 18:35:39 +02:00
9a5a021e64 Comment out missleading informations 2022-04-29 18:35:07 +02:00
14c05fec8c Update changelog v5.3.0 2022-04-28 07:52:08 +00:00
eaf7a455cd Fix name of npx script for generating email dir (changelog ignore) 2022-04-28 09:46:49 +02:00
55bb21f3ee Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-28 09:36:41 +02:00
f123bc0912 Bump version (changelog ignore) 2022-04-28 09:35:53 +02:00
572eb7b1c0 Rename keycloak_theme_email to keycloak_email (it's shorter) 2022-04-28 09:34:01 +02:00
2befaff8a8 Update changelog sumup in readme (changelog ignore) 2022-04-27 23:32:47 +02:00
437a9ce2d3 Update changelog v5.2.0 2022-04-27 19:27:37 +00:00
1b967b250a Bump version (changelog ignore) 2022-04-27 21:23:10 +02:00
e221f39e07 Export KcApp 2022-04-27 21:22:55 +02:00
21a8838a24 Update changelog v5.1.0 2022-04-27 19:20:36 +00:00
fad91ccae0 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-27 21:17:40 +02:00
825914aa4b Export kcLanguageTags 2022-04-27 21:17:26 +02:00
a8246d12ee Update changelog v5.0.0 2022-04-27 19:05:48 +00:00
abb8bf2ebb Bump version (changelog ingore) 2022-04-27 21:02:29 +02:00
7e7071305f i18n rebuild from the ground up 2022-04-27 21:02:10 +02:00
cc8b2e72c1 Update changelog v4.10.0 2022-04-26 14:45:04 +00:00
a3d6ee44a1 Bump version (changelog ignore) 2022-04-25 13:26:24 +02:00
ac99e2f41f Merge pull request #92 from Tasyp/add-login-idp-link-email
feat: add login-idp-link-email page
2022-04-25 13:23:54 +02:00
bf1839c061 feat: add mock data for login-idp-link-email page 2022-04-25 14:15:40 +03:00
fd5c132a40 feat: supply broker context with context 2022-04-25 14:14:03 +03:00
4dfa268eb3 Update changelog v4.9.0 2022-04-25 11:09:16 +00:00
332ca084f5 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-25 13:06:10 +02:00
01cbb8680a Bump version (changelog ignore) 2022-04-25 13:05:59 +02:00
bbdaaf30bc Test by default with kc 18. Update instructions to use quay.io/keycloak/keycloak instead of jboss/keycloak #93 2022-04-25 13:05:13 +02:00
0550b9ff8b Update changelog v4.8.7 2022-04-25 10:33:29 +00:00
b1a4c5cca5 Bump version (changelog ignore) 2022-04-25 12:30:29 +02:00
785080e14a Update instructions to test on Keycloak 18 https://github.com/keycloak/keycloak-web/issues/306 #93 2022-04-25 12:30:28 +02:00
3c7e093a3c Move the documentation form the readme to docs.keycloakify.dev 2022-04-23 22:01:15 +02:00
89be9f3a86 fmt (changelog ignore) 2022-04-23 05:14:43 +02:00
6f2ffa7861 Update README.md 2022-04-22 20:01:26 +02:00
7091f283f2 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-22 20:00:50 +02:00
2d28003451 Update demo video 2022-04-22 20:00:41 +02:00
f0ba7d3c0d Update changelog v4.8.6 2022-04-22 16:26:51 +00:00
cd5f346895 Bump version (changelog ignore) 2022-04-22 18:23:35 +02:00
66cd5aef0c always offer to download v11.0.3 2022-04-22 18:22:28 +02:00
6f8ec53e8b feat: add login-idp-link-email page 2022-04-22 17:54:47 +03:00
622504ff72 Update changelog v4.8.5 2022-04-22 14:45:25 +00:00
c9d47c483c Bump version (changelog ignore) 2022-04-22 16:39:04 +02:00
07098b89a5 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-22 16:38:26 +02:00
c583b83cbb #91 2022-04-22 16:38:20 +02:00
1670e1fe42 Update changelog v4.8.4 2022-04-22 11:59:31 +00:00
de8809608c Bump version (changelog ignore) 2022-04-22 13:56:54 +02:00
0e194ee045 #90 2022-04-22 13:56:29 +02:00
4205f6ecbe Remove no longer relevent link (changelog ignore) 2022-04-21 02:10:23 +02:00
4d90ec60e2 Remove no longer relevent section of the readme (changelog ignore) 2022-04-21 02:03:29 +02:00
d126a6563b Update changelog v4.8.3 2022-04-20 20:32:12 +00:00
aecb6ae79c Bump version (changelog ignore) 2022-04-20 22:26:33 +02:00
a65c826717 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-20 22:26:16 +02:00
66c3705f2b Keycloak 18 container hasn't been published yet (changelog ignore) 2022-04-20 22:26:10 +02:00
d18ebb45f8 Update changelog v4.8.2 2022-04-20 20:20:03 +00:00
d8e01f2c5d Bump version (changelog ignore) 2022-04-20 22:14:06 +02:00
4abbaa3841 Tell pepoles they can test with different keycloak version 2022-04-20 22:13:42 +02:00
42a463b348 Update changelog v4.8.1 2022-04-20 19:19:55 +00:00
8e15cf1d45 Bump version (changelog ignore) 2022-04-20 21:17:05 +02:00
2468b4108e Update changelog highlights 2022-04-20 21:15:58 +02:00
528b1bb607 Add missing shebang 2022-04-20 21:13:32 +02:00
b4449bb289 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-20 21:09:53 +02:00
737e00b490 Add video demo for npx download-builtin-keycloak-theme 2022-04-20 21:09:36 +02:00
55d4c7f4ab Update changelog v4.8.0 2022-04-20 18:59:10 +00:00
7afb078efd fmt (changelog ignore) 2022-04-20 20:55:53 +02:00
2c04f6c1e9 Bump version (changelog ignore) 2022-04-20 20:44:32 +02:00
2ad5ed7e73 Document email template customization feature #9 2022-04-20 20:44:31 +02:00
f2b7fe46a2 Add mention of download-builtin-keycloak-theme 2022-04-20 20:22:19 +02:00
1a1af62f62 Improve readme (changelog ignore) 2022-04-20 20:11:26 +02:00
98f715e652 Let the choice of kc version be auto in GH Action 2022-04-20 12:23:28 +02:00
fa5f1c230a Only test on node v15 and v14 (bellow is no longer supported (rmSync) 2022-04-20 11:59:19 +02:00
c92ae9cfa9 Fix broken link in readme (changelog ignore) 2022-04-20 11:43:15 +02:00
3dcb3a1a5b cange name of temp dir (changelog ignore) 2022-04-20 01:26:22 +02:00
efde71d07c Feature email customization #9 2022-04-20 00:39:40 +02:00
bff8cf2f32 Update README (changelog ignore) 2022-04-15 12:19:41 +02:00
72730135f1 Mention tested wit CRA 5.0.0 (changelog ignore) 2022-04-14 21:55:42 +02:00
50cf27b686 Mention test on Keycloak 17.0.1 (changelog ignore) 2022-04-14 21:53:27 +02:00
b293abffa4 Update changelog v4.7.6 2022-04-12 16:57:59 +00:00
be84ea299c Bump version (changelog ignore) 2022-04-12 18:51:30 +02:00
d54586426a Fix bugs with language switch #85 2022-04-12 18:51:03 +02:00
6ccf72c707 Update changelog v4.7.5 2022-04-09 20:28:23 +00:00
5817118461 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-09 22:25:51 +02:00
ebac1de111 Bump version (changelog ignore) 2022-04-09 22:25:43 +02:00
0d2f841b27 Fix #85 2022-04-09 22:25:20 +02:00
780ca383c9 Update changelog v4.7.4 2022-04-09 18:22:22 +00:00
a652a0f4f3 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-09 20:19:13 +02:00
5bdc812c43 Bump version (changelog ignore) 2022-04-09 20:19:07 +02:00
357bc8d19d M1 Mac compat (for real this time) 2022-04-09 20:18:42 +02:00
85b54ac011 Update changelog v4.7.3 2022-04-09 20:17:55 +02:00
17f888019c Update changelog v4.7.2 2022-04-09 20:17:55 +02:00
947fd0564e Update changelog v4.7.3 2022-04-08 13:04:37 +00:00
bd51d02902 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify 2022-04-08 15:01:47 +02:00
36d75c8641 Bump version (changelog ignore) 2022-04-08 15:01:39 +02:00
c75f158b48 Mention that there is still problems with M1 Mac 2022-04-08 15:01:21 +02:00
bb37ce9cef Update changelog v4.7.2 2022-04-06 23:41:42 +00:00
77ff33570d Bump version (changelog ignore) 2022-04-07 01:39:03 +02:00
20383d60a9 #43: M1 Mac support 2022-04-07 01:38:58 +02:00
f15c0ecbb0 Merge pull request #46 from InseeFrLab/main
Update fork
2022-04-04 17:41:06 +03:00
79aa5ac5f2 Update changelog v4.7.1 2022-03-30 14:23:41 +00:00
8be6c0d1d2 Bump version (changelog ignore) 2022-03-30 16:20:34 +02:00
7f5a9e77de Improve browser autofill 2022-03-30 16:20:14 +02:00
ff19ab8b08 factorization 2022-03-30 14:01:10 +02:00
63dcb2ad39 Update changelog v4.7.0 2022-03-17 23:49:31 +00:00
795e8ed0e5 Bump version (changelog ignore) 2022-03-18 00:46:40 +01:00
bccb56ed61 Add support for options validator 2022-03-18 00:46:12 +01:00
02e2ad89ec remove duplicate dependency 2022-03-18 00:41:29 +01:00
a236e2e5de Update changelog v4.6.0 2022-03-07 00:53:27 +00:00
ba294c85f8 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2022-03-07 01:50:38 +01:00
beb3dca495 Bump version (changelog ignore) 2022-03-07 01:50:25 +01:00
04101536c6 Remove powerhooks as dev dependency 2022-03-07 01:43:31 +01:00
2912e7e5dd Update changelog v4.5.5 2022-03-07 00:18:43 +00:00
bf6fadbde8 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2022-03-07 01:16:01 +01:00
001b49d09a Bump version (changelog ignore) 2022-03-07 01:15:52 +01:00
bbd5bdda95 Update tss-react 2022-03-07 01:15:36 +01:00
7e950e8e2b Update changelog v4.5.4 2022-03-06 23:33:45 +00:00
8b0efbc737 Bump version (changelog ignore) 2022-03-07 00:31:08 +01:00
93cfbd6696 Remove tss-react from peerDependencies (it becomes a dependency) 2022-03-07 00:30:44 +01:00
acc1d028ab Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2022-02-18 21:00:56 +01:00
3476b5acc3 (dev script) Use tsconfig.json to tell we are at the root of the project 2022-02-18 21:00:44 +01:00
72ca5da842 Update changelog v4.5.3 2022-01-26 15:33:05 +00:00
e214280fcd Rephrase (changelog ignore) 2022-01-26 10:42:45 +01:00
bf32987a3e Bump version (changelog ignore) 2022-01-26 10:40:36 +01:00
8941fe230b Themes no longer have to break on minor Keycloakify update 2022-01-26 10:40:08 +01:00
b6d4abee21 Update cover image (changelog ignore) 2022-01-25 23:20:26 +01:00
786bdc41c2 Update changelog v4.5.2 2022-01-20 01:57:57 +00:00
ed9f08f678 Update ..prettierignore (changelog ignore) 2022-01-20 02:55:14 +01:00
33fd6768f1 Bump version (changelog ignore) 2022-01-20 02:53:42 +01:00
87b8456531 Test container uses Keycloak 16.1.0 2022-01-20 02:52:31 +01:00
a12bde4656 Merge pull request #78 from InseeFrLab/Ann2827/pull
Ann2827/pull
2022-01-20 01:50:37 +01:00
6f219a4c2a Refactor #78 2022-01-20 01:49:35 +01:00
49d7818b64 Merge branch 'Ann2827/pull' of https://github.com/InseeFrLab/keycloakify into Ann2827/pull 2022-01-20 01:35:36 +01:00
fb0be3272c Compat with Keycloak 16 (and probably 17, 18) #79 2022-01-20 01:34:26 +01:00
994f7d6bea Warning about compat issues with Keycloak 16 2022-01-19 16:11:40 +01:00
6e8dcecaf1 Fix CI (changelog ignore) 2022-01-19 01:29:06 +01:00
363 changed files with 41597 additions and 25564 deletions

2
.gitattributes vendored
View File

@ -1,3 +1,3 @@
src/lib/i18n/generated_kcMessages/* linguist-documentation
src/bin/build-keycloak-theme/index.ts -linguist-detectable
src/bin/keycloakify/index.ts -linguist-detectable
src/bin/install-builtin-keycloak-themes.ts -linguist-detectable

4
.github/FUNDING.yaml vendored Normal file
View File

@ -0,0 +1,4 @@
# These are supported funding model platforms
github: [garronej]
custom: ['https://www.ringerhq.com/experts/garronej']

25
.github/release.yaml vendored Normal file
View File

@ -0,0 +1,25 @@
changelog:
exclude:
labels:
- ignore-for-release
authors:
- octocat
categories:
- title: Breaking Changes 🛠
labels:
- breaking
- title: Exciting New Features 🎉
labels:
- feature
- title: Fixes 🔧
labels:
- fix
- title: Documentation 🔧
labels:
- docs
- title: CI đŸ‘·
labels:
- ci
- title: Other Changes
labels:
- '*'

View File

@ -9,11 +9,12 @@ on:
jobs:
test_formatting:
test_lint:
runs-on: ubuntu-latest
if: ${{ !github.event.created && github.repository != 'garronej/ts-ci' }}
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/setup-node@v2.1.3
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: bahmutov/npm-install@v1
- name: If this step fails run 'yarn format' then commit again.
run: |
@ -23,20 +24,21 @@ jobs:
fi
$PACKAGE_MANAGER run format:check
test:
runs-on: macos-10.15
needs: test_formatting
runs-on: ${{ matrix.os }}
needs: test_lint
strategy:
matrix:
node: [ '15', '14', '13' ]
name: Test with Node v${{ matrix.node }}
node: [ '14','16' ]
os: [ windows-latest, ubuntu-latest ]
name: Test with Node v${{ matrix.node }} on ${{ matrix.os }}
steps:
- name: Tell if project is using npm or yarn
id: step1
uses: garronej/ts-ci@v1.1.5
uses: garronej/ts-ci@v2.0.2
with:
action_name: tell_if_project_uses_npm_or_yarn
- uses: actions/checkout@v2.3.4
- uses: actions/setup-node@v2.1.3
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
- uses: bahmutov/npm-install@v1
@ -62,64 +64,49 @@ jobs:
from_version: ${{ steps.step1.outputs.from_version }}
to_version: ${{ steps.step1.outputs.to_version }}
is_upgraded_version: ${{ steps.step1.outputs.is_upgraded_version }}
is_release_beta: ${{steps.step1.outputs.is_release_beta }}
is_pre_release: ${{steps.step1.outputs.is_pre_release }}
steps:
- uses: garronej/ts-ci@v1.1.5
- uses: garronej/ts-ci@v2.0.2
id: step1
with:
action_name: is_package_json_version_upgraded
branch: ${{ github.head_ref || github.ref }}
update_changelog:
runs-on: ubuntu-latest
needs: check_if_version_upgraded
if: needs.check_if_version_upgraded.outputs.is_upgraded_version == 'true'
steps:
- uses: garronej/ts-ci@v1.1.5
with:
action_name: update_changelog
branch: ${{ github.head_ref || github.ref }}
create_github_release:
runs-on: ubuntu-latest
# We create a release only if the version have been upgraded and we are on the main branch
# or if we are on a branch of the repo that has an PR open on main.
if: |
needs.check_if_version_upgraded.outputs.is_upgraded_version == 'true' &&
(
github.event_name == 'push' ||
needs.check_if_version_upgraded.outputs.is_pre_release == 'true'
)
needs:
- update_changelog
- check_if_version_upgraded
steps:
- name: Build GitHub release body
id: step1
run: |
if [ "$FROM_VERSION" = "0.0.0" ]; then
echo "::set-output name=body::🚀"
else
echo "::set-output name=body::📋 [CHANGELOG](https://github.com/$GITHUB_REPOSITORY/blob/v$TO_VERSION/CHANGELOG.md)"
fi
env:
FROM_VERSION: ${{ needs.check_if_version_upgraded.outputs.from_version }}
TO_VERSION: ${{ needs.check_if_version_upgraded.outputs.to_version }}
- uses: garronej/action-gh-release@v0.2.0
- uses: softprops/action-gh-release@v1
with:
name: Release v${{ needs.check_if_version_upgraded.outputs.to_version }}
tag_name: v${{ needs.check_if_version_upgraded.outputs.to_version }}
target_commitish: ${{ github.head_ref || github.ref }}
body: ${{ steps.step1.outputs.body }}
generate_release_notes: true
draft: false
prerelease: ${{ needs.check_if_version_upgraded.outputs.is_release_beta == 'true' }}
prerelease: ${{ needs.check_if_version_upgraded.outputs.is_pre_release == 'true' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish_on_npm:
runs-on: macos-10.15
runs-on: ubuntu-latest
needs:
- update_changelog
- create_github_release
- check_if_version_upgraded
steps:
- uses: actions/checkout@v2.3.4
- uses: actions/checkout@v3
with:
ref: ${{ github.ref }}
- uses: actions/setup-node@v2.1.3
- uses: actions/setup-node@v3
with:
node-version: '15'
registry-url: https://registry.npmjs.org/
- uses: bahmutov/npm-install@v1
- run: |
@ -128,7 +115,7 @@ jobs:
PACKAGE_MANAGER=yarn
fi
$PACKAGE_MANAGER run build
- run: npx -y -p denoify@0.6.5 denoify_enable_short_npm_import_path
- run: npx -y -p denoify@1.2.2 enable_short_npm_import_path
env:
DRY_RUN: "0"
- name: Publishing on NPM
@ -142,11 +129,11 @@ jobs:
false
fi
EXTRA_ARGS=""
if [ "$IS_BETA" = "true" ]; then
EXTRA_ARGS="--tag beta"
if [ "$IS_PRE_RELEASE" = "true" ]; then
EXTRA_ARGS="--tag next"
fi
npm publish $EXTRA_ARGS
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
VERSION: ${{ needs.check_if_version_upgraded.outputs.to_version }}
IS_BETA: ${{ needs.check_if_version_upgraded.outputs.is_release_beta }}
IS_PRE_RELEASE: ${{ needs.check_if_version_upgraded.outputs.is_pre_release }}

4
.gitignore vendored
View File

@ -41,8 +41,12 @@ jspm_packages
.DS_Store
/dist
/dist_test
/sample_react_project/
/.yarn_home/
.idea
/keycloak_email
/build_keycloak

View File

@ -1,6 +1,10 @@
node_modules/
/dist/
/dist_test/
/CHANGELOG.md
/.yarn_home/
/src/test/apps/
/src/tools/types/
/src/tools/types/
/sample_react_project
/build_keycloak/
/src/lib/i18n/generated_messages/

View File

@ -5,7 +5,7 @@
"semi": true,
"singleQuote": false,
"quoteProps": "preserve",
"trailingComma": "all",
"trailingComma": "none",
"bracketSpacing": true,
"arrowParens": "avoid"
}

View File

@ -1,776 +0,0 @@
### **4.5.1** (2022-01-18)
- fix previous version
## **4.5.0** (2022-01-18)
- Read public/CNAME for domain name in --externel-assets mode
## **4.4.0** (2022-01-01)
- Merge pull request #73 from lazToum/main
(feature) added login-page-expired.ftl
- added login-page-expired.ftl
- Add update instruction for 4.3.0
## **4.3.0** (2021-12-27)
- Merge pull request #72 from praiz/main
feat(*): added login-update-password
- feat(*): added login-update-password
### **4.2.21** (2021-12-27)
- update dependencies
### **4.2.19** (2021-12-21)
- Merge pull request #70 from VBustamante/patch-1
- Added realm name field to KcContext mocks object
- Merge pull request #69 from VBustamante/patch-1
Adding name field to realm in KcContext type
- Adding name field to realm in KcContext type
### **4.2.18** (2021-12-17)
- Improve css url() import (fix CRA 5)
### **4.2.17** (2021-12-16)
- Fix path.join polyfill
### **4.2.16** (2021-12-16)
### **4.2.15** (2021-12-16)
- use custom polyfill for path.join (fix webpack 5 build)
### **4.2.14** (2021-12-12)
- Merge pull request #65 from InseeFrLab/doge_ftl_errors
Prevent ftl errors in Keycloak log
- Encourage users to report errors in logs
- Fix ftl error related to url.loginAction in saml-post-form.ftl
- Ftl prevent error with updateProfileCtx
- Ftl prevent error with auth.attemptedUsername
- Fix ftl error as comment formatting
- Merge remote-tracking branch 'origin/main' into doge_ftl_errors
- Update README, remove all instruction about errors in logs
- Avoid error in Keycloak logs, fix long template loading time
- Add missing collon in README sample code
Add miss ','
### **4.2.13** (2021-12-08)
- Fix broken link about how to import fonts #62
- Add a video to show how to test the theme in a local container
### **4.2.12** (2021-12-08)
- Update post build instructions
### **4.2.11** (2021-12-07)
### **4.2.10** (2021-11-12)
- Export an exaustive list of KcLanguageTag
### **4.2.9** (2021-11-11)
- Fix useAdvancedMsg
### **4.2.8** (2021-11-10)
- Update doc about pattern that can be used for user attributes #50
- Bring back Safari compat
### **4.2.7** (2021-11-09)
- Fix useFormValidationSlice
### **4.2.6** (2021-11-08)
- Fix deepClone so we can overwrite with undefined in when we mock kcContext
### **4.2.5** (2021-11-07)
- Better debugging experience with user profile
### **4.2.4** (2021-11-01)
- Better autoComplete typings
### **4.2.3** (2021-11-01)
- Make it more easy to understand that error in the log are expected
### **4.2.2** (2021-10-27)
- Replace 'path' by 'browserify-path' #47
### **4.2.1** (2021-10-26)
- useFormValidationSlice: update when params have changed
- Explains that the password can't be validated
## **4.2.0** (2021-10-26)
- Export types definitions for Attribue and Validator
## **4.1.0** (2021-10-26)
- Document what's new in v4
# **4.0.0** (2021-10-26)
- fix RegisterUserProfile password confirmation field
- Much better support for frontend field validation
- Fix css injection order
- Makes the download output predictable. This fixes the case where GitHub redirects and wget was trying to download a filename called "15.0.2", and then unzip wouldn't pick it up.
Changes wget to curl because curl is awesome. -L is to follow the GitHub redirects.
- Remove duplicates
### **3.0.2** (2021-10-18)
- Scan deeper to retreive user attribute
### **3.0.1** (2021-10-17)
- Add client.description in type kcContext type def
# **3.0.0** (2021-10-16)
### **2.5.3** (2021-10-16)
### **2.5.2** (2021-10-13)
### **2.5.1** (2021-10-13)
- Update tss-react
## **2.5.0** (2021-10-12)
- register-user-profile.ftl tested working
- Make kcMessage more easily hackable
- fix useKcMessage
- Implement and type validators
- Remove syntax error in ftl and make it more directly debugable
- Support register-user-profile.ftl
## **2.4.0** (2021-10-08)
- #38: Implement messagesPerField existsError and get
## **2.3.0** (2021-10-07)
- #20: Support advancedMsg
## **2.2.0** (2021-10-07)
- Feat scrip: download-builtin-keycloak-theme for downloading any version of the builtin themes
- Use the latest version of keycloak for testing
- Test locally with 15.0.2 instead of 11.0.3
## **2.1.0** (2021-10-06)
- Support Hungarian and Danish (use Keycloak 15 language resources)
### **2.0.20** (2021-10-05)
- Update README.md
### **2.0.19** (2021-09-17)
- Fix kcContext type definitions
### **2.0.18** (2021-09-14)
### **2.0.17** (2021-09-14)
### **2.0.16** (2021-09-12)
- Add explaination about errors in logs
### **2.0.15** (2021-08-31)
- Update tss-react
### **2.0.14** (2021-08-20)
- Update tss-react
### **2.0.13** (2021-08-04)
- Merge pull request #28 from marcmrf/main
fix(mvn): scoped packages compatibility
- fix(mvn): scoped packages compatibility
### **2.0.12** (2021-07-28)
- Merge pull request #27 from jchn-codes/patch-1
add maven to requirements
- add maven to requirements
- Add #bluehats in the keyworks
### **2.0.11** (2021-07-21)
- Spaces in file path #22
- uptdate dependnecies
- Inport specific powerhooks files to reduce bundle size
### **2.0.10** (2021-07-16)
- Update dependencies
### **2.0.9** (2021-07-14)
- Fix #21
### **2.0.8** (2021-07-12)
- Fix previous release
- #20: Add def for clientId and name on kcContext.client
### **2.0.6** (2021-07-08)
- Merge pull request #18 from asashay/add-custom-props-to-theme-properties
Add possibility to add custom properties to theme.properties file
- add possibility to add custom properties to theme.properties file
### **2.0.5** (2021-07-05)
- Fix broken url for big stylesheet #16
### **2.0.4** (2021-07-03)
- Fix: #7
### **2.0.3** (2021-06-30)
- Escape double quote in ftl to js conversion #15
- Update readme
### **2.0.2** (2021-06-28)
- Updagte README for implementing non incuded pages
### **2.0.1** (2021-06-28)
- Update documentation for v2
# **2.0.0** (2021-06-28)
- Fix last bugs before relasing v2
- Implement a mechanism to overload kcContext
- Give the option in template to pull the default assets or not
- Enable possiblity to support custom pages (without forking keycloakify)
- Implement a getter for kcContext
- Update README.md
# **2.0.0** (2021-06-28)
- Fix last bugs before relasing v2
- Implement a mechanism to overload kcContext
- Give the option in template to pull the default assets or not
- Enable possiblity to support custom pages (without forking keycloakify)
- Implement a getter for kcContext
- Update README.md
### **1.2.1** (2021-06-22)
- Remove unessesary log
## **1.2.0** (2021-06-22)
- Generate kcContext automatically :rocket:
### **1.1.6** (2021-06-21)
- Fix: Alert messages sometimes includes HTML that is not rendered
- Update dist
### **1.1.5** (2021-06-15)
- #11: Provide socials in the register
### **1.1.4** (2021-06-15)
- Merge pull request #12 from InseeFrLab/email-typo
Fix typo on email
- Fix typo on email
### **1.1.3** (2021-06-14)
- Add missing key in Login for providers
### **1.1.2** (2021-06-14)
### **1.1.1** (2021-06-14)
## **1.1.0** (2021-06-14)
- Add login-idp-link-confirm.ftl
- Fix login-update-profile.ftl
- Add login-update-profile.ftl page
- Fix default background bug
- Remove unused 'markdown' dependency
- Fix warning related to powerhooks_useGlobalState_kcLanguageTag
- Update README.md
### **1.0.4** (2021-05-28)
- Instructions for custom themes with custom components
### **1.0.3** (2021-05-23)
- Instuction about how to integrate with non CRA projects
- Add mention to awesome list
### **1.0.2** (2021-05-01)
### **1.0.1** (2021-05-01)
- Fix: LoginOtp (and not otc)
# **1.0.0** (2021-05-01)
- #4: Guide for implementing a missing page
- Support OTP #4
### **0.4.4** (2021-04-29)
- Fix previous release
### **0.4.3** (2021-04-29)
- Add infos about the plugin that defines authorizedMailDomains
### **0.4.2** (2021-04-29)
- Client side validation of allowed email domains
- Support email whitlisting
- Restore kickstart video in the readme
- Update README.md
- Update README.md
- Important readme update
### **0.4.1** (2021-04-11)
- Quietly re-introduce --external-assets
- Give example of customization
## **0.4.0** (2021-04-09)
- Acual support of Therms of services
### **0.3.24** (2021-04-08)
- Add missing dependency: markdown
### **0.3.23** (2021-04-08)
- Allow to lazily load therms
### **0.3.22** (2021-04-08)
- update powerhooks
- Support terms and condition
- Fix info.ftl
- For useKcMessage we prefer returning callbacks with a changing references
### **0.3.21** (2021-04-04)
- Update powerhooks
### **0.3.20** (2021-04-01)
- Always catch freemarker errors
### **0.3.19** (2021-04-01)
- Fix previous release
### **0.3.18** (2021-04-01)
- Fix error.ftt, Adopt best effort strategy to convert ftl values into JS
### **0.3.17** (2021-03-29)
- Use push instead of replace in keycloak-js adapter to enable going back
### **0.3.15** (2021-03-28)
- Remove all reference to --external-assets, broken feature
### **0.3.14** (2021-03-28)
- Fix standalone mode: imports from js
### **0.3.13** (2021-03-26)
### **0.3.12** (2021-03-26)
- Fix mocksContext
### **0.3.11** (2021-03-26)
- Fix previous build, improve README
### **0.3.10** (2021-03-26)
- Handle <style> tag, improve documentation
### **0.3.9** (2021-03-25)
- Update readme
- Document --external-assets
- Update README.md
- Update README.md
- Update README.md
### **0.3.8** (2021-03-22)
- Make standalone mode the default
### **0.3.7** (2021-03-22)
- (test) external asset mode by default
### **0.3.6** (2021-03-22)
- Fix previous release
### **0.3.5** (2021-03-22)
- support homepage with urlPath
### **0.3.4** (2021-03-22)
- Bugfix: Import assets from CSS
### **0.3.3** (2021-03-22)
- Fix submit not receving correct text
### **0.3.2** (2021-03-21)
- Fix broken previous release
### **0.3.1** (2021-03-21)
- kcHeaderClass can be updated after initial mount
## **0.3.0** (2021-03-20)
- Bump version
- Feat: Cary over states using URL search params
- Bugfix: with kcHtmlClass
### **0.2.10** (2021-03-19)
- Remove dependency to denoify
### **0.2.9** (2021-03-19)
- Update deps and CI workflow
### **0.2.8** (2021-03-19)
- Bugfix: keycloak_build that grow and grow in size
- Add disclaimer about maitainment strategy
- Add a note for tested version support
### **0.2.7** (2021-03-13)
- Bump version
- Update README.md
- Update README.md
### **0.2.6** (2021-03-10)
- Fix generated gitignore
### **0.2.5** (2021-03-10)
- Fix generated .gitignore
### **0.2.4** (2021-03-10)
- Update README.md
### **0.2.3** (2021-03-09)
- fix gitignore generation
### **0.2.2** (2021-03-08)
- Add table of content
- Update README.md
- Update README.md
## **0.2.1** (2021-03-08)
- Update ci.yaml
- Update readme
- Update readme
- update deps
- Update readme
- Add all mocks for testing
- many small fixes
### **0.1.6** (2021-03-07)
- Fix Turkish
### **0.1.5** (2021-03-07)
- Fix getKcLanguageLabel
### **0.1.4** (2021-03-07)
### **0.1.3** (2021-03-07)
- Implement LoginVerifyEmail
- Implement login-reset-password.ftl
### **0.1.2** (2021-03-07)
- Fix build
- Fix build
### **0.1.1** (2021-03-06)
- Implement Error page
- rename pageBasename by pageId
- Implement reactive programing for language switching
- Add Info page, refactor
## **0.1.0** (2021-03-05)
- Rename keycloakify
### **0.0.33** (2021-03-05)
- Fix syncronization with non react pages
### **0.0.32** (2021-03-05)
- bump version
- Add log to tell when we are using react
- Fix missing parentesis
### **0.0.31** (2021-03-05)
- Fix typo
- Fix register page 500
### **0.0.30** (2021-03-05)
- Edit language statistique
### **0.0.30** (2021-03-05)
- avoid escaping urls
- Use default value instead of value
- Fix double single quote problem in messages
- Fix typo
- Fix non editable username
- Fix some bugs
- Fix Object.deepAssign
- Make the dongle to download smaller
- Split kcContext among pages
- Implement register
### **0.0.29** (2021-03-04)
- Fix build
- Fix i18n
- Login appear to be working now
- closer but not there yet
### **0.0.28** (2021-03-03)
- fix build
- There is no reason not to let use translations outside of keycloak
### **0.0.27** (2021-03-02)
- Implement entrypoint
### **0.0.26** (2021-03-02)
- Login page implemented
- Implement login
- remove unesseary log
### **0.0.25** (2021-03-02)
- Fix build and reduce size
- Implement the template
### **0.0.24** (2021-03-01)
- update
- update
- update
### **0.0.23** (2021-03-01)
- update
### **0.0.23** (2021-03-01)
- update
- update
### **0.0.23** (2021-03-01)
- update
- update
### **0.0.23** (2021-03-01)
- update
- Handle formatting in translation function
### **0.0.22** (2021-02-28)
- Split page messages
### **0.0.21** (2021-02-28)
- Restore yarn file
- Multiple fixes
- Update deps
- Update deps
- includes translations
- Update README.md
- improve docs
- update
- Update README.md
- update
- update
- update
- update
### **0.0.20** (2021-02-27)
- update
- update
### **0.0.19** (2021-02-27)
- update
- update
### **0.0.18** (2021-02-23)
- Bump version number
- Moving on with implementation of the lib
- Update readme
- Readme eddit
- Fixing video link
### **0.0.16** (2021-02-23)
- Bump version
- Give test container credentials
### **0.0.14** (2021-02-23)
- Bump version number
- enable the docker container to be run from the root of the react project
### **0.0.13** (2021-02-23)
- bump version
### **0.0.12** (2021-02-23)
- update readme
### **0.0.11** (2021-02-23)
- Add documentation
### **0.0.10** (2021-02-23)
- Remove extra closing bracket
### **0.0.9** (2021-02-22)
- fix container startup script
- minor update
### **0.0.8** (2021-02-21)
- Include theme properties
### **0.0.7** (2021-02-21)
- fix build
- Fix bundle
### **0.0.6** (2021-02-21)
- Include missing files in the release bundle
### **0.0.5** (2021-02-21)
- Bump version number
- Make the install faster
### **0.0.4** (2021-02-21)
- Fix script visibility
### **0.0.3** (2021-02-21)
- Do not run tests on window
- Add script for downloading base themes
- Generate debug files to be able to test the container
- Fix many little bugs
- refactor
- Almoste there
- Things are starting to take form
- Seems to be working
- First draft
- Remove eslint and prettyer
### **0.0.2** (2021-02-20)
- Update package.json

3
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,3 @@
Looking to contribute? Thank you! PR are more than welcome.
Please refers to [this documentation page](https://docs.keycloakify.dev/contributing) that will help you get started.

594
README.md
View File

@ -2,17 +2,14 @@
<img src="https://user-images.githubusercontent.com/6702424/109387840-eba11f80-7903-11eb-9050-db1dad883f78.png">
</p>
<p align="center">
<i>🔏 Create Keycloak themes using React 🔏</i>
<i>🔏 Create Keycloak themes using React 🔏</i>
<br>
<br>
<a href="https://github.com/garronej/keycloakify/actions">
<img src="https://github.com/garronej/keycloakify/workflows/ci/badge.svg?branch=main">
</a>
<a href="https://bundlephobia.com/package/keycloakify">
<img src="https://img.shields.io/bundlephobia/minzip/keycloakify">
</a>
<a href="https://www.npmjs.com/package/keycloakify">
<img src="https://img.shields.io/npm/dw/keycloakify">
<img src="https://img.shields.io/npm/dm/keycloakify">
</a>
<a href="https://github.com/garronej/keycloakify/blob/main/LICENSE">
<img src="https://img.shields.io/npm/l/keycloakify">
@ -23,465 +20,152 @@
<a href="https://github.com/thomasdarimont/awesome-keycloak">
<img src="https://awesome.re/mentioned-badge.svg"/>
</a>
<p align="center">
<a href="https://www.keycloakify.dev">Home</a>
-
<a href="https://docs.keycloakify.dev">Documentation</a>
-
<a href="https://github.com/codegouvfr/keycloakify-starter">Starter project</a>
</p>
</p>
<p align="center">
<i>Ultimately this build tool generates a Keycloak theme</i>
<i>Ultimately this build tool generates a Keycloak theme <a href="https://www.keycloakify.dev">Learn more</a></i>
<img src="https://user-images.githubusercontent.com/6702424/110260457-a1c3d380-7fac-11eb-853a-80459b65626b.png">
</p>
> **New in v4.4.0**: Feature [`login-page-expired.ftl`](https://user-images.githubusercontent.com/6702424/147856832-38c042a7-9fc8-473f-9595-e00123095ca6.png).
> Every time a page is added it's a breaking change for non CSS-only theme.
> Change [this](https://github.com/garronej/keycloakify-demo-app/blob/812754109c61157741f4a0b222026deb1538a02d/src/KcApp/KcApp.tsx#L18) and [this](https://github.com/garronej/keycloakify-demo-app/blob/812754109c61157741f4a0b222026deb1538a02d/src/KcApp/KcApp.tsx#L39) to update.
# Motivations
Keycloak provides [theme support](https://www.keycloak.org/docs/latest/server_development/#_themes) for web pages. This allows customizing the look and feel of end-user facing pages so they can be integrated with your applications.
It involves, however, a lot of raw JS/CSS/[FTL]() hacking, and bundling the theme is not exactly straightforward.
Beyond that, if you use Keycloak for a specific app you want your login page to be tightly integrated with it.
Ideally, you don't want the user to notice when he is being redirected away.
Trying to reproduce the look and feel of a specific app in another stack is not an easy task not to mention
the cheer amount of maintenance that it involves.
<p align="center">
<i>Without keycloakify, users suffers from a harsh context switch, no fronted form pre-validation</i><br>
<img src="https://user-images.githubusercontent.com/6702424/134997335-a28b4a57-0884-47ec-9341-a0e49f835c4d.gif">
</p>
Wouldn't it be great if we could just design the login and register pages as if they were part of our app?
Here is `keycloakify` for you 🍾
<p align="center">
<i> <a href="https://datalab.sspcloud.fr">With keycloakify:</a> </i>
<br>
<img src="https://user-images.githubusercontent.com/6702424/114332075-c5e37900-9b45-11eb-910b-48a05b3d90d9.gif">
</p>
**TL;DR**: [Here](https://github.com/garronej/keycloakify-demo-app) is a Hello World React project with Keycloakify set up.
If you already have a Keycloak custom theme, it can be easily ported to Keycloakify.
---
- [Motivations](#motivations)
- [Requirements](#requirements)
- [My framework doesn’t seem to be supported, what can I do?](#my-framework-doesnt-seem-to-be-supported-what-can-i-do)
- [How to use](#how-to-use)
- [Setting up the build tool](#setting-up-the-build-tool)
- [Changing just the look of the default Keycloak theme](#changing-just-the-look-of-the-default-keycloak-theme)
- [Advanced pages configuration](#advanced-pages-configuration)
- [Hot reload](#hot-reload)
- [Enable loading in a blink of an eye of login pages ⚡ (--external-assets)](#enable-loading-in-a-blink-of-an-eye-of-login-pages----external-assets)
- [User profile and frontend form validation](#user-profile-and-frontend-form-validation)
- [Support for Terms and conditions](#support-for-terms-and-conditions)
- [Some pages still have the default theme. Why?](#some-pages-still-have-the-default-theme-why)
- [GitHub Actions](#github-actions)
- [Limitations](#limitations)
- [`process.env.PUBLIC_URL` not supported.](#processenvpublic_url-not-supported)
- [`@font-face` importing fonts from the `src/` dir](#font-face-importing-fonts-from-the-src-dir)
- [Example of setup that **won't** work](#example-of-setup-that-wont-work)
- [Possible workarounds](#possible-workarounds)
- [Implement context persistence (optional)](#implement-context-persistence-optional)
- [Kickstart video](#kickstart-video)
- [FTL errors related to `ftl_object_to_js_code_declaring_an_object` in Keycloak logs.](#ftl-errors-related-to-ftl_object_to_js_code_declaring_an_object-in-keycloak-logs)
- [Adding custom message (to `i18n/useKcMessage.tsx`)](#adding-custom-message-to-i18nusekcmessagetsx)
- [Email domain whitelist](#email-domain-whitelist)
- [Changelog highlights](#changelog-highlights)
- [v4](#v4)
- [v3](#v3)
- [v2.5](#v25)
- [v2](#v2)
# Requirements
On Windows OS you'll have to use [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10). More info [here](https://github.com/InseeFrLab/keycloakify/issues/54%23issuecomment-984834217)
Tested with the following Keycloak versions:
- [11.0.3](https://hub.docker.com/layers/jboss/keycloak/11.0.3/images/sha256-4438f1e51c1369371cb807dffa526e1208086b3ebb9cab009830a178de949782?context=explore)
- [12.0.4](https://hub.docker.com/layers/jboss/keycloak/12.0.4/images/sha256-67e0c88e69bd0c7aef972c40bdeb558a974013a28b3668ca790ed63a04d70584?context=explore)
- [15.0.2](https://hub.docker.com/layers/jboss/keycloak/15.0.2/images/sha256-d8ed1ee5df42a178c341f924377da75db49eab08ea9f058ff39a8ed7ee05ec93?context=explore)
This tool will be maintained to stay compatible with Keycloak v11 and up, however, the default pages you will get
(before you customize it) will always be the ones of Keycloak v11.
This tool assumes you are bundling your app with Webpack (tested with the versions that ships with CRA v4.44.2 and v5.0.0) .
It assumes there is a `build/` directory at the root of your react project directory containing a `index.html` file
and a `build/static/` directory generated by webpack.
For more information see [this issue](https://github.com/InseeFrLab/keycloakify/issues/5#issuecomment-832296432)
**All this is defaults with [`create-react-app`](https://create-react-app.dev)** (tested with 4.0.3)
- `mvn` ([Maven](https://maven.apache.org/)), `rm`, `mkdir`, `curl`, `unzip` are assumed to be available.
- `docker` must be up and running when running `start_keycloak_testing_container.sh` (Instructions provided after running `yarn keycloak`).
## My framework doesn’t seem to be supported, what can I do?
Currently Keycloakify is only compatible with `create-react-app` apps.
It doesn’t mean that you can't use Keycloakify if you are using Next.js, Express or any other
framework that involves SSR but your Keycloak theme will need to be a standalone project.
Find specific instructions about how to get started [**here**](https://github.com/garronej/keycloakify-demo-app#keycloak-theme-only).
To share your styles between your main app and your login pages you will need to externalize your design system by making it a
separate module. Checkout [ts_ci](https://github.com/garronej/ts_ci), it can help with that.
# How to use
## Setting up the build tool
```bash
yarn add keycloakify @emotion/react tss-react powerhooks
```
[`package.json`](https://github.com/garronej/keycloakify-demo-app/blob/main/package.json)
```json
"scripts": {
"keycloak": "yarn build && build-keycloak-theme",
}
```
```bash
yarn keycloak # generates keycloak-theme.jar
```
On the console will be printed all the instructions about how to load the generated theme in Keycloak
### Changing just the look of the default Keycloak theme
The first approach is to only customize the style of the default Keycloak login by providing
your own class names.
If you have created a new React project specifically to create a Keycloak theme and nothing else then
your index should look something like:
`src/index.tsx`
```tsx
import { App } from "./<wherever>/App";
import { KcApp, defaultKcProps, getKcContext } from "keycloakify";
import { css } from "tss-react/@emotion/css";
const { kcContext } = getKcContext();
const myClassName = css({ "color": "red" });
reactDom.render(
<KcApp
kcContext={kcContext}
{...{
...defaultKcProps,
"kcHeaderWrapperClass": myClassName,
}}
/>,
document.getElementById("root"),
);
```
If you share a unique project for your app and the Keycloak theme, your index should look
more like this:
`src/index.tsx`
```tsx
import { App } from "./<wherever>/App";
import { KcApp, defaultKcProps, getKcContext } from "keycloakify";
import { css } from "tss-react/@emotion/css";
const { kcContext } = getKcContext();
const myClassName = css({ "color": "red" });
reactDom.render(
// Unless the app is currently being served by Keycloak
// kcContext is undefined.
kcContext !== undefined ? (
<KcApp
kcContext={kcContext}
{...{
...defaultKcProps,
"kcHeaderWrapperClass": myClassName,
}}
/>
) : (
<App />
), // Your actual app
document.getElementById("root"),
);
```
<p align="center">
<i>result:</i></br>
<img src="https://user-images.githubusercontent.com/6702424/114326299-6892fc00-9b34-11eb-8d75-85696e55458f.png">
</p>
Example of a customization using only CSS: [here](https://github.com/InseeFrLab/onyxia-web/blob/012639d62327a9a56be80c46e32c32c9497b82db/src/app/components/KcApp.tsx)
(the [index.tsx](https://github.com/InseeFrLab/onyxia-web/blob/012639d62327a9a56be80c46e32c32c9497b82db/src/app/index.tsx#L89-L94) )
and the result you can expect:
<p align="center">
<i> <a href="https://datalab.sspcloud.fr">Customization using only CSS:</a> </i>
<br>
<img src="https://github.com/InseeFrLab/keycloakify/releases/download/v0.3.8/keycloakify_after.gif">
</p>
### Advanced pages configuration
If you want to go beyond only customizing the CSS you can re-implement some of the
pages or even add new ones.
If you want to go this way checkout the demo setup provided [here](https://github.com/garronej/keycloakify-demo-app/tree/look_and_feel).
If you prefer a real life example you can checkout [onyxia-web's source](https://github.com/InseeFrLab/onyxia-web/tree/main/src/ui/components/KcApp).
The web app is in production [here](https://datalab.sspcloud.fr).
Main takeaways are:
- You must declare your custom pages in the package.json. [example](https://github.com/garronej/keycloakify-demo-app/blob/4eb2a9f63e9823e653b2d439495bda55e5ecc134/package.json#L17-L22)
- (TS only) You must declare theses page in the type argument of the getter
function for the `kcContext` in order to have the correct typings. [example](https://github.com/garronej/keycloakify-demo-app/blob/4eb2a9f63e9823e653b2d439495bda55e5ecc134/src/KcApp/kcContext.ts#L16-L21)
- (TS only) If you use Keycloak plugins that defines non standard `.ftl` values
(Like for example [this plugin](https://github.com/micedre/keycloak-mail-whitelisting)
that define `authorizedMailDomains` in `register.ftl`) you should
declare theses value to get the type. [example](https://github.com/garronej/keycloakify-demo-app/blob/4eb2a9f63e9823e653b2d439495bda55e5ecc134/src/KcApp/kcContext.ts#L6-L13)
- You should provide sample data for all the non standard value if you want to be able
to debug the page outside of keycloak. [example](https://github.com/garronej/keycloakify-demo-app/blob/4eb2a9f63e9823e653b2d439495bda55e5ecc134/src/KcApp/kcContext.ts#L28-L43)
WARNING: If you chose to go this way use:
```json
"dependencies": {
"keycloakify": "~X.Y.Z"
}
```
in your `package.json` instead of `^X.Y.Z`. A minor update of Keycloakify might break your app.
### Hot reload
Rebuild the theme each time you make a change to see the result is not practical.
If you want to test your login screens outside of Keycloak you can mock a given `kcContext`:
```tsx
import {
KcApp,
defaultKcProps,
getKcContext
} from "keycloakify";
const { kcContext } = getKcContext({
"mockPageId": "login.ftl"
});
reactDom.render(
<KcApp
kcContext={kcContextMocks.kcLoginContext}
{...defaultKcProps}
/>
document.getElementById("root")
);
```
Then `yarn start`, you will see your login page.
Checkout [this concrete example](https://github.com/garronej/keycloakify-demo-app/blob/main/src/index.tsx)
## Enable loading in a blink of an eye of login pages ⚡ (--external-assets)
By default the theme generated is standalone. Meaning that when your users
reach the login pages all scripts, images and stylesheet are downloaded from the Keycloak server.
If you are specifically building a theme to integrate with an app or a website that allows users
to first browse unauthenticated before logging in, you will get a significant
performance boost if you jump through those hoops:
- Provide the url of your app in the `homepage` field of package.json. [ex](https://github.com/garronej/keycloakify-demo-app/blob/7847cc70ef374ab26a6cc7953461cf25603e9a6d/package.json#L2) or in a `public/CNAME` file. [ex](https://github.com/garronej/keycloakify-demo-app/blob/main/public/CNAME).
- Build the theme using `npx build-keycloak-theme --external-assets` [ex](https://github.com/garronej/keycloakify-demo-app/blob/7847cc70ef374ab26a6cc7953461cf25603e9a6d/.github/workflows/ci.yaml#L21)
- Enable [long-term assets caching](https://create-react-app.dev/docs/production-build/#static-file-caching) on the server hosting your app.
- Make sure not to build your app and the keycloak theme separately
and remember to update the Keycloak theme every time you update your app.
- Be mindful that if your app is down your login pages are down as well.
Checkout a complete setup [here](https://github.com/garronej/keycloakify-demo-app#about-keycloakify)
# User profile and frontend form validation
<p align="center">
<a href="https://github.com/InseeFrLab/keycloakify/releases/download/v0.0.1/keycloakify_fontend_validation.mp4">
<img src="https://user-images.githubusercontent.com/6702424/138880146-6fef3280-c4a5-46d2-bbb3-8b9598c057a5.gif">
</a>
</p>
NOTE: In reality the regexp used in this gif doesn't work server side, the regexp pattern should be `^[^@]@gmail\.com$` 😬.
User Profile is a Keycloak feature that enables to
[define, from the admin console](https://user-images.githubusercontent.com/6702424/136872461-1f5b64ef-d2ef-4c6b-bb8d-07d4729552b3.png),
what information you want to collect on your users in the register page and to validate inputs
[**on the frontend**, in realtime](https://github.com/InseeFrLab/keycloakify/blob/6dca6a93d8cfe634ee4d8574ad0c091641220092/src/lib/getKcContext/KcContextBase.ts#L225-L261)!
NOTE: User profile is only available in Keycloak 15 and it's a beta feature that
[needs to be enabled when launching keycloak](https://github.com/InseeFrLab/keycloakify/blob/59f106bf9e210b63b190826da2bf5f75fc8b7644/src/bin/build-keycloak-theme/build-keycloak-theme.ts#L116-L117)
and [enabled in the console](https://user-images.githubusercontent.com/6702424/136874428-b071d614-c7f7-440d-9b2e-670faadc0871.png).
Keycloakify, in [`register-user-profile.ftl`](https://github.com/InseeFrLab/keycloakify/blob/main/src/lib/components/RegisterUserProfile.tsx),
provides frontend validation out of the box.
For implementing your own `register-user-profile.ftl` page, you can use [`import { useFormValidationSlice } from "keycloakify";`](https://github.com/InseeFrLab/keycloakify/blob/main/src/lib/useFormValidationSlice.tsx).
Find usage example [`here`](https://github.com/InseeFrLab/keycloakify/blob/d3a07edfcb3739e30032dc96fc2a55944dfc3387/src/lib/components/RegisterUserProfile.tsx#L79-L112).
As for right now [it's not possible to define a pattern for the password](https://keycloak.discourse.group/t/make-password-policies-available-to-freemarker/11632)
from the admin console. You can however pass validators for it to the `useFormValidationSlice` function.
# Support for Terms and conditions
[Many organizations have a requirement that when a new user logs in for the first time, they need to agree to the terms and conditions of the website.](https://www.keycloak.org/docs/4.8/server_admin/#terms-and-conditions).
First you need to enable the required action on the Keycloak server admin console:
![image](https://user-images.githubusercontent.com/6702424/114280501-dad2e600-9a39-11eb-9c39-a225572dd38a.png)
Then to load your own therms of services using [like this](https://github.com/garronej/keycloakify-demo-app/blob/8168c928a66605f2464f9bd28a4dc85fb0a231f9/src/index.tsx#L42-L66).
# Some pages still have the default theme. Why?
This project only support out of the box the most common user facing pages of Keycloak login.
[Here](https://user-images.githubusercontent.com/6702424/116787906-227fe700-aaa7-11eb-92ee-22e7673717c2.png) is the complete list of pages (you get them after running `yarn test`)
and [here](https://github.com/InseeFrLab/keycloakify/tree/main/src/lib/components) are the pages currently implemented by this module.
If you need to customize pages that are not supported yet or if you need to implement some non standard `.ftl` pages please refer to [Advanced pages configuration](#advanced-pages-configuration).
# GitHub Actions
![image](https://user-images.githubusercontent.com/6702424/114286938-47aea600-9a63-11eb-936e-17159e8826e8.png)
[Here is a demo repo](https://github.com/garronej/keycloakify-demo-app) to show how to automate
the building and publishing of the theme (the .jar file).
# Limitations
## `process.env.PUBLIC_URL` not supported.
You won't be able to [import things from your public directory **in your JavaScript code**](https://create-react-app.dev/docs/using-the-public-folder/#adding-assets-outside-of-the-module-system).
(This isn't recommended anyway).
## `@font-face` importing fonts from the `src/` dir
If you are building the theme with [--external-assets](#enable-loading-in-a-blink-of-a-eye-of-login-pages-)
this limitation doesn't apply, you can import fonts however you see fit.
### Example of setup that **won't** work
- We have a `fonts/` directory in `src/`
- We import the font like this [`src: url("/fonts/my-font.woff2") format("woff2");`](https://github.com/garronej/keycloakify-demo-app/blob/07d54a3012ef354ee12b1374c6f7ad1cb125d56b/src/fonts.scss#L4) in a `.scss` a file.
### Possible workarounds
- Use [`--external-assets`](#enable-loading-in-a-blink-of-a-eye-of-login-pages-).
- If it is possible, use Google Fonts or any other font provider.
- If you want to host your font recommended approach is to move your fonts into the `public`
directory and to place your `@font-face` statements in the `public/index.html`.
Example [here](https://github.com/garronej/keycloakify-demo-app/blob/9aa2dbaec28a7786d6b2983c9a59d393dec1b2d6/public/index.html#L27-L73)
(and the font are [here](https://github.com/garronej/keycloakify-demo-app/tree/main/public/fonts/WorkSans)).
- You can also [use non relative url](https://github.com/garronej/keycloakify-demo-app/blob/2de8a9eb6f5de9c94f9cd3991faad0377e63268c/src/fonts.scss#L16) but don't forget [`Access-Control-Allow-Origin`](https://github.com/garronej/keycloakify-demo-app/blob/2de8a9eb6f5de9c94f9cd3991faad0377e63268c/nginx.conf#L17-L19).
# Implement context persistence (optional)
If, before logging in, a user has selected a specific language
you don't want it to be reset to default when the user gets redirected to
the login or register pages.
Same goes for the dark mode, you don't want, if the user had it enabled
to show the login page with light themes.
The problem is that you are probably using `localStorage` to persist theses values across
reload but, as the Keycloak pages are not served on the same domain that the rest of your
app you won't be able to carry over states using `localStorage`.
The only reliable solution is to inject parameters into the URL before
redirecting to Keycloak. We integrate with
[`keycloak-js`](https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/javascript-adapter.adoc),
by providing you a way to tell `keycloak-js` that you would like to inject
some search parameters before redirecting.
The method also works with [`@react-keycloak/web`](https://www.npmjs.com/package/@react-keycloak/web) (use the `initOptions`).
You can implement your own mechanism to pass the states in the URL and
restore it on the other side but we recommend using `powerhooks/useGlobalState`
from the library [`powerhooks`](https://www.powerhooks.dev) that provide an elegant
way to handle states such as `isDarkModeEnabled` or `selectedLanguage`.
Let's modify [the example](https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/javascript-adapter.adoc) from the official `keycloak-js` documentation to
enables the states of `useGlobalStates` to be injected in the URL before redirecting.
Note that the states are automatically restored on the other side by `powerhooks`
```typescript
import keycloak_js from "keycloak-js";
import { injectGlobalStatesInSearchParams } from "powerhooks/useGlobalState";
import { createKeycloakAdapter } from "keycloakify";
//...
const keycloakInstance = keycloak_js({
"url": "http://keycloak-server/auth",
"realm": "myrealm",
"clientId": "myapp",
});
keycloakInstance.init({
"onLoad": "check-sso",
"silentCheckSsoRedirectUri": window.location.origin + "/silent-check-sso.html",
"adapter": createKeycloakAdapter({
"transformUrlBeforeRedirect": injectGlobalStatesInSearchParams,
keycloakInstance,
}),
});
//...
```
If you really want to go the extra miles and avoid having the white
flash of the blank html before the js bundle have been evaluated
[here is a snippet](https://github.com/InseeFrLab/onyxia-web/blob/e1c1f309aaa3d5f860df39ba0b75cce89c88a9de/public/index.html#L117-L166) that you can place in your `public/index.html` if you are using `powerhooks/useGlobalState`.
# Kickstart video
_NOTE: keycloak-react-theming was renamed keycloakify since this video was recorded_
[![kickstart_video](https://user-images.githubusercontent.com/6702424/108877866-f146ee80-75ff-11eb-8120-003b3c5f6dd8.png)](https://youtu.be/xTz0Rj7i2v8)
# FTL errors related to `ftl_object_to_js_code_declaring_an_object` in Keycloak logs.
If you ever encounter one of these errors:
```log
FTL stack trace ("~" means nesting-related):
- Failed at: #local value = object[key] [in template "login.ftl" in macro "ftl_object_to_js_code_declaring_an_object" at line 70, column 21]
- Reached through: @compress [in template "login.ftl" in macro "ftl_object_to_js_code_declaring_an_object" at line 36, column 5]
- Reached through: @ftl_object_to_js_code_declaring_an_object object=value depth=(dep... [in template "login.ftl" in macro "ftl_object_to_js_code_declaring_an_object" at line 81, column 27]
- Reached through: @compress [in template "login.ftl" in macro "ftl_object_to_js_code_declaring_an_object" at line 36, column 5]
- Reached through: @ftl_object_to_js_code_declaring_an_object object=(.data_model) de... [in template "login.ftl" at line 163, column 43]
```
It's just noise, they can be safely ignored.
You can, however, and are encouraged to, report any that you would spot.
Just open an issue about it and I will release a patched version of Keycloakify in the better delays.
# Adding custom message (to `i18n/useKcMessage.tsx`)
You can reproduce [this approach](https://github.com/garronej/keycloakify-demo-app/blob/main/src/kcMessagesExtension.ts)
( don't forget to [evaluate the code](https://github.com/garronej/keycloakify-demo-app/blob/0a6d349dba89a5702f98ba48bca6c76ac7265e1f/src/index.tsx#L15) ).
This approach is a bit hacky as it doesn't provide type safety but it works.
# Email domain whitelist
NOTE: This have been kind of deprecated by [user attribute](#user-profile-and-frontend-form-validation) you could
use a pattern [like this one](https://github.com/InseeFrLab/onyxia-web/blob/f1206e0329b3b8d401ca7bffa95ca9c213cb190a/src/app/components/KcApp/kcContext.ts#L106) to whitelist email domains.
If you want to restrict the emails domain that can register, you can use [this plugin](https://github.com/micedre/keycloak-mail-whitelisting)
and `kcRegisterContext["authorizedMailDomains"]` to validate on.
> 🗣 V6 have been released 🎉
> [It features major improvements](https://github.com/InseeFrLab/keycloakify#600).
> Checkout [the migration guide](https://docs.keycloakify.dev/v5-to-v6).
# Changelog highlights
> **New in v4.3.0**: Feature [`login-update-password.ftl`](https://user-images.githubusercontent.com/6702424/147517600-6191cf72-93dd-437b-a35c-47180142063e.png).
> Every time a page is added it's a breaking change for non CSS-only theme.
> Change [this](https://github.com/garronej/keycloakify-demo-app/blob/df664c13c77ce3c53ac7df0622d94d04e76d3f9f/src/KcApp/KcApp.tsx#L17) and [this](https://github.com/garronej/keycloakify-demo-app/blob/df664c13c77ce3c53ac7df0622d94d04e76d3f9f/src/KcApp/KcApp.tsx#L37) to update.
## 6.13
- Build work behind corporate proxies, [see issue](https://github.com/InseeFrLab/keycloakify/issues/257).
## 6.12
Massive improvement in the developer experience:
- There is now only one starter repo: https://github.com/codegouvfr/keycloakify-starter
- A lot of comments have been added in the code of the starter to make it easier to get started.
- The doc has been updated: https://docs.keycloakify.dev
- A lot of improvements in the type system.
## 6.11.4
- You no longer need to have Maven installed to build the theme. Thanks to @lordvlad, [see PR](https://github.com/InseeFrLab/keycloakify/pull/239).
- Feature new build options: [`bundler`](https://docs.keycloakify.dev/build-options#keycloakify.bundler), [`groupId`](https://docs.keycloakify.dev/build-options#keycloakify.groupid), [`artifactId`](https://docs.keycloakify.dev/build-options#keycloakify.artifactid), [`version`](https://docs.keycloakify.dev/build-options#version).
Theses options can be user to customize the output name of the .jar. You can use environnement variables to overrides the values read in the package.json. Thanks to @lordvlad.
## 6.10.0
- Widows compat (thanks to @lordvlad, [see PR](https://github.com/InseeFrLab/keycloakify/pull/226)). WSL is no longer required 🎉
## 6.8.4
- `@emotion/react` is no longer a peer dependency of Keycloakify.
## 6.8.0
- It is now possible to pass a custom `<Template />` component as a prop to `<KcApp />` and every
individual page (`<Login />`, `<RegisterUserProfile />`, ...) it enables to customize only the header and footer for
example without having to switch to a full-component level customization. [See issue](https://github.com/InseeFrLab/keycloakify/issues/191).
## 6.7.0
- Add support for `webauthn-authenticate.ftl` thanks to [@mstrodl](https://github.com/Mstrodl)'s hacktoberfest [PR](https://github.com/InseeFrLab/keycloakify/pull/185).
## 6.6.0
- Add support for `login-password.ftl` thanks to [@mstrodl](https://github.com/Mstrodl)'s hacktoberfest [PR](https://github.com/InseeFrLab/keycloakify/pull/184).
## 6.5.0
- Add support for `login-username.ftl` thanks to [@mstrodl](https://github.com/Mstrodl)'s hacktoberfest [PR](https://github.com/InseeFrLab/keycloakify/pull/183).
## 6.4.0
- You can now optionally pass a `doFetchDefaultThemeResources: boolean` prop to every page component and the default `<KcApp />`
This enables you to prevent the default CSS and JS that comes with the builtin Keycloak theme to be downloaded.
You'll get [a black slate](https://user-images.githubusercontent.com/6702424/192619083-4baa5df4-4a21-4ec7-8e28-d200d1208299.png).
## 6.0.0
- Bundle size drastically reduced, locals and component dynamically loaded.
- First print much quicker, use of React.lazy() everywhere.
- Real i18n API.
- Actual documentation for build options.
Checkout [the migration guide](https://docs.keycloakify.dev/v5-to-v6)
## 5.8.0
- [React.lazy()](https://reactjs.org/docs/code-splitting.html#reactlazy) support 🎉. [#141](https://github.com/InseeFrLab/keycloakify/issues/141)
## 5.7.0
- Feat `logout-confirm.ftl`. [PR](https://github.com/InseeFrLab/keycloakify/pull/120)
## 5.6.4
Fix `login-verify-email.ftl` page. [Before](https://user-images.githubusercontent.com/6702424/177436014-0bad22c4-5bfb-45bb-8fc9-dad65143cd0c.png) - [After](https://user-images.githubusercontent.com/6702424/177435797-ec5d7db3-84cf-49cb-8efc-3427a81f744e.png)
## v5.6.0
Add support for `login-config-totp.ftl` page [#127](https://github.com/InseeFrLab/keycloakify/pull/127).
## v5.3.0
Rename `keycloak_theme_email` to `keycloak_email`.
If you already had a `keycloak_theme_email` you should rename it `keycloak_email`.
## v5.0.0
[Migration guide](https://github.com/garronej/keycloakify-demo-app/blob/a5b6a50f24bc25e082931f5ad9ebf47492acd12a/src/index.tsx#L46-L63)
New i18n system.
Import of terms and services have changed. [See example](https://github.com/garronej/keycloakify-demo-app/blob/a5b6a50f24bc25e082931f5ad9ebf47492acd12a/src/index.tsx#L46-L63).
## v4.10.0
Add `login-idp-link-email.ftl` page [See PR](https://github.com/InseeFrLab/keycloakify/pull/92).
## v4.8.0
[Email template customization.](#email-template-customization)
## v4.7.4
**M1 Mac** support (for testing locally with a dockerized Keycloak).
## v4.7.2
> WARNING: This is broken.
> Testing with local Keycloak container working with M1 Mac. Thanks to [@eduardosanzb](https://github.com/InseeFrLab/keycloakify/issues/43#issuecomment-975699658).
> Be aware: When running M1s you are testing with Keycloak v15 else the local container spun will be a Keycloak v16.1.0.
## v4.7.0
Register with user profile enabled: Out of the box `options` validator support.
[Example](https://user-images.githubusercontent.com/6702424/158911163-81e6bbe8-feb0-4dc8-abff-de199d7a678e.mov)
## v4.6.0
`tss-react` and `powerhooks` are no longer peer dependencies of `keycloakify`.
After updating Keycloakify you can remove `tss-react` and `powerhooks` from your dependencies if you don't use them explicitly.
## v4.5.3
There is a new recommended way to setup highly customized theme. See [here](https://github.com/garronej/keycloakify-demo-app/blob/look_and_feel/src/KcApp/KcApp.tsx).
Unlike with [the previous recommended method](https://github.com/garronej/keycloakify-demo-app/blob/a51660578bea15fb3e506b8a2b78e1056c6d68bb/src/KcApp/KcApp.tsx),
with this new method your theme wont break on minor Keycloakify update.
## v4.3.0
Feature [`login-update-password.ftl`](https://user-images.githubusercontent.com/6702424/147517600-6191cf72-93dd-437b-a35c-47180142063e.png).
Every time a page is added it's a breaking change for non CSS-only theme.
Change [this](https://github.com/garronej/keycloakify-demo-app/blob/df664c13c77ce3c53ac7df0622d94d04e76d3f9f/src/KcApp/KcApp.tsx#L17) and [this](https://github.com/garronej/keycloakify-demo-app/blob/df664c13c77ce3c53ac7df0622d94d04e76d3f9f/src/KcApp/KcApp.tsx#L37) to update.
## v4

61
package.json Executable file → Normal file
View File

@ -1,7 +1,7 @@
{
"name": "keycloakify",
"version": "4.5.2-beta.1",
"description": "Keycloak theme generator for Reacts app",
"version": "6.13.2",
"description": "Create Keycloak themes using React",
"repository": {
"type": "git",
"url": "git://github.com/garronej/keycloakify.git"
@ -9,19 +9,23 @@
"main": "dist/lib/index.js",
"types": "dist/lib/index.d.ts",
"scripts": {
"clean": "rimraf dist/",
"build": "yarn clean && tsc && yarn grant-exec-perms && yarn copy-files",
"build": "rimraf dist/ && tsc -p src/bin && tsc -p src/lib && yarn grant-exec-perms && yarn copy-files dist/",
"build:test": "rimraf dist_test/ && tsc -p src/test && yarn copy-files dist_test/",
"grant-exec-perms": "node dist/bin/tools/grant-exec-perms.js",
"test": "node dist/test/bin/main && node dist/test/lib",
"copy-files": "copyfiles -u 1 src/**/*.ftl src/**/*.xml src/**/*.js dist/",
"generate-messages": "node dist/bin/generate-i18n-messages.js",
"link_in_test_app": "node dist/bin/link_in_test_app.js",
"copy-files": "copyfiles -u 1 src/**/*.ftl",
"pretest": "yarn build:test",
"test": "node dist_test/test/bin && node dist_test/test/lib",
"_format": "prettier '**/*.{ts,tsx,json,md}'",
"format": "yarn _format --write",
"format:check": "yarn _format --list-different"
"format:check": "yarn _format --list-different",
"generate-messages": "ts-node --skipProject src/scripts/generate-i18n-messages.ts",
"link-in-app": "ts-node --skipProject src/scripts/link-in-app.ts",
"link-in-starter": "yarn link-in-app keycloakify-starter",
"tsc-watch": "tsc -p src/bin -w & tsc -p src/lib -w "
},
"bin": {
"build-keycloak-theme": "dist/bin/build-keycloak-theme/index.js",
"keycloakify": "dist/bin/keycloakify/index.js",
"create-keycloak-email-directory": "dist/bin/create-keycloak-email-directory.js",
"download-builtin-keycloak-theme": "dist/bin/download-builtin-keycloak-theme.js"
},
"lint-staged": {
@ -38,9 +42,8 @@
"license": "MIT",
"files": [
"src/",
"!src/test/",
"!src/scripts",
"dist/",
"!dist/test/",
"!dist/tsconfig.tsbuildinfo"
],
"keywords": [
@ -55,33 +58,37 @@
],
"homepage": "https://github.com/garronej/keycloakify",
"peerDependencies": {
"@emotion/react": "^11.4.1",
"powerhooks": "^0.10.0",
"react": "^16.8.0 || ^17.0.0",
"tss-react": "^1.1.0 || ^3.0.0"
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"devDependencies": {
"@emotion/react": "^11.4.1",
"@types/node": "^10.0.0",
"@types/react": "^17.0.0",
"@babel/core": "^7.0.0",
"@types/make-fetch-happen": "^10.0.1",
"@types/minimist": "^1.2.2",
"@types/node": "^18.14.1",
"@types/react": "18.0.9",
"copyfiles": "^2.4.1",
"husky": "^4.3.8",
"lint-staged": "^11.0.0",
"powerhooks": "^0.11.0",
"prettier": "^2.3.0",
"properties-parser": "^0.3.1",
"react": "^17.0.1",
"react": "18.1.0",
"rimraf": "^3.0.2",
"tss-react": "^3.0.0",
"typescript": "^4.2.3"
"scripting-tools": "^0.19.13",
"ts-node": "^10.9.1",
"typescript": "^4.9.5"
},
"dependencies": {
"@octokit/rest": "^18.12.0",
"cheerio": "^1.0.0-rc.5",
"evt": "2.0.0-beta.39",
"minimal-polyfills": "^2.2.1",
"cli-select": "^1.1.2",
"evt": "^2.4.18",
"make-fetch-happen": "^11.0.3",
"minimal-polyfills": "^2.2.2",
"minimist": "^1.2.6",
"path-browserify": "^1.0.1",
"react-markdown": "^5.0.3",
"scripting-tools": "^0.19.13",
"tsafe": "^0.9.0"
"rfc4648": "^1.5.2",
"tsafe": "^1.6.0",
"zod": "^3.17.10"
}
}

27
renovate.json Normal file
View File

@ -0,0 +1,27 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"baseBranches": ["main", "landingpage"],
"extends": ["config:base"],
"dependencyDashboard": false,
"bumpVersion": "patch",
"rangeStrategy": "bump",
"ignorePaths": [".github/**"],
"branchPrefix": "renovate_",
"vulnerabilityAlerts": {
"enabled": false
},
"packageRules": [
{
"packagePatterns": ["*"],
"excludePackagePatterns": ["tsafe", "evt"],
"enabled": false
},
{
"packagePatterns": ["tsafe", "evt"],
"matchUpdateTypes": ["minor", "patch"],
"automerge": true,
"automergeType": "branch",
"groupName": "garronej_modules_update"
}
]
}

View File

@ -1,3 +0,0 @@
export const keycloakVersions = ["11.0.3", "15.0.2"] as const;
export type KeycloakVersion = typeof keycloakVersions[number];

View File

@ -1,146 +0,0 @@
import { generateKeycloakThemeResources } from "./generateKeycloakThemeResources";
import { generateJavaStackFiles } from "./generateJavaStackFiles";
import { join as pathJoin, relative as pathRelative, basename as pathBasename } from "path";
import * as child_process from "child_process";
import { generateDebugFiles, containerLaunchScriptBasename } from "./generateDebugFiles";
import { URL } from "url";
import * as fs from "fs";
type ParsedPackageJson = {
name: string;
version: string;
homepage?: string;
};
const reactProjectDirPath = process.cwd();
const doUseExternalAssets = process.argv[2]?.toLowerCase() === "--external-assets";
const parsedPackageJson: ParsedPackageJson = require(pathJoin(reactProjectDirPath, "package.json"));
export const keycloakThemeBuildingDirPath = pathJoin(reactProjectDirPath, "build_keycloak");
function sanitizeThemeName(name: string) {
return name
.replace(/^@(.*)/, "$1")
.split("/")
.join("-");
}
export function main() {
console.log("🔏 Building the keycloak theme...⌚");
const extraPagesId: string[] = (parsedPackageJson as any)["keycloakify"]?.["extraPages"] ?? [];
const extraThemeProperties: string[] = (parsedPackageJson as any)["keycloakify"]?.["extraThemeProperties"] ?? [];
const themeName = sanitizeThemeName(parsedPackageJson.name);
generateKeycloakThemeResources({
keycloakThemeBuildingDirPath,
"reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"),
themeName,
...(() => {
const url = (() => {
const { homepage } = parsedPackageJson;
if (homepage !== undefined) {
return new URL(homepage);
}
const cnameFilePath = pathJoin(reactProjectDirPath, "public", "CNAME");
if (fs.existsSync(cnameFilePath)) {
return new URL(`https://${fs.readFileSync(cnameFilePath).toString("utf8").replace(/\s+$/, "")}`);
}
return undefined;
})();
return {
"urlPathname": url === undefined ? "/" : url.pathname.replace(/([^/])$/, "$1/"),
"urlOrigin": !doUseExternalAssets
? undefined
: (() => {
if (url === undefined) {
console.error("ERROR: You must specify 'homepage' in your package.json");
process.exit(-1);
}
return url.origin;
})(),
};
})(),
extraPagesId,
extraThemeProperties,
//We have to leave it at that otherwise we break our default theme.
//Problem is that we can't guarantee that the the old resources common
//will still be available on the newer keycloak version.
"keycloakVersion": "11.0.3",
});
const { jarFilePath } = generateJavaStackFiles({
version: parsedPackageJson.version,
themeName,
homepage: parsedPackageJson.homepage,
keycloakThemeBuildingDirPath,
});
child_process.execSync("mvn package", {
"cwd": keycloakThemeBuildingDirPath,
});
generateDebugFiles({
keycloakThemeBuildingDirPath,
themeName,
"keycloakVersion": "15.0.2",
});
console.log(
[
"",
`✅ Your keycloak theme has been generated and bundled into ./${pathRelative(reactProjectDirPath, jarFilePath)} 🚀`,
`It is to be placed in "/opt/jboss/keycloak/standalone/deployments" in the container running a jboss/keycloak Docker image.`,
"",
"Using Helm (https://github.com/codecentric/helm-charts), edit to reflect:",
"",
"value.yaml: ",
" extraInitContainers: |",
" - name: realm-ext-provider",
" image: curlimages/curl",
" imagePullPolicy: IfNotPresent",
" command:",
" - sh",
" args:",
" - -c",
` - curl -L -f -S -o /extensions/${pathBasename(jarFilePath)} https://AN.URL.FOR/${pathBasename(jarFilePath)}`,
" volumeMounts:",
" - name: extensions",
" mountPath: /extensions",
" ",
" extraVolumeMounts: |",
" - name: extensions",
" mountPath: /opt/jboss/keycloak/standalone/deployments",
" extraEnv: |",
" - name: KEYCLOAK_USER",
" value: admin",
" - name: KEYCLOAK_PASSWORD",
" value: xxxxxxxxx",
" - name: JAVA_OPTS",
" value: -Dkeycloak.profile=preview",
"",
"",
"To test your theme locally, with hot reloading, you can spin up a Keycloak container image with the theme loaded by running:",
"",
`👉 $ ./${pathRelative(reactProjectDirPath, pathJoin(keycloakThemeBuildingDirPath, containerLaunchScriptBasename))} 👈`,
"",
"Once your container is up and running: ",
"- Log into the admin console 👉 http://localhost:8080 username: admin, password: admin 👈",
'- Create a realm named "myrealm"',
'- Create a client with id "myclient" and root url: "https://www.keycloak.org/app/"',
`- Select Login Theme: ${themeName} (don't forget to save at the bottom of the page)`,
`- Go to 👉 https://www.keycloak.org/app/ 👈 Click "Save" then "Sign in". You should see your login page`,
"",
"Video demoing this process: https://youtu.be/N3wlBoH4hKg",
"",
].join("\n"),
);
}

View File

@ -1,84 +0,0 @@
import * as fs from "fs";
import { join as pathJoin, dirname as pathDirname } from "path";
export const containerLaunchScriptBasename = "start_keycloak_testing_container.sh";
/** Files for being able to run a hot reload keycloak container */
export function generateDebugFiles(params: { keycloakVersion: "11.0.3" | "15.0.2"; themeName: string; keycloakThemeBuildingDirPath: string }) {
const { themeName, keycloakThemeBuildingDirPath, keycloakVersion } = params;
fs.writeFileSync(
pathJoin(keycloakThemeBuildingDirPath, "Dockerfile"),
Buffer.from(
[
`FROM jboss/keycloak:${keycloakVersion}`,
"",
"USER root",
"",
"WORKDIR /",
"",
"ADD configuration /opt/jboss/keycloak/standalone/configuration/",
"",
'ENTRYPOINT [ "/opt/jboss/tools/docker-entrypoint.sh" ]',
].join("\n"),
"utf8",
),
);
const dockerImage = `${themeName}/keycloak-hot-reload`;
const containerName = "keycloak-testing-container";
fs.writeFileSync(
pathJoin(keycloakThemeBuildingDirPath, containerLaunchScriptBasename),
Buffer.from(
[
"#!/bin/bash",
"",
`cd ${keycloakThemeBuildingDirPath}`,
"",
`docker rm ${containerName} || true`,
"",
`docker build . -t ${dockerImage}`,
"",
"docker run \\",
" -p 8080:8080 \\",
` --name ${containerName} \\`,
" -e KEYCLOAK_USER=admin \\",
" -e KEYCLOAK_PASSWORD=admin \\",
" -e JAVA_OPTS=-Dkeycloak.profile=preview \\",
` -v ${pathJoin(
keycloakThemeBuildingDirPath,
"src",
"main",
"resources",
"theme",
themeName,
)}:/opt/jboss/keycloak/themes/${themeName}:rw \\`,
` -it ${dockerImage}:latest`,
"",
].join("\n"),
"utf8",
),
{ "mode": 0o755 },
);
const standaloneHaFilePath = pathJoin(keycloakThemeBuildingDirPath, "configuration", `standalone-ha.xml`);
try {
fs.mkdirSync(pathDirname(standaloneHaFilePath));
} catch {}
fs.writeFileSync(
standaloneHaFilePath,
fs
.readFileSync(pathJoin(__dirname, `standalone-ha_${keycloakVersion}.xml`))
.toString("utf8")
.replace(
new RegExp(
["<staticMaxAge>2592000</staticMaxAge>", "<cacheThemes>true</cacheThemes>", "<cacheTemplates>true</cacheTemplates>"].join("\\s*"),
"g",
),
["<staticMaxAge>-1</staticMaxAge>", "<cacheThemes>false</cacheThemes>", "<cacheTemplates>false</cacheTemplates>"].join("\n"),
),
);
}

View File

@ -1 +0,0 @@
export * from "./generateDebugFiles";

View File

@ -1,666 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<server xmlns="urn:jboss:domain:13.0">
<extensions>
<extension module="org.jboss.as.clustering.infinispan"/>
<extension module="org.jboss.as.clustering.jgroups"/>
<extension module="org.jboss.as.connector"/>
<extension module="org.jboss.as.deployment-scanner"/>
<extension module="org.jboss.as.ee"/>
<extension module="org.jboss.as.ejb3"/>
<extension module="org.jboss.as.jaxrs"/>
<extension module="org.jboss.as.jmx"/>
<extension module="org.jboss.as.jpa"/>
<extension module="org.jboss.as.logging"/>
<extension module="org.jboss.as.mail"/>
<extension module="org.jboss.as.modcluster"/>
<extension module="org.jboss.as.naming"/>
<extension module="org.jboss.as.remoting"/>
<extension module="org.jboss.as.security"/>
<extension module="org.jboss.as.transactions"/>
<extension module="org.jboss.as.weld"/>
<extension module="org.keycloak.keycloak-server-subsystem"/>
<extension module="org.wildfly.extension.bean-validation"/>
<extension module="org.wildfly.extension.core-management"/>
<extension module="org.wildfly.extension.elytron"/>
<extension module="org.wildfly.extension.io"/>
<extension module="org.wildfly.extension.microprofile.config-smallrye"/>
<extension module="org.wildfly.extension.microprofile.health-smallrye"/>
<extension module="org.wildfly.extension.microprofile.metrics-smallrye"/>
<extension module="org.wildfly.extension.request-controller"/>
<extension module="org.wildfly.extension.security.manager"/>
<extension module="org.wildfly.extension.undertow"/>
</extensions>
<management>
<security-realms>
<security-realm name="ManagementRealm">
<authentication>
<local default-user="$local" skip-group-loading="true"/>
<properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
</authentication>
<authorization map-groups-to-roles="false">
<properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
</authorization>
</security-realm>
<security-realm name="ApplicationRealm">
<server-identities>
<ssl>
<keystore path="application.keystore" relative-to="jboss.server.config.dir" keystore-password="password" alias="server" key-password="password" generate-self-signed-certificate-host="localhost"/>
</ssl>
</server-identities>
<authentication>
<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
<properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
</authentication>
<authorization>
<properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
</authorization>
</security-realm>
</security-realms>
<audit-log>
<formatters>
<json-formatter name="json-formatter"/>
</formatters>
<handlers>
<file-handler name="file" formatter="json-formatter" path="audit-log.log" relative-to="jboss.server.data.dir"/>
</handlers>
<logger log-boot="true" log-read-only="false" enabled="false">
<handlers>
<handler name="file"/>
</handlers>
</logger>
</audit-log>
<management-interfaces>
<http-interface security-realm="ManagementRealm">
<http-upgrade enabled="true"/>
<socket-binding http="management-http"/>
</http-interface>
</management-interfaces>
<access-control provider="simple">
<role-mapping>
<role name="SuperUser">
<include>
<user name="$local"/>
</include>
</role>
</role-mapping>
</access-control>
</management>
<profile>
<subsystem xmlns="urn:jboss:domain:logging:8.0">
<console-handler name="CONSOLE">
<formatter>
<named-formatter name="COLOR-PATTERN"/>
</formatter>
</console-handler>
<logger category="com.arjuna">
<level name="WARN"/>
</logger>
<logger category="io.jaegertracing.Configuration">
<level name="WARN"/>
</logger>
<logger category="org.jboss.as.config">
<level name="DEBUG"/>
</logger>
<logger category="sun.rmi">
<level name="WARN"/>
</logger>
<logger category="org.keycloak">
<level name="${env.KEYCLOAK_LOGLEVEL:INFO}"/>
</logger>
<root-logger>
<level name="${env.ROOT_LOGLEVEL:INFO}"/>
<handlers>
<handler name="CONSOLE"/>
</handlers>
</root-logger>
<formatter name="PATTERN">
<pattern-formatter pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
</formatter>
<formatter name="COLOR-PATTERN">
<pattern-formatter pattern="%K{level}%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
</formatter>
</subsystem>
<subsystem xmlns="urn:jboss:domain:bean-validation:1.0"/>
<subsystem xmlns="urn:jboss:domain:core-management:1.0"/>
<subsystem xmlns="urn:jboss:domain:datasources:6.0">
<datasources>
<datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}">
<connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}">
<connection-url>jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE</connection-url>
<driver>h2</driver>
<pool>
<max-pool-size>100</max-pool-size>
</pool>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<drivers>
<driver name="h2" module="com.h2database.h2">
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
</datasources>
</subsystem>
<subsystem xmlns="urn:jboss:domain:deployment-scanner:2.0">
<deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="5000" runtime-failure-causes-rollback="${jboss.deployment.scanner.rollback.on.failure:false}"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:ee:5.0">
<spec-descriptor-property-replacement>false</spec-descriptor-property-replacement>
<concurrent>
<context-services>
<context-service name="default" jndi-name="java:jboss/ee/concurrency/context/default" use-transaction-setup-provider="true"/>
</context-services>
<managed-thread-factories>
<managed-thread-factory name="default" jndi-name="java:jboss/ee/concurrency/factory/default" context-service="default"/>
</managed-thread-factories>
<managed-executor-services>
<managed-executor-service name="default" jndi-name="java:jboss/ee/concurrency/executor/default" context-service="default" hung-task-threshold="60000" keepalive-time="5000"/>
</managed-executor-services>
<managed-scheduled-executor-services>
<managed-scheduled-executor-service name="default" jndi-name="java:jboss/ee/concurrency/scheduler/default" context-service="default" hung-task-threshold="60000" keepalive-time="3000"/>
</managed-scheduled-executor-services>
</concurrent>
<default-bindings context-service="java:jboss/ee/concurrency/context/default" datasource="java:jboss/datasources/ExampleDS" managed-executor-service="java:jboss/ee/concurrency/executor/default" managed-scheduled-executor-service="java:jboss/ee/concurrency/scheduler/default" managed-thread-factory="java:jboss/ee/concurrency/factory/default"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:ejb3:7.0">
<session-bean>
<stateless>
<bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
</stateless>
<stateful default-access-timeout="5000" cache-ref="distributable" passivation-disabled-cache-ref="simple"/>
<singleton default-access-timeout="5000"/>
</session-bean>
<pools>
<bean-instance-pools>
<strict-max-pool name="mdb-strict-max-pool" derive-size="from-cpu-count" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
<strict-max-pool name="slsb-strict-max-pool" derive-size="from-worker-pools" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
</bean-instance-pools>
</pools>
<caches>
<cache name="simple"/>
<cache name="distributable" passivation-store-ref="infinispan" aliases="passivating clustered"/>
</caches>
<passivation-stores>
<passivation-store name="infinispan" cache-container="ejb" max-size="10000"/>
</passivation-stores>
<async thread-pool-name="default"/>
<timer-service thread-pool-name="default" default-data-store="default-file-store">
<data-stores>
<file-data-store name="default-file-store" path="timer-service-data" relative-to="jboss.server.data.dir"/>
</data-stores>
</timer-service>
<remote connector-ref="http-remoting-connector" thread-pool-name="default">
<channel-creation-options>
<option name="MAX_OUTBOUND_MESSAGES" value="1234" type="remoting"/>
</channel-creation-options>
</remote>
<thread-pools>
<thread-pool name="default">
<max-threads count="10"/>
<keepalive-time time="60" unit="seconds"/>
</thread-pool>
</thread-pools>
<default-security-domain value="other"/>
<default-missing-method-permissions-deny-access value="true"/>
<statistics enabled="${wildfly.ejb3.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
<log-system-exceptions value="true"/>
</subsystem>
<subsystem xmlns="urn:wildfly:elytron:10.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
<providers>
<aggregate-providers name="combined-providers">
<providers name="elytron"/>
<providers name="openssl"/>
</aggregate-providers>
<provider-loader name="elytron" module="org.wildfly.security.elytron"/>
<provider-loader name="openssl" module="org.wildfly.openssl"/>
</providers>
<audit-logging>
<file-audit-log name="local-audit" path="audit.log" relative-to="jboss.server.log.dir" format="JSON"/>
</audit-logging>
<security-domains>
<security-domain name="ApplicationDomain" default-realm="ApplicationRealm" permission-mapper="default-permission-mapper">
<realm name="ApplicationRealm" role-decoder="groups-to-roles"/>
<realm name="local"/>
</security-domain>
<security-domain name="ManagementDomain" default-realm="ManagementRealm" permission-mapper="default-permission-mapper">
<realm name="ManagementRealm" role-decoder="groups-to-roles"/>
<realm name="local" role-mapper="super-user-mapper"/>
</security-domain>
</security-domains>
<security-realms>
<identity-realm name="local" identity="$local"/>
<properties-realm name="ApplicationRealm">
<users-properties path="application-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ApplicationRealm"/>
<groups-properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
</properties-realm>
<properties-realm name="ManagementRealm">
<users-properties path="mgmt-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ManagementRealm"/>
<groups-properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
</properties-realm>
</security-realms>
<mappers>
<simple-permission-mapper name="default-permission-mapper" mapping-mode="first">
<permission-mapping>
<principal name="anonymous"/>
<permission-set name="default-permissions"/>
</permission-mapping>
<permission-mapping match-all="true">
<permission-set name="login-permission"/>
<permission-set name="default-permissions"/>
</permission-mapping>
</simple-permission-mapper>
<constant-realm-mapper name="local" realm-name="local"/>
<simple-role-decoder name="groups-to-roles" attribute="groups"/>
<constant-role-mapper name="super-user-mapper">
<role name="SuperUser"/>
</constant-role-mapper>
</mappers>
<permission-sets>
<permission-set name="login-permission">
<permission class-name="org.wildfly.security.auth.permission.LoginPermission"/>
</permission-set>
<permission-set name="default-permissions">
<permission class-name="org.wildfly.extension.batch.jberet.deployment.BatchPermission" module="org.wildfly.extension.batch.jberet" target-name="*"/>
<permission class-name="org.wildfly.transaction.client.RemoteTransactionPermission" module="org.wildfly.transaction.client"/>
<permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/>
</permission-set>
</permission-sets>
<http>
<http-authentication-factory name="management-http-authentication" security-domain="ManagementDomain" http-server-mechanism-factory="global">
<mechanism-configuration>
<mechanism mechanism-name="DIGEST">
<mechanism-realm realm-name="ManagementRealm"/>
</mechanism>
</mechanism-configuration>
</http-authentication-factory>
<provider-http-server-mechanism-factory name="global"/>
</http>
<sasl>
<sasl-authentication-factory name="application-sasl-authentication" sasl-server-factory="configured" security-domain="ApplicationDomain">
<mechanism-configuration>
<mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
<mechanism mechanism-name="DIGEST-MD5">
<mechanism-realm realm-name="ApplicationRealm"/>
</mechanism>
</mechanism-configuration>
</sasl-authentication-factory>
<sasl-authentication-factory name="management-sasl-authentication" sasl-server-factory="configured" security-domain="ManagementDomain">
<mechanism-configuration>
<mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
<mechanism mechanism-name="DIGEST-MD5">
<mechanism-realm realm-name="ManagementRealm"/>
</mechanism>
</mechanism-configuration>
</sasl-authentication-factory>
<configurable-sasl-server-factory name="configured" sasl-server-factory="elytron">
<properties>
<property name="wildfly.sasl.local-user.default-user" value="$local"/>
</properties>
</configurable-sasl-server-factory>
<mechanism-provider-filtering-sasl-server-factory name="elytron" sasl-server-factory="global">
<filters>
<filter provider-name="WildFlyElytron"/>
</filters>
</mechanism-provider-filtering-sasl-server-factory>
<provider-sasl-server-factory name="global"/>
</sasl>
</subsystem>
<subsystem xmlns="urn:jboss:domain:infinispan:10.0">
<cache-container name="keycloak" module="org.keycloak.keycloak-model-infinispan">
<transport lock-timeout="60000"/>
<local-cache name="realms">
<object-memory size="10000"/>
</local-cache>
<local-cache name="users">
<object-memory size="10000"/>
</local-cache>
<local-cache name="authorization">
<object-memory size="10000"/>
</local-cache>
<local-cache name="keys">
<object-memory size="1000"/>
<expiration max-idle="3600000"/>
</local-cache>
<replicated-cache name="work"/>
<distributed-cache name="sessions" owners="1"/>
<distributed-cache name="authenticationSessions" owners="1"/>
<distributed-cache name="offlineSessions" owners="1"/>
<distributed-cache name="clientSessions" owners="1"/>
<distributed-cache name="offlineClientSessions" owners="1"/>
<distributed-cache name="loginFailures" owners="1"/>
<distributed-cache name="actionTokens" owners="2">
<object-memory size="-1"/>
<expiration interval="300000" max-idle="-1"/>
</distributed-cache>
</cache-container>
<cache-container name="server" aliases="singleton cluster" default-cache="default" module="org.wildfly.clustering.server">
<transport lock-timeout="60000"/>
<replicated-cache name="default">
<transaction mode="BATCH"/>
</replicated-cache>
</cache-container>
<cache-container name="web" default-cache="dist" module="org.wildfly.clustering.web.infinispan">
<transport lock-timeout="60000"/>
<replicated-cache name="sso">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
</replicated-cache>
<distributed-cache name="dist">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
<file-store/>
</distributed-cache>
<distributed-cache name="routing"/>
</cache-container>
<cache-container name="ejb" aliases="sfsb" default-cache="dist" module="org.wildfly.clustering.ejb.infinispan">
<transport lock-timeout="60000"/>
<distributed-cache name="dist">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
<file-store/>
</distributed-cache>
</cache-container>
<cache-container name="hibernate" module="org.infinispan.hibernate-cache">
<transport lock-timeout="60000"/>
<local-cache name="local-query">
<object-memory size="10000"/>
<expiration max-idle="100000"/>
</local-cache>
<invalidation-cache name="entity">
<transaction mode="NON_XA"/>
<object-memory size="10000"/>
<expiration max-idle="100000"/>
</invalidation-cache>
<replicated-cache name="timestamps"/>
</cache-container>
</subsystem>
<subsystem xmlns="urn:jboss:domain:io:3.0">
<worker name="default"/>
<buffer-pool name="default"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jaxrs:2.0"/>
<subsystem xmlns="urn:jboss:domain:jca:5.0">
<archive-validation enabled="true" fail-on-error="true" fail-on-warn="false"/>
<bean-validation enabled="true"/>
<default-workmanager>
<short-running-threads>
<core-threads count="50"/>
<queue-length count="50"/>
<max-threads count="50"/>
<keepalive-time time="10" unit="seconds"/>
</short-running-threads>
<long-running-threads>
<core-threads count="50"/>
<queue-length count="50"/>
<max-threads count="50"/>
<keepalive-time time="10" unit="seconds"/>
</long-running-threads>
</default-workmanager>
<cached-connection-manager/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jgroups:8.0">
<channels default="ee">
<channel name="ee" stack="udp" cluster="ejb"/>
</channels>
<stacks>
<stack name="udp">
<transport type="UDP" socket-binding="jgroups-udp"/>
<protocol type="PING"/>
<protocol type="MERGE3"/>
<socket-protocol type="FD_SOCK" socket-binding="jgroups-udp-fd"/>
<protocol type="FD_ALL"/>
<protocol type="VERIFY_SUSPECT"/>
<protocol type="pbcast.NAKACK2"/>
<protocol type="UNICAST3"/>
<protocol type="pbcast.STABLE"/>
<protocol type="pbcast.GMS"/>
<protocol type="UFC"/>
<protocol type="MFC"/>
<protocol type="FRAG3"/>
</stack>
<stack name="tcp">
<transport type="TCP" socket-binding="jgroups-tcp"/>
<socket-protocol type="MPING" socket-binding="jgroups-mping"/>
<protocol type="MERGE3"/>
<socket-protocol type="FD_SOCK" socket-binding="jgroups-tcp-fd"/>
<protocol type="FD_ALL"/>
<protocol type="VERIFY_SUSPECT"/>
<protocol type="pbcast.NAKACK2"/>
<protocol type="UNICAST3"/>
<protocol type="pbcast.STABLE"/>
<protocol type="pbcast.GMS"/>
<protocol type="MFC"/>
<protocol type="FRAG3"/>
</stack>
</stacks>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jmx:1.3">
<expose-resolved-model/>
<expose-expression-model/>
<remoting-connector/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jpa:1.1">
<jpa default-datasource="" default-extended-persistence-inheritance="DEEP"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
<web-context>auth</web-context>
<providers>
<provider>
classpath:${jboss.home.dir}/providers/*
</provider>
</providers>
<master-realm-name>master</master-realm-name>
<scheduled-task-interval>900</scheduled-task-interval>
<theme>
<staticMaxAge>2592000</staticMaxAge>
<cacheThemes>true</cacheThemes>
<cacheTemplates>true</cacheTemplates>
<welcomeTheme>${env.KEYCLOAK_WELCOME_THEME:keycloak}</welcomeTheme>
<default>${env.KEYCLOAK_DEFAULT_THEME:keycloak}</default>
<dir>${jboss.home.dir}/themes</dir>
</theme>
<spi name="eventsStore">
<provider name="jpa" enabled="true">
<properties>
<property name="exclude-events" value="[&quot;REFRESH_TOKEN&quot;]"/>
</properties>
</provider>
</spi>
<spi name="userCache">
<provider name="default" enabled="true"/>
</spi>
<spi name="userSessionPersister">
<default-provider>jpa</default-provider>
</spi>
<spi name="timer">
<default-provider>basic</default-provider>
</spi>
<spi name="connectionsHttpClient">
<provider name="default" enabled="true"/>
</spi>
<spi name="connectionsJpa">
<provider name="default" enabled="true">
<properties>
<property name="dataSource" value="java:jboss/datasources/KeycloakDS"/>
<property name="initializeEmpty" value="true"/>
<property name="migrationStrategy" value="update"/>
<property name="migrationExport" value="${jboss.home.dir}/keycloak-database-update.sql"/>
</properties>
</provider>
</spi>
<spi name="realmCache">
<provider name="default" enabled="true"/>
</spi>
<spi name="connectionsInfinispan">
<default-provider>default</default-provider>
<provider name="default" enabled="true">
<properties>
<property name="cacheContainer" value="java:jboss/infinispan/container/keycloak"/>
</properties>
</provider>
</spi>
<spi name="jta-lookup">
<default-provider>${keycloak.jta.lookup.provider:jboss}</default-provider>
<provider name="jboss" enabled="true"/>
</spi>
<spi name="publicKeyStorage">
<provider name="infinispan" enabled="true">
<properties>
<property name="minTimeBetweenRequests" value="10"/>
</properties>
</provider>
</spi>
<spi name="x509cert-lookup">
<default-provider>${keycloak.x509cert.lookup.provider:default}</default-provider>
<provider name="default" enabled="true"/>
</spi>
<spi name="hostname">
<default-provider>${keycloak.hostname.provider:default}</default-provider>
<provider name="default" enabled="true">
<properties>
<property name="frontendUrl" value="${keycloak.frontendUrl:}"/>
<property name="forceBackendUrlToFrontendUrl" value="false"/>
</properties>
</provider>
<provider name="fixed" enabled="true">
<properties>
<property name="hostname" value="${keycloak.hostname.fixed.hostname:localhost}"/>
<property name="httpPort" value="${keycloak.hostname.fixed.httpPort:-1}"/>
<property name="httpsPort" value="${keycloak.hostname.fixed.httpsPort:-1}"/>
<property name="alwaysHttps" value="${keycloak.hostname.fixed.alwaysHttps:false}"/>
</properties>
</provider>
</spi>
</subsystem>
<subsystem xmlns="urn:jboss:domain:mail:4.0">
<mail-session name="default" jndi-name="java:jboss/mail/Default">
<smtp-server outbound-socket-binding-ref="mail-smtp"/>
</mail-session>
</subsystem>
<subsystem xmlns="urn:wildfly:microprofile-config-smallrye:1.0"/>
<subsystem xmlns="urn:wildfly:microprofile-health-smallrye:2.0" security-enabled="false" empty-liveness-checks-status="${env.MP_HEALTH_EMPTY_LIVENESS_CHECKS_STATUS:UP}" empty-readiness-checks-status="${env.MP_HEALTH_EMPTY_READINESS_CHECKS_STATUS:UP}"/>
<subsystem xmlns="urn:wildfly:microprofile-metrics-smallrye:2.0" security-enabled="false" exposed-subsystems="*" prefix="${wildfly.metrics.prefix:wildfly}"/>
<subsystem xmlns="urn:jboss:domain:modcluster:5.0">
<proxy name="default" advertise-socket="modcluster" listener="ajp">
<dynamic-load-provider>
<load-metric type="cpu"/>
</dynamic-load-provider>
</proxy>
</subsystem>
<subsystem xmlns="urn:jboss:domain:naming:2.0">
<remote-naming/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:remoting:4.0">
<http-connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:request-controller:1.0"/>
<subsystem xmlns="urn:jboss:domain:security:2.0">
<security-domains>
<security-domain name="other" cache-type="default">
<authentication>
<login-module code="Remoting" flag="optional">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
<login-module code="RealmDirect" flag="required">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
</authentication>
</security-domain>
<security-domain name="jboss-web-policy" cache-type="default">
<authorization>
<policy-module code="Delegating" flag="required"/>
</authorization>
</security-domain>
<security-domain name="jaspitest" cache-type="default">
<authentication-jaspi>
<login-module-stack name="dummy">
<login-module code="Dummy" flag="optional"/>
</login-module-stack>
<auth-module code="Dummy"/>
</authentication-jaspi>
</security-domain>
<security-domain name="jboss-ejb-policy" cache-type="default">
<authorization>
<policy-module code="Delegating" flag="required"/>
</authorization>
</security-domain>
</security-domains>
</subsystem>
<subsystem xmlns="urn:jboss:domain:security-manager:1.0">
<deployment-permissions>
<maximum-set>
<permission class="java.security.AllPermission"/>
</maximum-set>
</deployment-permissions>
</subsystem>
<subsystem xmlns="urn:jboss:domain:transactions:5.0">
<core-environment node-identifier="${jboss.tx.node.id:1}">
<process-id>
<uuid/>
</process-id>
</core-environment>
<recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
<coordinator-environment statistics-enabled="${wildfly.transactions.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
<object-store path="tx-object-store" relative-to="jboss.server.data.dir"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:undertow:11.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
<buffer-cache name="default"/>
<server name="default-server">
<ajp-listener name="ajp" socket-binding="ajp"/>
<http-listener name="default" read-timeout="30000" socket-binding="http" redirect-socket="https" proxy-address-forwarding="${env.PROXY_ADDRESS_FORWARDING:false}" enable-http2="true"/>
<https-listener name="https" read-timeout="30000" socket-binding="https" proxy-address-forwarding="${env.PROXY_ADDRESS_FORWARDING:false}" security-realm="ApplicationRealm" enable-http2="true"/>
<host name="default-host" alias="localhost">
<location name="/" handler="welcome-content"/>
<http-invoker security-realm="ApplicationRealm"/>
</host>
</server>
<servlet-container name="default">
<jsp-config/>
<websockets/>
</servlet-container>
<handlers>
<file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
</handlers>
</subsystem>
<subsystem xmlns="urn:jboss:domain:weld:4.0"/>
</profile>
<interfaces>
<interface name="management">
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
</interface>
<interface name="private">
<inet-address value="${jboss.bind.address.private:127.0.0.1}"/>
</interface>
<interface name="public">
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
</interface>
</interfaces>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
<socket-binding name="http" port="${jboss.http.port:8080}"/>
<socket-binding name="https" port="${jboss.https.port:8443}"/>
<socket-binding name="jgroups-mping" interface="private" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45700"/>
<socket-binding name="jgroups-tcp" interface="private" port="7600"/>
<socket-binding name="jgroups-tcp-fd" interface="private" port="57600"/>
<socket-binding name="jgroups-udp" interface="private" port="55200" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45688"/>
<socket-binding name="jgroups-udp-fd" interface="private" port="54200"/>
<socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
<socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
<socket-binding name="modcluster" multicast-address="${jboss.modcluster.multicast.address:224.0.1.105}" multicast-port="23364"/>
<socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/>
<outbound-socket-binding name="mail-smtp">
<remote-destination host="localhost" port="25"/>
</outbound-socket-binding>
</socket-binding-group>
</server>

View File

@ -1,693 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<server xmlns="urn:jboss:domain:16.0">
<extensions>
<extension module="org.jboss.as.clustering.infinispan"/>
<extension module="org.jboss.as.clustering.jgroups"/>
<extension module="org.jboss.as.connector"/>
<extension module="org.jboss.as.deployment-scanner"/>
<extension module="org.jboss.as.ee"/>
<extension module="org.jboss.as.ejb3"/>
<extension module="org.jboss.as.jaxrs"/>
<extension module="org.jboss.as.jmx"/>
<extension module="org.jboss.as.jpa"/>
<extension module="org.jboss.as.logging"/>
<extension module="org.jboss.as.mail"/>
<extension module="org.jboss.as.modcluster"/>
<extension module="org.jboss.as.naming"/>
<extension module="org.jboss.as.remoting"/>
<extension module="org.jboss.as.security"/>
<extension module="org.jboss.as.transactions"/>
<extension module="org.jboss.as.weld"/>
<extension module="org.keycloak.keycloak-server-subsystem"/>
<extension module="org.wildfly.extension.bean-validation"/>
<extension module="org.wildfly.extension.core-management"/>
<extension module="org.wildfly.extension.elytron"/>
<extension module="org.wildfly.extension.health"/>
<extension module="org.wildfly.extension.io"/>
<extension module="org.wildfly.extension.metrics"/>
<extension module="org.wildfly.extension.request-controller"/>
<extension module="org.wildfly.extension.security.manager"/>
<extension module="org.wildfly.extension.undertow"/>
</extensions>
<management>
<security-realms>
<security-realm name="ManagementRealm">
<authentication>
<local default-user="$local" skip-group-loading="true"/>
<properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
</authentication>
<authorization map-groups-to-roles="false">
<properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
</authorization>
</security-realm>
<security-realm name="ApplicationRealm">
<server-identities>
<ssl>
<keystore path="application.keystore" relative-to="jboss.server.config.dir" keystore-password="password" alias="server" key-password="password" generate-self-signed-certificate-host="localhost"/>
</ssl>
</server-identities>
<authentication>
<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
<properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
</authentication>
<authorization>
<properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
</authorization>
</security-realm>
</security-realms>
<audit-log>
<formatters>
<json-formatter name="json-formatter"/>
</formatters>
<handlers>
<file-handler name="file" formatter="json-formatter" path="audit-log.log" relative-to="jboss.server.data.dir"/>
</handlers>
<logger log-boot="true" log-read-only="false" enabled="false">
<handlers>
<handler name="file"/>
</handlers>
</logger>
</audit-log>
<management-interfaces>
<http-interface security-realm="ManagementRealm">
<http-upgrade enabled="true"/>
<socket-binding http="management-http"/>
</http-interface>
</management-interfaces>
<access-control provider="simple">
<role-mapping>
<role name="SuperUser">
<include>
<user name="$local"/>
</include>
</role>
</role-mapping>
</access-control>
</management>
<profile>
<subsystem xmlns="urn:jboss:domain:logging:8.0">
<console-handler name="CONSOLE">
<formatter>
<named-formatter name="COLOR-PATTERN"/>
</formatter>
</console-handler>
<logger category="com.arjuna">
<level name="WARN"/>
</logger>
<logger category="io.jaegertracing.Configuration">
<level name="WARN"/>
</logger>
<logger category="org.jboss.as.config">
<level name="DEBUG"/>
</logger>
<logger category="sun.rmi">
<level name="WARN"/>
</logger>
<logger category="org.keycloak">
<level name="${env.KEYCLOAK_LOGLEVEL:INFO}"/>
</logger>
<root-logger>
<level name="${env.ROOT_LOGLEVEL:INFO}"/>
<handlers>
<handler name="CONSOLE"/>
</handlers>
</root-logger>
<formatter name="PATTERN">
<pattern-formatter pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
</formatter>
<formatter name="COLOR-PATTERN">
<pattern-formatter pattern="%K{level}%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
</formatter>
</subsystem>
<subsystem xmlns="urn:jboss:domain:bean-validation:1.0"/>
<subsystem xmlns="urn:jboss:domain:core-management:1.0"/>
<subsystem xmlns="urn:jboss:domain:datasources:6.0">
<datasources>
<datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}">
<connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}">
<connection-url>jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<drivers>
<driver name="h2" module="com.h2database.h2">
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
</datasources>
</subsystem>
<subsystem xmlns="urn:jboss:domain:deployment-scanner:2.0">
<deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="5000" runtime-failure-causes-rollback="${jboss.deployment.scanner.rollback.on.failure:false}"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:ee:6.0">
<spec-descriptor-property-replacement>false</spec-descriptor-property-replacement>
<concurrent>
<context-services>
<context-service name="default" jndi-name="java:jboss/ee/concurrency/context/default" use-transaction-setup-provider="true"/>
</context-services>
<managed-thread-factories>
<managed-thread-factory name="default" jndi-name="java:jboss/ee/concurrency/factory/default" context-service="default"/>
</managed-thread-factories>
<managed-executor-services>
<managed-executor-service name="default" jndi-name="java:jboss/ee/concurrency/executor/default" context-service="default" hung-task-termination-period="0" hung-task-threshold="60000" keepalive-time="5000"/>
</managed-executor-services>
<managed-scheduled-executor-services>
<managed-scheduled-executor-service name="default" jndi-name="java:jboss/ee/concurrency/scheduler/default" context-service="default" hung-task-termination-period="0" hung-task-threshold="60000" keepalive-time="3000"/>
</managed-scheduled-executor-services>
</concurrent>
<default-bindings context-service="java:jboss/ee/concurrency/context/default" datasource="java:jboss/datasources/ExampleDS" managed-executor-service="java:jboss/ee/concurrency/executor/default" managed-scheduled-executor-service="java:jboss/ee/concurrency/scheduler/default" managed-thread-factory="java:jboss/ee/concurrency/factory/default"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:ejb3:9.0">
<session-bean>
<stateless>
<bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
</stateless>
<stateful default-access-timeout="5000" cache-ref="distributable" passivation-disabled-cache-ref="simple"/>
<singleton default-access-timeout="5000"/>
</session-bean>
<pools>
<bean-instance-pools>
<strict-max-pool name="mdb-strict-max-pool" derive-size="from-cpu-count" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
<strict-max-pool name="slsb-strict-max-pool" derive-size="from-worker-pools" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
</bean-instance-pools>
</pools>
<caches>
<cache name="simple"/>
<cache name="distributable" passivation-store-ref="infinispan" aliases="passivating clustered"/>
</caches>
<passivation-stores>
<passivation-store name="infinispan" cache-container="ejb" max-size="10000"/>
</passivation-stores>
<async thread-pool-name="default"/>
<timer-service thread-pool-name="default" default-data-store="default-file-store">
<data-stores>
<file-data-store name="default-file-store" path="timer-service-data" relative-to="jboss.server.data.dir"/>
</data-stores>
</timer-service>
<remote cluster="ejb" connectors="http-remoting-connector" thread-pool-name="default">
<channel-creation-options>
<option name="MAX_OUTBOUND_MESSAGES" value="1234" type="remoting"/>
</channel-creation-options>
</remote>
<thread-pools>
<thread-pool name="default">
<max-threads count="10"/>
<keepalive-time time="60" unit="seconds"/>
</thread-pool>
</thread-pools>
<default-security-domain value="other"/>
<default-missing-method-permissions-deny-access value="true"/>
<statistics enabled="${wildfly.ejb3.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
<log-system-exceptions value="true"/>
</subsystem>
<subsystem xmlns="urn:wildfly:elytron:13.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
<providers>
<aggregate-providers name="combined-providers">
<providers name="elytron"/>
<providers name="openssl"/>
</aggregate-providers>
<provider-loader name="elytron" module="org.wildfly.security.elytron"/>
<provider-loader name="openssl" module="org.wildfly.openssl"/>
</providers>
<audit-logging>
<file-audit-log name="local-audit" path="audit.log" relative-to="jboss.server.log.dir" format="JSON"/>
</audit-logging>
<security-domains>
<security-domain name="ApplicationDomain" default-realm="ApplicationRealm" permission-mapper="default-permission-mapper">
<realm name="ApplicationRealm" role-decoder="groups-to-roles"/>
<realm name="local"/>
</security-domain>
<security-domain name="ManagementDomain" default-realm="ManagementRealm" permission-mapper="default-permission-mapper">
<realm name="ManagementRealm" role-decoder="groups-to-roles"/>
<realm name="local" role-mapper="super-user-mapper"/>
</security-domain>
</security-domains>
<security-realms>
<identity-realm name="local" identity="$local"/>
<properties-realm name="ApplicationRealm">
<users-properties path="application-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ApplicationRealm"/>
<groups-properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
</properties-realm>
<properties-realm name="ManagementRealm">
<users-properties path="mgmt-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ManagementRealm"/>
<groups-properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
</properties-realm>
</security-realms>
<mappers>
<simple-permission-mapper name="default-permission-mapper" mapping-mode="first">
<permission-mapping>
<principal name="anonymous"/>
<permission-set name="default-permissions"/>
</permission-mapping>
<permission-mapping match-all="true">
<permission-set name="login-permission"/>
<permission-set name="default-permissions"/>
</permission-mapping>
</simple-permission-mapper>
<constant-realm-mapper name="local" realm-name="local"/>
<simple-role-decoder name="groups-to-roles" attribute="groups"/>
<constant-role-mapper name="super-user-mapper">
<role name="SuperUser"/>
</constant-role-mapper>
</mappers>
<permission-sets>
<permission-set name="login-permission">
<permission class-name="org.wildfly.security.auth.permission.LoginPermission"/>
</permission-set>
<permission-set name="default-permissions">
<permission class-name="org.wildfly.extension.batch.jberet.deployment.BatchPermission" module="org.wildfly.extension.batch.jberet" target-name="*"/>
<permission class-name="org.wildfly.transaction.client.RemoteTransactionPermission" module="org.wildfly.transaction.client"/>
<permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/>
<permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/>
</permission-set>
</permission-sets>
<http>
<http-authentication-factory name="management-http-authentication" security-domain="ManagementDomain" http-server-mechanism-factory="global">
<mechanism-configuration>
<mechanism mechanism-name="DIGEST">
<mechanism-realm realm-name="ManagementRealm"/>
</mechanism>
</mechanism-configuration>
</http-authentication-factory>
<provider-http-server-mechanism-factory name="global"/>
</http>
<sasl>
<sasl-authentication-factory name="application-sasl-authentication" sasl-server-factory="configured" security-domain="ApplicationDomain">
<mechanism-configuration>
<mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
<mechanism mechanism-name="DIGEST-MD5">
<mechanism-realm realm-name="ApplicationRealm"/>
</mechanism>
</mechanism-configuration>
</sasl-authentication-factory>
<sasl-authentication-factory name="management-sasl-authentication" sasl-server-factory="configured" security-domain="ManagementDomain">
<mechanism-configuration>
<mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
<mechanism mechanism-name="DIGEST-MD5">
<mechanism-realm realm-name="ManagementRealm"/>
</mechanism>
</mechanism-configuration>
</sasl-authentication-factory>
<configurable-sasl-server-factory name="configured" sasl-server-factory="elytron">
<properties>
<property name="wildfly.sasl.local-user.default-user" value="$local"/>
</properties>
</configurable-sasl-server-factory>
<mechanism-provider-filtering-sasl-server-factory name="elytron" sasl-server-factory="global">
<filters>
<filter provider-name="WildFlyElytron"/>
</filters>
</mechanism-provider-filtering-sasl-server-factory>
<provider-sasl-server-factory name="global"/>
</sasl>
<tls>
<key-stores>
<key-store name="applicationKS">
<credential-reference clear-text="password"/>
<implementation type="JKS"/>
<file path="application.keystore" relative-to="jboss.server.config.dir"/>
</key-store>
</key-stores>
<key-managers>
<key-manager name="applicationKM" key-store="applicationKS" generate-self-signed-certificate-host="localhost">
<credential-reference clear-text="password"/>
</key-manager>
</key-managers>
<server-ssl-contexts>
<server-ssl-context name="applicationSSC" key-manager="applicationKM"/>
</server-ssl-contexts>
</tls>
</subsystem>
<subsystem xmlns="urn:wildfly:health:1.0" security-enabled="false"/>
<subsystem xmlns="urn:jboss:domain:infinispan:12.0">
<cache-container name="ejb" default-cache="dist" aliases="sfsb" modules="org.wildfly.clustering.ejb.infinispan">
<transport lock-timeout="60000"/>
<distributed-cache name="dist">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
<file-store/>
</distributed-cache>
</cache-container>
<cache-container name="keycloak" modules="org.keycloak.keycloak-model-infinispan">
<transport lock-timeout="60000"/>
<local-cache name="realms">
<heap-memory size="10000"/>
</local-cache>
<local-cache name="users">
<heap-memory size="10000"/>
</local-cache>
<local-cache name="authorization">
<heap-memory size="10000"/>
</local-cache>
<local-cache name="keys">
<heap-memory size="1000"/>
<expiration max-idle="3600000"/>
</local-cache>
<replicated-cache name="work">
<expiration lifespan="900000000000000000"/>
</replicated-cache>
<distributed-cache name="sessions" owners="1">
<expiration lifespan="900000000000000000"/>
</distributed-cache>
<distributed-cache name="authenticationSessions" owners="1">
<expiration lifespan="900000000000000000"/>
</distributed-cache>
<distributed-cache name="offlineSessions" owners="1">
<expiration lifespan="900000000000000000"/>
</distributed-cache>
<distributed-cache name="clientSessions" owners="1">
<expiration lifespan="900000000000000000"/>
</distributed-cache>
<distributed-cache name="offlineClientSessions" owners="1">
<expiration lifespan="900000000000000000"/>
</distributed-cache>
<distributed-cache name="loginFailures" owners="1">
<expiration lifespan="900000000000000000"/>
</distributed-cache>
<distributed-cache name="actionTokens" owners="2">
<heap-memory size="-1"/>
<expiration interval="300000" lifespan="900000000000000000" max-idle="-1"/>
</distributed-cache>
</cache-container>
<cache-container name="server" default-cache="default" aliases="singleton cluster" modules="org.wildfly.clustering.server">
<transport lock-timeout="60000"/>
<replicated-cache name="default">
<transaction mode="BATCH"/>
</replicated-cache>
</cache-container>
<cache-container name="web" default-cache="dist" modules="org.wildfly.clustering.web.infinispan">
<transport lock-timeout="60000"/>
<replicated-cache name="sso">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
</replicated-cache>
<distributed-cache name="dist">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
<file-store/>
</distributed-cache>
<distributed-cache name="routing"/>
</cache-container>
<cache-container name="hibernate" modules="org.infinispan.hibernate-cache">
<transport lock-timeout="60000"/>
<local-cache name="local-query">
<heap-memory size="10000"/>
<expiration max-idle="100000"/>
</local-cache>
<invalidation-cache name="entity">
<transaction mode="NON_XA"/>
<heap-memory size="10000"/>
<expiration max-idle="100000"/>
</invalidation-cache>
<replicated-cache name="timestamps"/>
</cache-container>
</subsystem>
<subsystem xmlns="urn:jboss:domain:io:3.0">
<worker name="default"/>
<buffer-pool name="default"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jaxrs:2.0"/>
<subsystem xmlns="urn:jboss:domain:jca:5.0">
<archive-validation enabled="true" fail-on-error="true" fail-on-warn="false"/>
<bean-validation enabled="true"/>
<default-workmanager>
<short-running-threads>
<core-threads count="50"/>
<queue-length count="50"/>
<max-threads count="50"/>
<keepalive-time time="10" unit="seconds"/>
</short-running-threads>
<long-running-threads>
<core-threads count="50"/>
<queue-length count="50"/>
<max-threads count="50"/>
<keepalive-time time="10" unit="seconds"/>
</long-running-threads>
</default-workmanager>
<cached-connection-manager/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jgroups:8.0">
<channels default="ee">
<channel name="ee" stack="udp" cluster="ejb"/>
</channels>
<stacks>
<stack name="udp">
<transport type="UDP" socket-binding="jgroups-udp"/>
<protocol type="PING"/>
<protocol type="MERGE3"/>
<socket-protocol type="FD_SOCK" socket-binding="jgroups-udp-fd"/>
<protocol type="FD_ALL"/>
<protocol type="VERIFY_SUSPECT"/>
<protocol type="pbcast.NAKACK2"/>
<protocol type="UNICAST3"/>
<protocol type="pbcast.STABLE"/>
<protocol type="pbcast.GMS"/>
<protocol type="UFC"/>
<protocol type="MFC"/>
<protocol type="FRAG3"/>
</stack>
<stack name="tcp">
<transport type="TCP" socket-binding="jgroups-tcp"/>
<socket-protocol type="MPING" socket-binding="jgroups-mping"/>
<protocol type="MERGE3"/>
<socket-protocol type="FD_SOCK" socket-binding="jgroups-tcp-fd"/>
<protocol type="FD_ALL"/>
<protocol type="VERIFY_SUSPECT"/>
<protocol type="pbcast.NAKACK2"/>
<protocol type="UNICAST3"/>
<protocol type="pbcast.STABLE"/>
<protocol type="pbcast.GMS"/>
<protocol type="MFC"/>
<protocol type="FRAG3"/>
</stack>
</stacks>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jmx:1.3">
<expose-resolved-model/>
<expose-expression-model/>
<remoting-connector/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jpa:1.1">
<jpa default-extended-persistence-inheritance="DEEP"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
<web-context>auth</web-context>
<providers>
<provider>
classpath:${jboss.home.dir}/providers/*
</provider>
</providers>
<master-realm-name>master</master-realm-name>
<scheduled-task-interval>900</scheduled-task-interval>
<theme>
<staticMaxAge>2592000</staticMaxAge>
<cacheThemes>true</cacheThemes>
<cacheTemplates>true</cacheTemplates>
<welcomeTheme>${env.KEYCLOAK_WELCOME_THEME:keycloak}</welcomeTheme>
<default>${env.KEYCLOAK_DEFAULT_THEME:keycloak}</default>
<dir>${jboss.home.dir}/themes</dir>
</theme>
<spi name="eventsStore">
<provider name="jpa" enabled="true">
<properties>
<property name="exclude-events" value="[&quot;REFRESH_TOKEN&quot;]"/>
</properties>
</provider>
</spi>
<spi name="userCache">
<provider name="default" enabled="true"/>
</spi>
<spi name="userSessionPersister">
<default-provider>jpa</default-provider>
</spi>
<spi name="timer">
<default-provider>basic</default-provider>
</spi>
<spi name="connectionsHttpClient">
<provider name="default" enabled="true"/>
</spi>
<spi name="connectionsJpa">
<provider name="default" enabled="true">
<properties>
<property name="dataSource" value="java:jboss/datasources/KeycloakDS"/>
<property name="initializeEmpty" value="true"/>
<property name="migrationStrategy" value="update"/>
<property name="migrationExport" value="${jboss.home.dir}/keycloak-database-update.sql"/>
</properties>
</provider>
</spi>
<spi name="realmCache">
<provider name="default" enabled="true"/>
</spi>
<spi name="connectionsInfinispan">
<default-provider>default</default-provider>
<provider name="default" enabled="true">
<properties>
<property name="cacheContainer" value="java:jboss/infinispan/container/keycloak"/>
</properties>
</provider>
</spi>
<spi name="jta-lookup">
<default-provider>${keycloak.jta.lookup.provider:jboss}</default-provider>
<provider name="jboss" enabled="true"/>
</spi>
<spi name="publicKeyStorage">
<provider name="infinispan" enabled="true">
<properties>
<property name="minTimeBetweenRequests" value="10"/>
</properties>
</provider>
</spi>
<spi name="x509cert-lookup">
<default-provider>${keycloak.x509cert.lookup.provider:default}</default-provider>
<provider name="default" enabled="true"/>
</spi>
<spi name="hostname">
<default-provider>${keycloak.hostname.provider:default}</default-provider>
<provider name="default" enabled="true">
<properties>
<property name="frontendUrl" value="${keycloak.frontendUrl:}"/>
<property name="forceBackendUrlToFrontendUrl" value="false"/>
</properties>
</provider>
<provider name="fixed" enabled="true">
<properties>
<property name="hostname" value="${keycloak.hostname.fixed.hostname:localhost}"/>
<property name="httpPort" value="${keycloak.hostname.fixed.httpPort:-1}"/>
<property name="httpsPort" value="${keycloak.hostname.fixed.httpsPort:-1}"/>
<property name="alwaysHttps" value="${keycloak.hostname.fixed.alwaysHttps:false}"/>
</properties>
</provider>
</spi>
</subsystem>
<subsystem xmlns="urn:jboss:domain:mail:4.0">
<mail-session name="default" jndi-name="java:jboss/mail/Default">
<smtp-server outbound-socket-binding-ref="mail-smtp"/>
</mail-session>
</subsystem>
<subsystem xmlns="urn:wildfly:metrics:1.0" security-enabled="false" exposed-subsystems="*" prefix="${wildfly.metrics.prefix:wildfly}"/>
<subsystem xmlns="urn:jboss:domain:modcluster:5.0">
<proxy name="default" advertise-socket="modcluster" listener="ajp">
<dynamic-load-provider>
<load-metric type="cpu"/>
</dynamic-load-provider>
</proxy>
</subsystem>
<subsystem xmlns="urn:jboss:domain:naming:2.0">
<remote-naming/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:remoting:4.0">
<http-connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:request-controller:1.0"/>
<subsystem xmlns="urn:jboss:domain:security:2.0">
<security-domains>
<security-domain name="other" cache-type="default">
<authentication>
<login-module code="Remoting" flag="optional">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
<login-module code="RealmDirect" flag="required">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
</authentication>
</security-domain>
<security-domain name="jboss-web-policy" cache-type="default">
<authorization>
<policy-module code="Delegating" flag="required"/>
</authorization>
</security-domain>
<security-domain name="jaspitest" cache-type="default">
<authentication-jaspi>
<login-module-stack name="dummy">
<login-module code="Dummy" flag="optional"/>
</login-module-stack>
<auth-module code="Dummy"/>
</authentication-jaspi>
</security-domain>
<security-domain name="jboss-ejb-policy" cache-type="default">
<authorization>
<policy-module code="Delegating" flag="required"/>
</authorization>
</security-domain>
</security-domains>
</subsystem>
<subsystem xmlns="urn:jboss:domain:security-manager:1.0">
<deployment-permissions>
<maximum-set>
<permission class="java.security.AllPermission"/>
</maximum-set>
</deployment-permissions>
</subsystem>
<subsystem xmlns="urn:jboss:domain:transactions:6.0">
<core-environment node-identifier="${jboss.tx.node.id:1}">
<process-id>
<uuid/>
</process-id>
</core-environment>
<recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
<coordinator-environment statistics-enabled="${wildfly.transactions.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
<object-store path="tx-object-store" relative-to="jboss.server.data.dir"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:undertow:12.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
<buffer-cache name="default"/>
<server name="default-server">
<ajp-listener name="ajp" socket-binding="ajp"/>
<http-listener name="default" socket-binding="http" redirect-socket="https" proxy-address-forwarding="${env.PROXY_ADDRESS_FORWARDING:false}" enable-http2="true"/>
<https-listener name="https" socket-binding="https" proxy-address-forwarding="${env.PROXY_ADDRESS_FORWARDING:false}" security-realm="ApplicationRealm" enable-http2="true"/>
<host name="default-host" alias="localhost">
<location name="/" handler="welcome-content"/>
<http-invoker security-realm="ApplicationRealm"/>
</host>
</server>
<servlet-container name="default">
<jsp-config/>
<websockets/>
</servlet-container>
<handlers>
<file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
</handlers>
</subsystem>
<subsystem xmlns="urn:jboss:domain:weld:4.0"/>
</profile>
<interfaces>
<interface name="management">
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
</interface>
<interface name="private">
<inet-address value="${jboss.bind.address.private:127.0.0.1}"/>
</interface>
<interface name="public">
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
</interface>
</interfaces>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
<socket-binding name="http" port="${jboss.http.port:8080}"/>
<socket-binding name="https" port="${jboss.https.port:8443}"/>
<socket-binding name="jgroups-mping" interface="private" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45700"/>
<socket-binding name="jgroups-tcp" interface="private" port="7600"/>
<socket-binding name="jgroups-tcp-fd" interface="private" port="57600"/>
<socket-binding name="jgroups-udp" interface="private" port="55200" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45688"/>
<socket-binding name="jgroups-udp-fd" interface="private" port="54200"/>
<socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
<socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
<socket-binding name="modcluster" multicast-address="${jboss.modcluster.multicast.address:224.0.1.105}" multicast-port="23364"/>
<socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/>
<outbound-socket-binding name="mail-smtp">
<remote-destination host="${jboss.mail.server.host:localhost}" port="${jboss.mail.server.port:25}"/>
</outbound-socket-binding>
</socket-binding-group>
</server>

View File

@ -1,135 +0,0 @@
import cheerio from "cheerio";
import { replaceImportsFromStaticInJsCode, replaceImportsInInlineCssCode, generateCssCodeToDefineGlobals } from "../replaceImportFromStatic";
import fs from "fs";
import { join as pathJoin } from "path";
import { objectKeys } from "tsafe/objectKeys";
import { ftlValuesGlobalName } from "../ftlValuesGlobalName";
export const pageIds = [
"login.ftl",
"register.ftl",
"register-user-profile.ftl",
"info.ftl",
"error.ftl",
"login-reset-password.ftl",
"login-verify-email.ftl",
"terms.ftl",
"login-otp.ftl",
"login-update-profile.ftl",
"login-update-password.ftl",
"login-idp-link-confirm.ftl",
"login-page-expired.ftl",
] as const;
export type PageId = typeof pageIds[number];
export function generateFtlFilesCodeFactory(params: {
cssGlobalsToDefine: Record<string, string>;
indexHtmlCode: string;
urlPathname: string;
urlOrigin: undefined | string;
}) {
const { cssGlobalsToDefine, indexHtmlCode, urlPathname, urlOrigin } = params;
const $ = cheerio.load(indexHtmlCode);
$("script:not([src])").each((...[, element]) => {
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
"jsCode": $(element).html()!,
urlOrigin,
});
$(element).text(fixedJsCode);
});
$("style").each((...[, element]) => {
const { fixedCssCode } = replaceImportsInInlineCssCode({
"cssCode": $(element).html()!,
"urlPathname": params.urlPathname,
urlOrigin,
});
$(element).text(fixedCssCode);
});
(
[
["link", "href"],
["script", "src"],
] as const
).forEach(([selector, attrName]) =>
$(selector).each((...[, element]) => {
const href = $(element).attr(attrName);
if (href === undefined) {
return;
}
$(element).attr(
attrName,
urlOrigin !== undefined
? href.replace(/^\//, `${urlOrigin}/`)
: href.replace(new RegExp(`^${urlPathname.replace(/\//g, "\\/")}`), "${url.resourcesPath}/build/"),
);
}),
);
//FTL is no valid html, we can't insert with cheerio, we put placeholder for injecting later.
const replaceValueBySearchValue = {
'{ "x": "vIdLqMeOed9sdLdIdOxdK0d" }': fs
.readFileSync(pathJoin(__dirname, "ftl_object_to_js_code_declaring_an_object.ftl"))
.toString("utf8")
.match(/^<script>const _=((?:.|\n)+)<\/script>[\n]?$/)![1],
"<!-- xIdLqMeOedErIdLsPdNdI9dSlxI -->": [
"<#if scripts??>",
" <#list scripts as script>",
' <script src="${script}" type="text/javascript"></script>',
" </#list>",
"</#if>",
].join("\n"),
};
$("head").prepend(
[
...(Object.keys(cssGlobalsToDefine).length === 0
? []
: [
"",
"<style>",
generateCssCodeToDefineGlobals({
cssGlobalsToDefine,
urlPathname,
}).cssCodeToPrependInHead,
"</style>",
"",
]),
"<script>",
` window.${ftlValuesGlobalName}= ${objectKeys(replaceValueBySearchValue)[0]};`,
"</script>",
"",
objectKeys(replaceValueBySearchValue)[1],
].join("\n"),
);
const partiallyFixedIndexHtmlCode = $.html();
function generateFtlFilesCode(params: { pageId: string }): {
ftlCode: string;
} {
const { pageId } = params;
const $ = cheerio.load(partiallyFixedIndexHtmlCode);
let ftlCode = $.html();
Object.entries({
...replaceValueBySearchValue,
//If updated, don't forget to change in the ftl script as well.
"PAGE_ID_xIgLsPgGId9D8e": pageId,
}).map(([searchValue, replaceValue]) => (ftlCode = ftlCode.replace(searchValue, replaceValue)));
return { ftlCode };
}
return { generateFtlFilesCode };
}

View File

@ -1,140 +0,0 @@
import { transformCodebase } from "../tools/transformCodebase";
import * as fs from "fs";
import { join as pathJoin } from "path";
import { replaceImportsInCssCode, replaceImportsFromStaticInJsCode } from "./replaceImportFromStatic";
import { generateFtlFilesCodeFactory, pageIds } from "./generateFtl";
import { downloadBuiltinKeycloakTheme } from "../download-builtin-keycloak-theme";
import * as child_process from "child_process";
import { resourcesCommonPath, resourcesPath, subDirOfPublicDirBasename } from "../../lib/getKcContext/kcContextMocks/urlResourcesPath";
import { isInside } from "../tools/isInside";
export function generateKeycloakThemeResources(params: {
themeName: string;
reactAppBuildDirPath: string;
keycloakThemeBuildingDirPath: string;
urlPathname: string;
//If urlOrigin is not undefined then it means --externals-assets
urlOrigin: undefined | string;
extraPagesId: string[];
extraThemeProperties: string[];
keycloakVersion: "11.0.3" | "15.0.2";
}) {
const {
themeName,
reactAppBuildDirPath,
keycloakThemeBuildingDirPath,
urlPathname,
urlOrigin,
extraPagesId,
extraThemeProperties,
keycloakVersion,
} = params;
const themeDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", themeName, "login");
let allCssGlobalsToDefine: Record<string, string> = {};
transformCodebase({
"destDirPath": urlOrigin === undefined ? pathJoin(themeDirPath, "resources", "build") : reactAppBuildDirPath,
"srcDirPath": reactAppBuildDirPath,
"transformSourceCode": ({ filePath, sourceCode }) => {
//NOTE: Prevent cycles, excludes the folder we generated for debug in public/
if (
urlOrigin === undefined &&
isInside({
"dirPath": pathJoin(reactAppBuildDirPath, subDirOfPublicDirBasename),
filePath,
})
) {
return undefined;
}
if (urlOrigin === undefined && /\.css?$/i.test(filePath)) {
const { cssGlobalsToDefine, fixedCssCode } = replaceImportsInCssCode({
"cssCode": sourceCode.toString("utf8"),
});
allCssGlobalsToDefine = {
...allCssGlobalsToDefine,
...cssGlobalsToDefine,
};
return {
"modifiedSourceCode": Buffer.from(fixedCssCode, "utf8"),
};
}
if (/\.js?$/i.test(filePath)) {
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
"jsCode": sourceCode.toString("utf8"),
urlOrigin,
});
return {
"modifiedSourceCode": Buffer.from(fixedJsCode, "utf8"),
};
}
return urlOrigin === undefined ? { "modifiedSourceCode": sourceCode } : undefined;
},
});
const { generateFtlFilesCode } = generateFtlFilesCodeFactory({
"cssGlobalsToDefine": allCssGlobalsToDefine,
"indexHtmlCode": fs.readFileSync(pathJoin(reactAppBuildDirPath, "index.html")).toString("utf8"),
urlPathname,
urlOrigin,
});
[...pageIds, ...extraPagesId].forEach(pageId => {
const { ftlCode } = generateFtlFilesCode({ pageId });
fs.mkdirSync(themeDirPath, { "recursive": true });
fs.writeFileSync(pathJoin(themeDirPath, pageId), Buffer.from(ftlCode, "utf8"));
});
{
const tmpDirPath = pathJoin(themeDirPath, "..", "tmp_xxKdLpdIdLd");
downloadBuiltinKeycloakTheme({
keycloakVersion,
"destDirPath": tmpDirPath,
});
const themeResourcesDirPath = pathJoin(themeDirPath, "resources");
transformCodebase({
"srcDirPath": pathJoin(tmpDirPath, "keycloak", "login", "resources"),
"destDirPath": themeResourcesDirPath,
});
const reactAppPublicDirPath = pathJoin(reactAppBuildDirPath, "..", "public");
transformCodebase({
"srcDirPath": themeResourcesDirPath,
"destDirPath": pathJoin(reactAppPublicDirPath, resourcesPath),
});
transformCodebase({
"srcDirPath": pathJoin(tmpDirPath, "keycloak", "common", "resources"),
"destDirPath": pathJoin(reactAppPublicDirPath, resourcesCommonPath),
});
const keycloakResourcesWithinPublicDirPath = pathJoin(reactAppPublicDirPath, subDirOfPublicDirBasename);
fs.writeFileSync(
pathJoin(keycloakResourcesWithinPublicDirPath, "README.txt"),
Buffer.from(["This is just a test folder that helps develop", "the login and register page without having to yarn build"].join(" ")),
);
fs.writeFileSync(pathJoin(keycloakResourcesWithinPublicDirPath, ".gitignore"), Buffer.from("*", "utf8"));
child_process.execSync(`rm -r ${tmpDirPath}`);
}
fs.writeFileSync(
pathJoin(themeDirPath, "theme.properties"),
Buffer.from("parent=keycloak".concat("\n\n", extraThemeProperties.join("\n\n")), "utf8"),
);
}

View File

@ -1,8 +0,0 @@
#!/usr/bin/env node
export * from "./build-keycloak-theme";
import { main } from "./build-keycloak-theme";
if (require.main === module) {
main();
}

View File

@ -1,92 +0,0 @@
import * as crypto from "crypto";
import { ftlValuesGlobalName } from "./ftlValuesGlobalName";
export function replaceImportsFromStaticInJsCode(params: { jsCode: string; urlOrigin: undefined | string }): { fixedJsCode: string } {
/*
NOTE:
When we have urlOrigin defined it means that
we are building with --external-assets
so we have to make sur that the fixed js code will run
inside and outside keycloak.
When urlOrigin isn't defined we can assume the fixedJsCode
will always run in keycloak context.
*/
const { jsCode, urlOrigin } = params;
const fixedJsCode = jsCode
.replace(/([a-z]+\.[a-z]+)\+"static\//g, (...[, group]) =>
urlOrigin === undefined
? `window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/`
: `("${ftlValuesGlobalName}" in window ? "${urlOrigin}" : "") + ${group} + "static/`,
)
.replace(/".chunk.css",([a-z])+=([a-z]+\.[a-z]+)\+([a-z]+),/, (...[, group1, group2, group3]) =>
urlOrigin === undefined
? `".chunk.css",${group1} = window.${ftlValuesGlobalName}.url.resourcesPath + "/build/" + ${group3},`
: `".chunk.css",${group1} = ("${ftlValuesGlobalName}" in window ? "${urlOrigin}" : "") + ${group2} + ${group3},`,
);
return { fixedJsCode };
}
export function replaceImportsInInlineCssCode(params: { cssCode: string; urlPathname: string; urlOrigin: undefined | string }): {
fixedCssCode: string;
} {
const { cssCode, urlPathname, urlOrigin } = params;
const fixedCssCode = cssCode.replace(
urlPathname === "/" ? /url\(["']?\/([^/][^)"']+)["']?\)/g : new RegExp(`url\\(["']?${urlPathname}([^)"']+)["']?\\)`, "g"),
(...[, group]) => `url(${urlOrigin === undefined ? "${url.resourcesPath}/build/" + group : params.urlOrigin + urlPathname + group})`,
);
return { fixedCssCode };
}
export function replaceImportsInCssCode(params: { cssCode: string }): {
fixedCssCode: string;
cssGlobalsToDefine: Record<string, string>;
} {
const { cssCode } = params;
const cssGlobalsToDefine: Record<string, string> = {};
new Set(cssCode.match(/url\(["']?\/[^/][^)"']+["']?\)[^;}]*/g) ?? []).forEach(
match => (cssGlobalsToDefine["url" + crypto.createHash("sha256").update(match).digest("hex").substring(0, 15)] = match),
);
let fixedCssCode = cssCode;
Object.keys(cssGlobalsToDefine).forEach(
cssVariableName =>
//NOTE: split/join pattern ~ replace all
(fixedCssCode = fixedCssCode.split(cssGlobalsToDefine[cssVariableName]).join(`var(--${cssVariableName})`)),
);
return { fixedCssCode, cssGlobalsToDefine };
}
export function generateCssCodeToDefineGlobals(params: { cssGlobalsToDefine: Record<string, string>; urlPathname: string }): {
cssCodeToPrependInHead: string;
} {
const { cssGlobalsToDefine, urlPathname } = params;
return {
"cssCodeToPrependInHead": [
":root {",
...Object.keys(cssGlobalsToDefine)
.map(cssVariableName =>
[
`--${cssVariableName}:`,
cssGlobalsToDefine[cssVariableName].replace(
new RegExp(`url\\(${urlPathname.replace(/\//g, "\\/")}`, "g"),
"url(${url.resourcesPath}/build/",
),
].join(" "),
)
.map(line => ` ${line};`),
"}",
].join("\n"),
};
}

View File

@ -0,0 +1,41 @@
#!/usr/bin/env node
import { downloadBuiltinKeycloakTheme } from "./download-builtin-keycloak-theme";
import { keycloakThemeEmailDirPath } from "./keycloakify";
import { join as pathJoin, basename as pathBasename } from "path";
import { transformCodebase } from "./tools/transformCodebase";
import { promptKeycloakVersion } from "./promptKeycloakVersion";
import * as fs from "fs";
import { getCliOptions } from "./tools/cliOptions";
import { getLogger } from "./tools/logger";
if (require.main === module) {
(async () => {
const { isSilent } = getCliOptions(process.argv.slice(2));
const logger = getLogger({ isSilent });
if (fs.existsSync(keycloakThemeEmailDirPath)) {
logger.warn(`There is already a ./${pathBasename(keycloakThemeEmailDirPath)} directory in your project. Aborting.`);
process.exit(-1);
}
const { keycloakVersion } = await promptKeycloakVersion();
const builtinKeycloakThemeTmpDirPath = pathJoin(keycloakThemeEmailDirPath, "..", "tmp_xIdP3_builtin_keycloak_theme");
downloadBuiltinKeycloakTheme({
keycloakVersion,
"destDirPath": builtinKeycloakThemeTmpDirPath,
isSilent
});
transformCodebase({
"srcDirPath": pathJoin(builtinKeycloakThemeTmpDirPath, "base", "email"),
"destDirPath": keycloakThemeEmailDirPath
});
logger.log(`./${pathBasename(keycloakThemeEmailDirPath)} ready to be customized`);
fs.rmSync(builtinKeycloakThemeTmpDirPath, { "recursive": true, "force": true });
})();
}

View File

@ -1,39 +1,40 @@
#!/usr/bin/env node
import { keycloakThemeBuildingDirPath } from "./build-keycloak-theme";
import { keycloakThemeBuildingDirPath } from "./keycloakify";
import { join as pathJoin } from "path";
import { downloadAndUnzip } from "./tools/downloadAndUnzip";
import type { KeycloakVersion } from "./KeycloakVersion";
import { promptKeycloakVersion } from "./promptKeycloakVersion";
import { getCliOptions } from "./tools/cliOptions";
import { getLogger } from "./tools/logger";
export function downloadBuiltinKeycloakTheme(params: { keycloakVersion: KeycloakVersion; destDirPath: string }) {
const { keycloakVersion, destDirPath } = params;
export async function downloadBuiltinKeycloakTheme(params: { keycloakVersion: string; destDirPath: string; isSilent: boolean }) {
const { keycloakVersion, destDirPath, isSilent } = params;
for (const ext of ["", "-community"]) {
downloadAndUnzip({
await downloadAndUnzip({
"destDirPath": destDirPath,
"url": `https://github.com/keycloak/keycloak/archive/refs/tags/${keycloakVersion}.zip`,
"pathOfDirToExtractInArchive": `keycloak-${keycloakVersion}/themes/src/main/resources${ext}/theme`,
"cacheDirPath": pathJoin(keycloakThemeBuildingDirPath, ".cache"),
isSilent
});
}
}
if (require.main === module) {
const keycloakVersion = (() => {
const keycloakVersion = process.argv[2] as KeycloakVersion | undefined;
(async () => {
const { isSilent } = getCliOptions(process.argv.slice(2));
const logger = getLogger({ isSilent });
const { keycloakVersion } = await promptKeycloakVersion();
if (keycloakVersion === undefined) {
return "15.0.2";
}
const destDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme");
return keycloakVersion;
logger.log(`Downloading builtins theme of Keycloak ${keycloakVersion} here ${destDirPath}`);
await downloadBuiltinKeycloakTheme({
keycloakVersion,
destDirPath,
isSilent
});
})();
const destDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme");
console.log(`Downloading builtins theme of Keycloak ${keycloakVersion} here ${destDirPath}`);
downloadBuiltinKeycloakTheme({
keycloakVersion,
destDirPath,
});
}

View File

@ -1,75 +0,0 @@
import "minimal-polyfills/Object.fromEntries";
import * as fs from "fs";
import { join as pathJoin, relative as pathRelative } from "path";
import { crawl } from "./tools/crawl";
import { downloadBuiltinKeycloakTheme } from "./download-builtin-keycloak-theme";
import { getProjectRoot } from "./tools/getProjectRoot";
import { rm_rf, rm_r } from "./tools/rm";
import { keycloakVersions } from "./KeycloakVersion";
//@ts-ignore
const propertiesParser = require("properties-parser");
for (const keycloakVersion of keycloakVersions) {
console.log({ keycloakVersion });
const tmpDirPath = pathJoin(getProjectRoot(), "tmp_xImOef9dOd44");
rm_rf(tmpDirPath);
downloadBuiltinKeycloakTheme({
keycloakVersion,
"destDirPath": tmpDirPath,
});
type Dictionary = { [idiomId: string]: string };
const record: { [typeOfPage: string]: { [language: string]: Dictionary } } = {};
{
const baseThemeDirPath = pathJoin(tmpDirPath, "base");
crawl(baseThemeDirPath).forEach(filePath => {
const match = filePath.match(/^([^/]+)\/messages\/messages_([^.]+)\.properties$/);
if (match === null) {
return;
}
const [, typeOfPage, language] = match;
(record[typeOfPage] ??= {})[language.replace(/_/g, "-")] = Object.fromEntries(
Object.entries(propertiesParser.parse(fs.readFileSync(pathJoin(baseThemeDirPath, filePath)).toString("utf8"))).map(
([key, value]: any) => [key, value.replace(/''/g, "'")],
),
);
});
}
rm_r(tmpDirPath);
const targetDirPath = pathJoin(getProjectRoot(), "src", "lib", "i18n", "generated_kcMessages", keycloakVersion);
fs.mkdirSync(targetDirPath, { "recursive": true });
Object.keys(record).forEach(pageType => {
const filePath = pathJoin(targetDirPath, `${pageType}.ts`);
fs.writeFileSync(
filePath,
Buffer.from(
[
`//This code was automatically generated by running ${pathRelative(getProjectRoot(), __filename)}`,
"//PLEASE DO NOT EDIT MANUALLY",
"",
"/* spell-checker: disable */",
`export const kcMessages= ${JSON.stringify(record[pageType], null, 2)};`,
"/* spell-checker: enable */",
].join("\n"),
"utf8",
),
);
console.log(`${filePath} wrote`);
});
}

View File

@ -0,0 +1,207 @@
import { z } from "zod";
import { assert } from "tsafe/assert";
import type { Equals } from "tsafe";
import { id } from "tsafe/id";
import { parse as urlParse } from "url";
import { typeGuard } from "tsafe/typeGuard";
import { symToStr } from "tsafe/symToStr";
const bundlers = ["mvn", "keycloakify", "none"] as const;
type Bundler = (typeof bundlers)[number];
type ParsedPackageJson = {
name: string;
version: string;
homepage?: string;
keycloakify?: {
extraPages?: string[];
extraThemeProperties?: string[];
areAppAndKeycloakServerSharingSameDomain?: boolean;
artifactId?: string;
groupId?: string;
bundler?: Bundler;
};
};
const zParsedPackageJson = z.object({
"name": z.string(),
"version": z.string(),
"homepage": z.string().optional(),
"keycloakify": z
.object({
"extraPages": z.array(z.string()).optional(),
"extraThemeProperties": z.array(z.string()).optional(),
"areAppAndKeycloakServerSharingSameDomain": z.boolean().optional(),
"artifactId": z.string().optional(),
"groupId": z.string().optional(),
"bundler": z.enum(bundlers).optional()
})
.optional()
});
assert<Equals<ReturnType<(typeof zParsedPackageJson)["parse"]>, ParsedPackageJson>>();
/** Consolidated build option gathered form CLI arguments and config in package.json */
export type BuildOptions = BuildOptions.Standalone | BuildOptions.ExternalAssets;
export namespace BuildOptions {
export type Common = {
isSilent: boolean;
version: string;
themeName: string;
extraPages?: string[];
extraThemeProperties?: string[];
groupId: string;
artifactId: string;
bundler: Bundler;
};
export type Standalone = Common & {
isStandalone: true;
urlPathname: string | undefined;
};
export type ExternalAssets = ExternalAssets.SameDomain | ExternalAssets.DifferentDomains;
export namespace ExternalAssets {
export type CommonExternalAssets = Common & {
isStandalone: false;
};
export type SameDomain = CommonExternalAssets & {
areAppAndKeycloakServerSharingSameDomain: true;
};
export type DifferentDomains = CommonExternalAssets & {
areAppAndKeycloakServerSharingSameDomain: false;
urlOrigin: string;
urlPathname: string | undefined;
};
}
}
export function readBuildOptions(params: {
packageJson: string;
CNAME: string | undefined;
isExternalAssetsCliParamProvided: boolean;
isSilent: boolean;
}): BuildOptions {
const { packageJson, CNAME, isExternalAssetsCliParamProvided, isSilent } = params;
const parsedPackageJson = zParsedPackageJson.parse(JSON.parse(packageJson));
const url = (() => {
const { homepage } = parsedPackageJson;
let url: URL | undefined = undefined;
if (homepage !== undefined) {
url = new URL(homepage);
}
if (CNAME !== undefined) {
url = new URL(`https://${CNAME.replace(/\s+$/, "")}`);
}
if (url === undefined) {
return undefined;
}
return {
"origin": url.origin,
"pathname": (() => {
const out = url.pathname.replace(/([^/])$/, "$1/");
return out === "/" ? undefined : out;
})()
};
})();
const common: BuildOptions.Common = (() => {
const { name, keycloakify = {}, version, homepage } = parsedPackageJson;
const { extraPages, extraThemeProperties, groupId, artifactId, bundler } = keycloakify ?? {};
const themeName = name
.replace(/^@(.*)/, "$1")
.split("/")
.join("-");
return {
themeName,
"bundler": (() => {
const { KEYCLOAKIFY_BUNDLER } = process.env;
assert(
typeGuard<Bundler | undefined>(
KEYCLOAKIFY_BUNDLER,
[undefined, ...id<readonly string[]>(bundlers)].includes(KEYCLOAKIFY_BUNDLER)
),
`${symToStr({ KEYCLOAKIFY_BUNDLER })} should be one of ${bundlers.join(", ")}`
);
return KEYCLOAKIFY_BUNDLER ?? bundler ?? "keycloakify";
})(),
"artifactId": process.env.KEYCLOAKIFY_ARTIFACT_ID ?? artifactId ?? `${themeName}-keycloak-theme`,
"groupId": (() => {
const fallbackGroupId = `${themeName}.keycloak`;
return (
process.env.KEYCLOAKIFY_GROUP_ID ??
groupId ??
(!homepage
? fallbackGroupId
: urlParse(homepage)
.host?.replace(/:[0-9]+$/, "")
?.split(".")
.reverse()
.join(".") ?? fallbackGroupId) + ".keycloak"
);
})(),
"version": process.env.KEYCLOAKIFY_VERSION ?? version,
extraPages,
extraThemeProperties,
isSilent
};
})();
if (isExternalAssetsCliParamProvided) {
const commonExternalAssets = id<BuildOptions.ExternalAssets.CommonExternalAssets>({
...common,
"isStandalone": false
});
if (parsedPackageJson.keycloakify?.areAppAndKeycloakServerSharingSameDomain) {
return id<BuildOptions.ExternalAssets.SameDomain>({
...commonExternalAssets,
"areAppAndKeycloakServerSharingSameDomain": true
});
} else {
assert(
url !== undefined,
[
"Can't compile in external assets mode if we don't know where",
"the app will be hosted.",
"You should provide a homepage field in the package.json (or create a",
"public/CNAME file.",
"Alternatively, if your app and the Keycloak server are on the same domain, ",
"eg https://example.com is your app and https://example.com/auth is the keycloak",
'admin UI, you can set "keycloakify": { "areAppAndKeycloakServerSharingSameDomain": true }',
"in your package.json"
].join(" ")
);
return id<BuildOptions.ExternalAssets.DifferentDomains>({
...commonExternalAssets,
"areAppAndKeycloakServerSharingSameDomain": false,
"urlOrigin": url.origin,
"urlPathname": url.pathname
});
}
}
return id<BuildOptions.Standalone>({
...common,
"isStandalone": true,
"urlPathname": url?.pathname
});
}

View File

@ -30,50 +30,84 @@ ${ftl_object_to_js_code_declaring_an_object(.data_model, [])?no_esc};
</#attempt>
"printIfExists": function (fieldName, x) {
<#list fieldNames as fieldName>
if(fieldName === "${fieldName}" ){
<#attempt>
return "${messagesPerField.printIfExists(fieldName,'1')}" ? x : undefined;
<#recover>
</#attempt>
}
</#list>
throw new Error("There is no " + fieldName + " field");
<#if !messagesPerField?? >
return undefined;
<#else>
<#list fieldNames as fieldName>
if(fieldName === "${fieldName}" ){
<#attempt>
<#if '${fieldName}' == 'username' || '${fieldName}' == 'password'>
return <#if messagesPerField.existsError('username', 'password')>x<#else>undefined</#if>;
<#else>
return <#if messagesPerField.existsError('${fieldName}')>x<#else>undefined</#if>;
</#if>
<#recover>
</#attempt>
}
</#list>
throw new Error("There is no " + fieldName + " field");
</#if>
},
"existsError": function (fieldName) {
<#list fieldNames as fieldName>
if(fieldName === "${fieldName}" ){
<#attempt>
return <#if messagesPerField.existsError('${fieldName}')>true<#else>false</#if>;
<#recover>
</#attempt>
}
</#list>
throw new Error("There is no " + fieldName + " field");
<#if !messagesPerField?? >
return false;
<#else>
<#list fieldNames as fieldName>
if(fieldName === "${fieldName}" ){
<#attempt>
<#if '${fieldName}' == 'username' || '${fieldName}' == 'password'>
return <#if messagesPerField.existsError('username', 'password')>true<#else>false</#if>;
<#else>
return <#if messagesPerField.existsError('${fieldName}')>true<#else>false</#if>;
</#if>
<#recover>
</#attempt>
}
</#list>
throw new Error("There is no " + fieldName + " field");
</#if>
},
"get": function (fieldName) {
<#list fieldNames as fieldName>
if(fieldName === "${fieldName}" ){
<#attempt>
<#if messagesPerField.existsError('${fieldName}')>
return "${messagesPerField.get('${fieldName}')?no_esc}";
</#if>
<#recover>
</#attempt>
}
</#list>
throw new Error("There is no " + fieldName + " field");
<#if !messagesPerField?? >
return '';
<#else>
<#list fieldNames as fieldName>
if(fieldName === "${fieldName}" ){
<#attempt>
<#if '${fieldName}' == 'username' || '${fieldName}' == 'password'>
<#if messagesPerField.existsError('username', 'password')>
return 'Invalid username or password.';
</#if>
<#else>
<#if messagesPerField.existsError('${fieldName}')>
return "${messagesPerField.get('${fieldName}')?no_esc}";
</#if>
</#if>
<#recover>
</#attempt>
}
</#list>
throw new Error("There is no " + fieldName + " field");
</#if>
},
"exists": function (fieldName) {
<#list fieldNames as fieldName>
if(fieldName === "${fieldName}" ){
<#attempt>
return <#if messagesPerField.exists('${fieldName}')>true<#else>false</#if>;
<#recover>
</#attempt>
}
</#list>
throw new Error("There is no " + fieldName + " field");
<#if !messagesPerField?? >
return false;
<#else>
<#list fieldNames as fieldName>
if(fieldName === "${fieldName}" ){
<#attempt>
<#if '${fieldName}' == 'username' || '${fieldName}' == 'password'>
return <#if messagesPerField.exists('username') || messagesPerField.exists('password')>true<#else>false</#if>;
<#else>
return <#if messagesPerField.exists('${fieldName}')>true<#else>false</#if>;
</#if>
<#recover>
</#attempt>
}
</#list>
throw new Error("There is no " + fieldName + " field");
</#if>
}
};
@ -122,10 +156,28 @@ ${ftl_object_to_js_code_declaring_an_object(.data_model, [])?no_esc};
key == "updateProfileCtx" &&
are_same_path(path, [])
) || (
<#-- https://github.com/InseeFrLab/keycloakify/pull/65#issuecomment-991896344 -->
<#-- https://github.com/InseeFrLab/keycloakify/pull/65#issuecomment-991896344 (reports with saml-post-form.ftl) -->
<#-- https://github.com/InseeFrLab/keycloakify/issues/91#issue-1212319466 (reports with error.ftl and Kc18) -->
<#-- https://github.com/InseeFrLab/keycloakify/issues/109#issuecomment-1134610163 -->
key == "loginAction" &&
are_same_path(path, ["url"]) &&
pageId == "saml-post-form.ftl"
["saml-post-form.ftl", "error.ftl", "info.ftl"]?seq_contains(pageId) &&
!(auth?has_content && auth.showTryAnotherWayLink())
) || (
["contextData", "idpConfig", "idp", "authenticationSession"]?seq_contains(key) &&
are_same_path(path, ["brokerContext"]) &&
["login-idp-link-confirm.ftl", "login-idp-link-email.ftl" ]?seq_contains(pageId)
) || (
key == "identityProviderBrokerCtx" &&
are_same_path(path, []) &&
["login-idp-link-confirm.ftl", "login-idp-link-email.ftl" ]?seq_contains(pageId)
) || (
["masterAdminClient", "delegateForUpdate", "defaultRole"]?seq_contains(key) &&
are_same_path(path, ["realm"])
) || (
"error.ftl" == pageId &&
are_same_path(path, ["realm"]) &&
!["name", "displayName", "displayNameHtml", "internationalizationEnabled", "registrationEmailAsUsername" ]?seq_contains(key)
)
>
<#local out_seq += ["/*If you need '" + key + "' on " + pageId + ", please submit an issue to the Keycloakify repo*/"]>
@ -143,16 +195,7 @@ ${ftl_object_to_js_code_declaring_an_object(.data_model, [])?no_esc};
</#attempt>
</#if>
<#if
["contextData", "idpConfig", "idp", "authenticationSession"]?seq_contains(key) &&
are_same_path(path, ["brokerContext"])
>
<#continue>
</#if>
<#if key == "identityProviderBrokerCtx" && are_same_path(path, []) ><#continue></#if>
<#attempt>
<#if !object[key]??>
<#continue>
@ -200,6 +243,31 @@ ${ftl_object_to_js_code_declaring_an_object(.data_model, [])?no_esc};
</#attempt>
<#if isMethod>
<#if are_same_path(path, ["auth", "showUsername"])>
<#attempt>
<#return auth.showUsername()?c>
<#recover>
<#return "ABORT: Couldn't evaluate auth.showUsername()">
</#attempt>
</#if>
<#if are_same_path(path, ["auth", "showResetCredentials"])>
<#attempt>
<#return auth.showResetCredentials()?c>
<#recover>
<#return "ABORT: Couldn't evaluate auth.showResetCredentials()">
</#attempt>
</#if>
<#if are_same_path(path, ["auth", "showTryAnotherWayLink"])>
<#attempt>
<#return auth.showTryAnotherWayLink()?c>
<#recover>
<#return "ABORT: Couldn't evaluate auth.showTryAnotherWayLink()">
</#attempt>
</#if>
<#return "ABORT: It's a method">
</#if>
@ -230,6 +298,11 @@ ${ftl_object_to_js_code_declaring_an_object(.data_model, [])?no_esc};
<#list object as array_item>
<#if !array_item??>
<#local out_seq += ["null,"]>
<#continue>
</#if>
<#local rec_out = ftl_object_to_js_code_declaring_an_object(array_item, path + [ i ])>
<#local i = i + 1>
@ -263,7 +336,7 @@ ${ftl_object_to_js_code_declaring_an_object(.data_model, [])?no_esc};
</#function>
<#function are_same_path path searchedPath>
<#if path?size != path?size>
<#if path?size != searchedPath?size>
<#return false>
</#if>

View File

@ -0,0 +1,190 @@
import cheerio from "cheerio";
import { replaceImportsFromStaticInJsCode } from "../replacers/replaceImportsFromStaticInJsCode";
import { generateCssCodeToDefineGlobals } from "../replacers/replaceImportsInCssCode";
import { replaceImportsInInlineCssCode } from "../replacers/replaceImportsInInlineCssCode";
import * as fs from "fs";
import { join as pathJoin } from "path";
import { objectKeys } from "tsafe/objectKeys";
import { ftlValuesGlobalName } from "../ftlValuesGlobalName";
import type { BuildOptions } from "../BuildOptions";
import { assert } from "tsafe/assert";
import { Reflect } from "tsafe/Reflect";
// https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/forms/login/freemarker/Templates.java
export const pageIds = [
"login.ftl",
"login-username.ftl",
"login-password.ftl",
"webauthn-authenticate.ftl",
"register.ftl",
"register-user-profile.ftl",
"info.ftl",
"error.ftl",
"login-reset-password.ftl",
"login-verify-email.ftl",
"terms.ftl",
"login-otp.ftl",
"login-update-profile.ftl",
"login-update-password.ftl",
"login-idp-link-confirm.ftl",
"login-idp-link-email.ftl",
"login-page-expired.ftl",
"login-config-totp.ftl",
"logout-confirm.ftl",
"update-user-profile.ftl",
"idp-review-user-profile.ftl"
] as const;
export type BuildOptionsLike = BuildOptionsLike.Standalone | BuildOptionsLike.ExternalAssets;
export namespace BuildOptionsLike {
export type Standalone = {
isStandalone: true;
urlPathname: string | undefined;
};
export type ExternalAssets = ExternalAssets.SameDomain | ExternalAssets.DifferentDomains;
export namespace ExternalAssets {
export type CommonExternalAssets = {
isStandalone: false;
};
export type SameDomain = CommonExternalAssets & {
areAppAndKeycloakServerSharingSameDomain: true;
};
export type DifferentDomains = CommonExternalAssets & {
areAppAndKeycloakServerSharingSameDomain: false;
urlOrigin: string;
urlPathname: string | undefined;
};
}
}
{
const buildOptions = Reflect<BuildOptions>();
assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
}
export type PageId = (typeof pageIds)[number];
export function generateFtlFilesCodeFactory(params: {
indexHtmlCode: string;
//NOTE: Expected to be an empty object if external assets mode is enabled.
cssGlobalsToDefine: Record<string, string>;
buildOptions: BuildOptionsLike;
}) {
const { cssGlobalsToDefine, indexHtmlCode, buildOptions } = params;
const $ = cheerio.load(indexHtmlCode);
fix_imports_statements: {
if (!buildOptions.isStandalone && buildOptions.areAppAndKeycloakServerSharingSameDomain) {
break fix_imports_statements;
}
$("script:not([src])").each((...[, element]) => {
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
"jsCode": $(element).html()!,
buildOptions
});
$(element).text(fixedJsCode);
});
$("style").each((...[, element]) => {
const { fixedCssCode } = replaceImportsInInlineCssCode({
"cssCode": $(element).html()!,
buildOptions
});
$(element).text(fixedCssCode);
});
(
[
["link", "href"],
["script", "src"]
] as const
).forEach(([selector, attrName]) =>
$(selector).each((...[, element]) => {
const href = $(element).attr(attrName);
if (href === undefined) {
return;
}
$(element).attr(
attrName,
buildOptions.isStandalone
? href.replace(new RegExp(`^${(buildOptions.urlPathname ?? "/").replace(/\//g, "\\/")}`), "${url.resourcesPath}/build/")
: href.replace(/^\//, `${buildOptions.urlOrigin}/`)
);
})
);
if (Object.keys(cssGlobalsToDefine).length !== 0) {
$("head").prepend(
[
"",
"<style>",
generateCssCodeToDefineGlobals({
cssGlobalsToDefine,
buildOptions
}).cssCodeToPrependInHead,
"</style>",
""
].join("\n")
);
}
}
//FTL is no valid html, we can't insert with cheerio, we put placeholder for injecting later.
const replaceValueBySearchValue = {
'{ "x": "vIdLqMeOed9sdLdIdOxdK0d" }': fs
.readFileSync(pathJoin(__dirname, "ftl_object_to_js_code_declaring_an_object.ftl"))
.toString("utf8")
.match(/^<script>const _=((?:.|\n)+)<\/script>[\n]?$/)![1],
"<!-- xIdLqMeOedErIdLsPdNdI9dSlxI -->": [
"<#if scripts??>",
" <#list scripts as script>",
' <script src="${script}" type="text/javascript"></script>',
" </#list>",
"</#if>"
].join("\n")
};
$("head").prepend(
[
"<script>",
` window.${ftlValuesGlobalName}= ${objectKeys(replaceValueBySearchValue)[0]};`,
"</script>",
"",
objectKeys(replaceValueBySearchValue)[1]
].join("\n")
);
const partiallyFixedIndexHtmlCode = $.html();
function generateFtlFilesCode(params: { pageId: string }): {
ftlCode: string;
} {
const { pageId } = params;
const $ = cheerio.load(partiallyFixedIndexHtmlCode);
let ftlCode = $.html();
Object.entries({
...replaceValueBySearchValue,
//If updated, don't forget to change in the ftl script as well.
"PAGE_ID_xIgLsPgGId9D8e": pageId
}).map(([searchValue, replaceValue]) => (ftlCode = ftlCode.replace(searchValue, replaceValue)));
return { ftlCode };
}
return { generateFtlFilesCode };
}

View File

@ -1,33 +1,39 @@
import * as url from "url";
import * as fs from "fs";
import { join as pathJoin, dirname as pathDirname } from "path";
import { assert } from "tsafe/assert";
import { Reflect } from "tsafe/Reflect";
import type { BuildOptions } from "./BuildOptions";
export function generateJavaStackFiles(params: { version: string; themeName: string; homepage?: string; keycloakThemeBuildingDirPath: string }): {
export type BuildOptionsLike = {
themeName: string;
groupId: string;
artifactId?: string;
version: string;
};
{
const buildOptions = Reflect<BuildOptions>();
assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
}
export function generateJavaStackFiles(params: {
keycloakThemeBuildingDirPath: string;
doBundlesEmailTemplate: boolean;
buildOptions: BuildOptionsLike;
}): {
jarFilePath: string;
} {
const { themeName, version, homepage, keycloakThemeBuildingDirPath } = params;
const {
buildOptions: { groupId, themeName, version, artifactId },
keycloakThemeBuildingDirPath,
doBundlesEmailTemplate
} = params;
{
const { pomFileCode } = (function generatePomFileCode(): {
pomFileCode: string;
} {
const groupId = (() => {
const fallbackGroupId = `there.was.no.homepage.field.in.the.package.json.${themeName}`;
return (
(!homepage
? fallbackGroupId
: url
.parse(homepage)
.host?.replace(/:[0-9]+$/, "")
?.split(".")
.reverse()
.join(".") ?? fallbackGroupId) + ".keycloak"
);
})();
const artefactId = `${themeName}-keycloak-theme`;
const pomFileCode = [
`<?xml version="1.0"?>`,
`<project xmlns="http://maven.apache.org/POM/4.0.0"`,
@ -35,11 +41,11 @@ export function generateJavaStackFiles(params: { version: string; themeName: str
` xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">`,
` <modelVersion>4.0.0</modelVersion>`,
` <groupId>${groupId}</groupId>`,
` <artifactId>${artefactId}</artifactId>`,
` <artifactId>${artifactId}</artifactId>`,
` <version>${version}</version>`,
` <name>${artefactId}</name>`,
` <name>${artifactId}</name>`,
` <description />`,
`</project>`,
`</project>`
].join("\n");
return { pomFileCode };
@ -63,19 +69,19 @@ export function generateJavaStackFiles(params: { version: string; themeName: str
"themes": [
{
"name": themeName,
"types": ["login"],
},
],
"types": ["login", ...(doBundlesEmailTemplate ? ["email"] : [])]
}
]
},
null,
2,
2
),
"utf8",
),
"utf8"
)
);
}
return {
"jarFilePath": pathJoin(keycloakThemeBuildingDirPath, "target", `${themeName}-${version}.jar`),
"jarFilePath": pathJoin(keycloakThemeBuildingDirPath, "target", `${artifactId}-${version}.jar`)
};
}

View File

@ -0,0 +1,201 @@
import { transformCodebase } from "../tools/transformCodebase";
import * as fs from "fs";
import { join as pathJoin, basename as pathBasename } from "path";
import { replaceImportsFromStaticInJsCode } from "./replacers/replaceImportsFromStaticInJsCode";
import { replaceImportsInCssCode } from "./replacers/replaceImportsInCssCode";
import { generateFtlFilesCodeFactory, pageIds } from "./generateFtl";
import { downloadBuiltinKeycloakTheme } from "../download-builtin-keycloak-theme";
import { mockTestingResourcesCommonPath, mockTestingResourcesPath, mockTestingSubDirOfPublicDirBasename } from "../mockTestingResourcesPath";
import { isInside } from "../tools/isInside";
import type { BuildOptions } from "./BuildOptions";
import { assert } from "tsafe/assert";
import { Reflect } from "tsafe/Reflect";
import { getLogger } from "../tools/logger";
export type BuildOptionsLike = BuildOptionsLike.Standalone | BuildOptionsLike.ExternalAssets;
export namespace BuildOptionsLike {
export type Common = {
themeName: string;
extraPages?: string[];
extraThemeProperties?: string[];
isSilent: boolean;
};
export type Standalone = Common & {
isStandalone: true;
urlPathname: string | undefined;
};
export type ExternalAssets = ExternalAssets.SameDomain | ExternalAssets.DifferentDomains;
export namespace ExternalAssets {
export type CommonExternalAssets = Common & {
isStandalone: false;
};
export type SameDomain = CommonExternalAssets & {
areAppAndKeycloakServerSharingSameDomain: true;
};
export type DifferentDomains = CommonExternalAssets & {
areAppAndKeycloakServerSharingSameDomain: false;
urlOrigin: string;
urlPathname: string | undefined;
};
}
}
{
const buildOptions = Reflect<BuildOptions>();
assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
}
export async function generateKeycloakThemeResources(params: {
reactAppBuildDirPath: string;
keycloakThemeBuildingDirPath: string;
keycloakThemeEmailDirPath: string;
keycloakVersion: string;
buildOptions: BuildOptionsLike;
}): Promise<{ doBundlesEmailTemplate: boolean }> {
const { reactAppBuildDirPath, keycloakThemeBuildingDirPath, keycloakThemeEmailDirPath, keycloakVersion, buildOptions } = params;
const logger = getLogger({ isSilent: buildOptions.isSilent });
const themeDirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", buildOptions.themeName, "login");
let allCssGlobalsToDefine: Record<string, string> = {};
transformCodebase({
"destDirPath": buildOptions.isStandalone ? pathJoin(themeDirPath, "resources", "build") : reactAppBuildDirPath,
"srcDirPath": reactAppBuildDirPath,
"transformSourceCode": ({ filePath, sourceCode }) => {
//NOTE: Prevent cycles, excludes the folder we generated for debug in public/
if (
buildOptions.isStandalone &&
isInside({
"dirPath": pathJoin(reactAppBuildDirPath, mockTestingSubDirOfPublicDirBasename),
filePath
})
) {
return undefined;
}
if (/\.css?$/i.test(filePath)) {
if (!buildOptions.isStandalone) {
return undefined;
}
const { cssGlobalsToDefine, fixedCssCode } = replaceImportsInCssCode({
"cssCode": sourceCode.toString("utf8")
});
allCssGlobalsToDefine = {
...allCssGlobalsToDefine,
...cssGlobalsToDefine
};
return { "modifiedSourceCode": Buffer.from(fixedCssCode, "utf8") };
}
if (/\.js?$/i.test(filePath)) {
if (!buildOptions.isStandalone && buildOptions.areAppAndKeycloakServerSharingSameDomain) {
return undefined;
}
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
"jsCode": sourceCode.toString("utf8"),
buildOptions
});
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
}
return buildOptions.isStandalone ? { "modifiedSourceCode": sourceCode } : undefined;
}
});
let doBundlesEmailTemplate: boolean;
email: {
if (!fs.existsSync(keycloakThemeEmailDirPath)) {
logger.log(
[
`Not bundling email template because ${pathBasename(keycloakThemeEmailDirPath)} does not exist`,
`To start customizing the email template, run: 👉 npx create-keycloak-email-directory 👈`
].join("\n")
);
doBundlesEmailTemplate = false;
break email;
}
doBundlesEmailTemplate = true;
transformCodebase({
"srcDirPath": keycloakThemeEmailDirPath,
"destDirPath": pathJoin(themeDirPath, "..", "email")
});
}
const { generateFtlFilesCode } = generateFtlFilesCodeFactory({
"indexHtmlCode": fs.readFileSync(pathJoin(reactAppBuildDirPath, "index.html")).toString("utf8"),
"cssGlobalsToDefine": allCssGlobalsToDefine,
"buildOptions": buildOptions
});
[...pageIds, ...(buildOptions.extraPages ?? [])].forEach(pageId => {
const { ftlCode } = generateFtlFilesCode({ pageId });
fs.mkdirSync(themeDirPath, { "recursive": true });
fs.writeFileSync(pathJoin(themeDirPath, pageId), Buffer.from(ftlCode, "utf8"));
});
{
const tmpDirPath = pathJoin(themeDirPath, "..", "tmp_xxKdLpdIdLd");
await downloadBuiltinKeycloakTheme({
keycloakVersion,
"destDirPath": tmpDirPath,
isSilent: buildOptions.isSilent
});
const themeResourcesDirPath = pathJoin(themeDirPath, "resources");
transformCodebase({
"srcDirPath": pathJoin(tmpDirPath, "keycloak", "login", "resources"),
"destDirPath": themeResourcesDirPath
});
const reactAppPublicDirPath = pathJoin(reactAppBuildDirPath, "..", "public");
transformCodebase({
"srcDirPath": pathJoin(tmpDirPath, "keycloak", "common", "resources"),
"destDirPath": pathJoin(themeResourcesDirPath, pathBasename(mockTestingResourcesCommonPath))
});
transformCodebase({
"srcDirPath": themeResourcesDirPath,
"destDirPath": pathJoin(reactAppPublicDirPath, mockTestingResourcesPath)
});
const keycloakResourcesWithinPublicDirPath = pathJoin(reactAppPublicDirPath, mockTestingSubDirOfPublicDirBasename);
fs.writeFileSync(
pathJoin(keycloakResourcesWithinPublicDirPath, "README.txt"),
Buffer.from(
["This is just a test folder that helps develop", "the login and register page without having to run a Keycloak container"].join(" ")
)
);
fs.writeFileSync(pathJoin(keycloakResourcesWithinPublicDirPath, ".gitignore"), Buffer.from("*", "utf8"));
fs.rmSync(tmpDirPath, { recursive: true, force: true });
}
fs.writeFileSync(
pathJoin(themeDirPath, "theme.properties"),
Buffer.from(["parent=keycloak", ...(buildOptions.extraThemeProperties ?? [])].join("\n\n"), "utf8")
);
return { doBundlesEmailTemplate };
}

View File

@ -0,0 +1,61 @@
import * as fs from "fs";
import { join as pathJoin } from "path";
import { assert } from "tsafe/assert";
import { Reflect } from "tsafe/Reflect";
import type { BuildOptions } from "./BuildOptions";
export type BuildOptionsLike = {
themeName: string;
};
{
const buildOptions = Reflect<BuildOptions>();
assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
}
generateStartKeycloakTestingContainer.basename = "start_keycloak_testing_container.sh";
const containerName = "keycloak-testing-container";
/** Files for being able to run a hot reload keycloak container */
export function generateStartKeycloakTestingContainer(params: {
keycloakVersion: string;
keycloakThemeBuildingDirPath: string;
buildOptions: BuildOptionsLike;
}) {
const {
keycloakThemeBuildingDirPath,
keycloakVersion,
buildOptions: { themeName }
} = params;
const keycloakThemePath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", themeName).replace(/\\/g, "/");
fs.writeFileSync(
pathJoin(keycloakThemeBuildingDirPath, generateStartKeycloakTestingContainer.basename),
Buffer.from(
[
"#!/usr/bin/env bash",
"",
`docker rm ${containerName} || true`,
"",
`cd "${keycloakThemeBuildingDirPath.replace(/\\/g, "/")}"`,
"",
"docker run \\",
" -p 8080:8080 \\",
` --name ${containerName} \\`,
" -e KEYCLOAK_ADMIN=admin \\",
" -e KEYCLOAK_ADMIN_PASSWORD=admin \\",
" -e JAVA_OPTS=-Dkeycloak.profile=preview \\",
` -v "${keycloakThemePath}":"/opt/keycloak/themes/${themeName}":rw \\`,
` -it quay.io/keycloak/keycloak:${keycloakVersion} \\`,
` start-dev`,
""
].join("\n"),
"utf8"
),
{ "mode": 0o755 }
);
}

View File

@ -0,0 +1,8 @@
#!/usr/bin/env node
export * from "./keycloakify";
import { main } from "./keycloakify";
if (require.main === module) {
main().catch(e => console.error(e));
}

View File

@ -0,0 +1,139 @@
import { generateKeycloakThemeResources } from "./generateKeycloakThemeResources";
import { generateJavaStackFiles } from "./generateJavaStackFiles";
import { join as pathJoin, relative as pathRelative, basename as pathBasename } from "path";
import * as child_process from "child_process";
import { generateStartKeycloakTestingContainer } from "./generateStartKeycloakTestingContainer";
import * as fs from "fs";
import { readBuildOptions } from "./BuildOptions";
import { getLogger } from "../tools/logger";
import { getCliOptions } from "../tools/cliOptions";
import jar from "../tools/jar";
import { assert } from "tsafe/assert";
import type { Equals } from "tsafe";
const reactProjectDirPath = process.cwd();
export const keycloakThemeBuildingDirPath = pathJoin(reactProjectDirPath, "build_keycloak");
export const keycloakThemeEmailDirPath = pathJoin(keycloakThemeBuildingDirPath, "..", "keycloak_email");
export async function main() {
const { isSilent, hasExternalAssets } = getCliOptions(process.argv.slice(2));
const logger = getLogger({ isSilent });
logger.log("🔏 Building the keycloak theme...⌚");
const buildOptions = readBuildOptions({
"packageJson": fs.readFileSync(pathJoin(reactProjectDirPath, "package.json")).toString("utf8"),
"CNAME": (() => {
const cnameFilePath = pathJoin(reactProjectDirPath, "public", "CNAME");
if (!fs.existsSync(cnameFilePath)) {
return undefined;
}
return fs.readFileSync(cnameFilePath).toString("utf8");
})(),
"isExternalAssetsCliParamProvided": hasExternalAssets,
"isSilent": isSilent
});
const { doBundlesEmailTemplate } = await generateKeycloakThemeResources({
keycloakThemeBuildingDirPath,
keycloakThemeEmailDirPath,
"reactAppBuildDirPath": pathJoin(reactProjectDirPath, "build"),
buildOptions,
//We have to leave it at that otherwise we break our default theme.
//Problem is that we can't guarantee that the the old resources
//will still be available on the newer keycloak version.
"keycloakVersion": "11.0.3"
});
const { jarFilePath } = generateJavaStackFiles({
keycloakThemeBuildingDirPath,
doBundlesEmailTemplate,
buildOptions
});
switch (buildOptions.bundler) {
case "none":
logger.log("đŸ˜± Skipping bundling step, there will be no jar");
break;
case "keycloakify":
logger.log("đŸ«¶ Let keycloakify do its thang");
await jar({
"rootPath": pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources"),
"version": buildOptions.version,
"groupId": buildOptions.groupId,
"artifactId": buildOptions.artifactId,
"targetPath": jarFilePath
});
break;
case "mvn":
logger.log("đŸ«™ Run maven to deliver a jar");
child_process.execSync("mvn package", { "cwd": keycloakThemeBuildingDirPath });
break;
default:
assert<Equals<typeof buildOptions.bundler, never>>(false);
}
// We want, however, to test in a container running the latest Keycloak version
const containerKeycloakVersion = "20.0.1";
generateStartKeycloakTestingContainer({
keycloakThemeBuildingDirPath,
"keycloakVersion": containerKeycloakVersion,
buildOptions
});
logger.log(
[
"",
`✅ Your keycloak theme has been generated and bundled into ./${pathRelative(reactProjectDirPath, jarFilePath)} 🚀`,
`It is to be placed in "/opt/keycloak/providers" in the container running a quay.io/keycloak/keycloak Docker image.`,
"",
//TODO: Restore when we find a good Helm chart for Keycloak.
//"Using Helm (https://github.com/codecentric/helm-charts), edit to reflect:",
"",
"value.yaml: ",
" extraInitContainers: |",
" - name: realm-ext-provider",
" image: curlimages/curl",
" imagePullPolicy: IfNotPresent",
" command:",
" - sh",
" args:",
" - -c",
` - curl -L -f -S -o /extensions/${pathBasename(jarFilePath)} https://AN.URL.FOR/${pathBasename(jarFilePath)}`,
" volumeMounts:",
" - name: extensions",
" mountPath: /extensions",
" ",
" extraVolumeMounts: |",
" - name: extensions",
" mountPath: /opt/keycloak/providers",
" extraEnv: |",
" - name: KEYCLOAK_USER",
" value: admin",
" - name: KEYCLOAK_PASSWORD",
" value: xxxxxxxxx",
" - name: JAVA_OPTS",
" value: -Dkeycloak.profile=preview",
"",
"",
`To test your theme locally you can spin up a Keycloak ${containerKeycloakVersion} container image with the theme pre loaded by running:`,
"",
`👉 $ ./${pathRelative(reactProjectDirPath, pathJoin(keycloakThemeBuildingDirPath, generateStartKeycloakTestingContainer.basename))} 👈`,
"",
"Test with different Keycloak versions by editing the .sh file. see available versions here: https://quay.io/repository/keycloak/keycloak?tab=tags",
"",
"Once your container is up and running: ",
"- Log into the admin console 👉 http://localhost:8080/admin username: admin, password: admin 👈",
'- Create a realm named "myrealm"',
'- Create a client with ID: "myclient", "Root URL": "https://www.keycloak.org/app/" and "Valid redirect URIs": "https://www.keycloak.org/app/*"',
`- Select Login Theme: ${buildOptions.themeName} (don't forget to save at the bottom of the page)`,
`- Go to 👉 https://www.keycloak.org/app/ 👈 Click "Save" then "Sign in". You should see your login page`,
"",
"Video demoing this process: https://youtu.be/N3wlBoH4hKg",
""
].join("\n")
);
}

View File

@ -0,0 +1,86 @@
import { ftlValuesGlobalName } from "../ftlValuesGlobalName";
import type { BuildOptions } from "../BuildOptions";
import { assert } from "tsafe/assert";
import { is } from "tsafe/is";
import { Reflect } from "tsafe/Reflect";
export type BuildOptionsLike = BuildOptionsLike.Standalone | BuildOptionsLike.ExternalAssets;
export namespace BuildOptionsLike {
export type Standalone = {
isStandalone: true;
};
export type ExternalAssets = {
isStandalone: false;
urlOrigin: string;
};
}
{
const buildOptions = Reflect<BuildOptions>();
assert(!is<BuildOptions.ExternalAssets.CommonExternalAssets>(buildOptions));
assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
}
export function replaceImportsFromStaticInJsCode(params: { jsCode: string; buildOptions: BuildOptionsLike }): { fixedJsCode: string } {
/*
NOTE:
When we have urlOrigin defined it means that
we are building with --external-assets
so we have to make sur that the fixed js code will run
inside and outside keycloak.
When urlOrigin isn't defined we can assume the fixedJsCode
will always run in keycloak context.
*/
const { jsCode, buildOptions } = params;
const getReplaceArgs = (language: "js" | "css"): Parameters<typeof String.prototype.replace> => [
new RegExp(`([a-zA-Z_]+)\\.([a-zA-Z]+)=function\\(([a-zA-Z]+)\\){return"static\\/${language}\\/"`, "g"),
(...[, n, u, e]) => `
${n}[(function(){
var pd= Object.getOwnPropertyDescriptor(${n}, "p");
if( pd === undefined || pd.configurable ){
${
buildOptions.isStandalone
? `
Object.defineProperty(${n}, "p", {
get: function() { return window.${ftlValuesGlobalName}.url.resourcesPath; },
set: function (){}
});
`
: `
var p= "";
Object.defineProperty(${n}, "p", {
get: function() { return "${ftlValuesGlobalName}" in window ? "${buildOptions.urlOrigin}/" : p; },
set: function (value){ p = value;}
});
`
}
}
return "${u}";
})()] = function(${e}) { return "${buildOptions.isStandalone ? "/build/" : ""}static/${language}/"`
];
const fixedJsCode = jsCode
.replace(...getReplaceArgs("js"))
.replace(...getReplaceArgs("css"))
.replace(/([a-zA-Z]+\.[a-zA-Z]+)\+"static\//g, (...[, group]) =>
buildOptions.isStandalone
? `window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/`
: `("${ftlValuesGlobalName}" in window ? "${buildOptions.urlOrigin}/" : ${group}) + "static/`
)
//TODO: Write a test case for this
.replace(/".chunk.css",([a-zA-Z])+=([a-zA-Z]+\.[a-zA-Z]+)\+([a-zA-Z]+),/, (...[, group1, group2, group3]) =>
buildOptions.isStandalone
? `".chunk.css",${group1} = window.${ftlValuesGlobalName}.url.resourcesPath + "/build/" + ${group3},`
: `".chunk.css",${group1} = ("${ftlValuesGlobalName}" in window ? "${buildOptions.urlOrigin}/" : ${group2}) + ${group3},`
);
return { fixedJsCode };
}

View File

@ -0,0 +1,64 @@
import * as crypto from "crypto";
import type { BuildOptions } from "../BuildOptions";
import { assert } from "tsafe/assert";
import { is } from "tsafe/is";
import { Reflect } from "tsafe/Reflect";
export type BuildOptionsLike = {
urlPathname: string | undefined;
};
{
const buildOptions = Reflect<BuildOptions>();
assert(!is<BuildOptions.ExternalAssets.CommonExternalAssets>(buildOptions));
assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
}
export function replaceImportsInCssCode(params: { cssCode: string }): {
fixedCssCode: string;
cssGlobalsToDefine: Record<string, string>;
} {
const { cssCode } = params;
const cssGlobalsToDefine: Record<string, string> = {};
new Set(cssCode.match(/url\(["']?\/[^/][^)"']+["']?\)[^;}]*/g) ?? []).forEach(
match => (cssGlobalsToDefine["url" + crypto.createHash("sha256").update(match).digest("hex").substring(0, 15)] = match)
);
let fixedCssCode = cssCode;
Object.keys(cssGlobalsToDefine).forEach(
cssVariableName =>
//NOTE: split/join pattern ~ replace all
(fixedCssCode = fixedCssCode.split(cssGlobalsToDefine[cssVariableName]).join(`var(--${cssVariableName})`))
);
return { fixedCssCode, cssGlobalsToDefine };
}
export function generateCssCodeToDefineGlobals(params: { cssGlobalsToDefine: Record<string, string>; buildOptions: BuildOptionsLike }): {
cssCodeToPrependInHead: string;
} {
const { cssGlobalsToDefine, buildOptions } = params;
return {
"cssCodeToPrependInHead": [
":root {",
...Object.keys(cssGlobalsToDefine)
.map(cssVariableName =>
[
`--${cssVariableName}:`,
cssGlobalsToDefine[cssVariableName].replace(
new RegExp(`url\\(${(buildOptions.urlPathname ?? "/").replace(/\//g, "\\/")}`, "g"),
"url(${url.resourcesPath}/build/"
)
].join(" ")
)
.map(line => ` ${line};`),
"}"
].join("\n")
};
}

View File

@ -0,0 +1,47 @@
import type { BuildOptions } from "../BuildOptions";
import { assert } from "tsafe/assert";
import { is } from "tsafe/is";
import { Reflect } from "tsafe/Reflect";
export type BuildOptionsLike = BuildOptionsLike.Standalone | BuildOptionsLike.ExternalAssets;
export namespace BuildOptionsLike {
export type Common = {
urlPathname: string | undefined;
};
export type Standalone = Common & {
isStandalone: true;
};
export type ExternalAssets = Common & {
isStandalone: false;
urlOrigin: string;
};
}
{
const buildOptions = Reflect<BuildOptions>();
assert(!is<BuildOptions.ExternalAssets.CommonExternalAssets>(buildOptions));
assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
}
export function replaceImportsInInlineCssCode(params: { cssCode: string; buildOptions: BuildOptionsLike }): {
fixedCssCode: string;
} {
const { cssCode, buildOptions } = params;
const fixedCssCode = cssCode.replace(
buildOptions.urlPathname === undefined
? /url\(["']?\/([^/][^)"']+)["']?\)/g
: new RegExp(`url\\(["']?${buildOptions.urlPathname}([^)"']+)["']?\\)`, "g"),
(...[, group]) =>
`url(${
buildOptions.isStandalone ? "${url.resourcesPath}/build/" + group : buildOptions.urlOrigin + (buildOptions.urlPathname ?? "/") + group
})`
);
return { fixedCssCode };
}

View File

@ -1,102 +0,0 @@
import { execSync } from "child_process";
import { join as pathJoin, relative as pathRelative } from "path";
import * as fs from "fs";
const keycloakifyDirPath = pathJoin(__dirname, "..", "..");
fs.writeFileSync(
pathJoin(keycloakifyDirPath, "dist", "package.json"),
Buffer.from(
JSON.stringify(
(() => {
const packageJsonParsed = JSON.parse(fs.readFileSync(pathJoin(keycloakifyDirPath, "package.json")).toString("utf8"));
return {
...packageJsonParsed,
"main": packageJsonParsed["main"].replace(/^dist\//, ""),
"types": packageJsonParsed["types"].replace(/^dist\//, ""),
};
})(),
null,
2,
),
"utf8",
),
);
const commonThirdPartyDeps = (() => {
const namespaceModuleNames = ["@emotion"];
const standaloneModuleNames = ["react", "@types/react", "powerhooks", "tss-react", "evt"];
return [
...namespaceModuleNames
.map(namespaceModuleName =>
fs
.readdirSync(pathJoin(keycloakifyDirPath, "node_modules", namespaceModuleName))
.map(submoduleName => `${namespaceModuleName}/${submoduleName}`),
)
.reduce((prev, curr) => [...prev, ...curr], []),
...standaloneModuleNames,
];
})();
const yarnHomeDirPath = pathJoin(keycloakifyDirPath, ".yarn_home");
execSync(["rm -rf", "mkdir"].map(cmd => `${cmd} ${yarnHomeDirPath}`).join(" && "));
const execYarnLink = (params: { targetModuleName?: string; cwd: string }) => {
const { targetModuleName, cwd } = params;
const cmd = ["yarn", "link", ...(targetModuleName !== undefined ? [targetModuleName] : [])].join(" ");
console.log(`$ cd ${pathRelative(keycloakifyDirPath, cwd) || "."} && ${cmd}`);
execSync(cmd, {
cwd,
"env": {
...process.env,
"HOME": yarnHomeDirPath,
},
});
};
const testAppNames = ["keycloakify-demo-app"] as const;
const getTestAppPath = (testAppName: typeof testAppNames[number]) => pathJoin(keycloakifyDirPath, "..", testAppName);
testAppNames.forEach(testAppName => execSync("yarn install", { "cwd": getTestAppPath(testAppName) }));
console.log("=== Linking common dependencies ===");
const total = commonThirdPartyDeps.length;
let current = 0;
commonThirdPartyDeps.forEach(commonThirdPartyDep => {
current++;
console.log(`${current}/${total} ${commonThirdPartyDep}`);
const localInstallPath = pathJoin(
...[keycloakifyDirPath, "node_modules", ...(commonThirdPartyDep.startsWith("@") ? commonThirdPartyDep.split("/") : [commonThirdPartyDep])],
);
execYarnLink({ "cwd": localInstallPath });
testAppNames.forEach(testAppName =>
execYarnLink({
"cwd": getTestAppPath(testAppName),
"targetModuleName": commonThirdPartyDep,
}),
);
});
console.log("=== Linking in house dependencies ===");
execYarnLink({ "cwd": pathJoin(keycloakifyDirPath, "dist") });
testAppNames.forEach(testAppName =>
execYarnLink({
"cwd": getTestAppPath(testAppName),
"targetModuleName": "keycloakify",
}),
);

View File

@ -0,0 +1,5 @@
import { pathJoin } from "./tools/pathJoin";
export const mockTestingSubDirOfPublicDirBasename = "keycloak_static";
export const mockTestingResourcesPath = pathJoin(mockTestingSubDirOfPublicDirBasename, "resources");
export const mockTestingResourcesCommonPath = pathJoin(mockTestingResourcesPath, "resources_common");

View File

@ -0,0 +1,47 @@
import { getLatestsSemVersionedTagFactory } from "./tools/octokit-addons/getLatestsSemVersionedTag";
import { Octokit } from "@octokit/rest";
import cliSelect from "cli-select";
export async function promptKeycloakVersion() {
const { getLatestsSemVersionedTag } = (() => {
const { octokit } = (() => {
const githubToken = process.env.GITHUB_TOKEN;
const octokit = new Octokit(githubToken === undefined ? undefined : { "auth": githubToken });
return { octokit };
})();
const { getLatestsSemVersionedTag } = getLatestsSemVersionedTagFactory({ octokit });
return { getLatestsSemVersionedTag };
})();
console.log("Initialize the directory with email template from which keycloak version?");
const tags = [
...(await getLatestsSemVersionedTag({
"count": 10,
"doIgnoreBeta": true,
"owner": "keycloak",
"repo": "keycloak"
}).then(arr => arr.map(({ tag }) => tag))),
"11.0.3"
];
if (process.env["GITHUB_ACTIONS"] === "true") {
return { "keycloakVersion": tags[0] };
}
const { value: keycloakVersion } = await cliSelect<string>({
"values": tags
}).catch(() => {
console.log("Aborting");
process.exit(-1);
});
console.log(keycloakVersion);
return { keycloakVersion };
}

View File

@ -0,0 +1,73 @@
export type NpmModuleVersion = {
major: number;
minor: number;
patch: number;
betaPreRelease?: number;
};
export namespace NpmModuleVersion {
export function parse(versionStr: string): NpmModuleVersion {
const match = versionStr.match(/^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-beta.([0-9]+))?/);
if (!match) {
throw new Error(`${versionStr} is not a valid NPM version`);
}
return {
"major": parseInt(match[1]),
"minor": parseInt(match[2]),
"patch": parseInt(match[3]),
...(() => {
const str = match[4];
return str === undefined ? {} : { "betaPreRelease": parseInt(str) };
})()
};
}
export function stringify(v: NpmModuleVersion) {
return `${v.major}.${v.minor}.${v.patch}${v.betaPreRelease === undefined ? "" : `-beta.${v.betaPreRelease}`}`;
}
/**
*
* v1 < v2 => -1
* v1 === v2 => 0
* v1 > v2 => 1
*
*/
export function compare(v1: NpmModuleVersion, v2: NpmModuleVersion): -1 | 0 | 1 {
const sign = (diff: number): -1 | 0 | 1 => (diff === 0 ? 0 : diff < 0 ? -1 : 1);
const noUndefined = (n: number | undefined) => n ?? Infinity;
for (const level of ["major", "minor", "patch", "betaPreRelease"] as const) {
if (noUndefined(v1[level]) !== noUndefined(v2[level])) {
return sign(noUndefined(v1[level]) - noUndefined(v2[level]));
}
}
return 0;
}
/*
console.log(compare(parse("3.0.0-beta.3"), parse("3.0.0")) === -1 )
console.log(compare(parse("3.0.0-beta.3"), parse("3.0.0-beta.4")) === -1 )
console.log(compare(parse("3.0.0-beta.3"), parse("4.0.0")) === -1 )
*/
export function bumpType(params: { versionBehindStr: string; versionAheadStr: string }): "major" | "minor" | "patch" | "betaPreRelease" | "same" {
const versionAhead = parse(params.versionAheadStr);
const versionBehind = parse(params.versionBehindStr);
if (compare(versionBehind, versionAhead) === 1) {
throw new Error(`Version regression ${versionBehind} -> ${versionAhead}`);
}
for (const level of ["major", "minor", "patch", "betaPreRelease"] as const) {
if (versionBehind[level] !== versionAhead[level]) {
return level;
}
}
return "same";
}
}

View File

@ -0,0 +1,15 @@
import parseArgv from "minimist";
export type CliOptions = {
isSilent: boolean;
hasExternalAssets: boolean;
};
export const getCliOptions = (processArgv: string[]): CliOptions => {
const argv = parseArgv(processArgv);
return {
isSilent: typeof argv["silent"] === "boolean" ? argv["silent"] : false,
hasExternalAssets: typeof argv["external-assets"] === "boolean" ? argv["external-assets"] : false
};
};

54
src/bin/tools/crc32.ts Normal file
View File

@ -0,0 +1,54 @@
import { Readable } from "stream";
const crc32tab = [
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
];
/**
*
* @param input either a byte stream, a string or a buffer, you want to have the checksum for
* @returns a promise for a checksum (uint32)
*/
export function crc32(input: Readable | String | Buffer): Promise<number> {
if (typeof input === "string") {
let crc = ~0;
for (let i = 0; i < input.length; i++) crc = (crc >>> 8) ^ crc32tab[(crc ^ input.charCodeAt(i)) & 0xff];
return Promise.resolve((crc ^ -1) >>> 0);
} else if (input instanceof Buffer) {
let crc = ~0;
for (let i = 0; i < input.length; i++) crc = (crc >>> 8) ^ crc32tab[(crc ^ input[i]) & 0xff];
return Promise.resolve((crc ^ -1) >>> 0);
} else if (input instanceof Readable) {
return new Promise<number>((resolve, reject) => {
let crc = ~0;
input.on("end", () => resolve((crc ^ -1) >>> 0));
input.on("error", e => reject(e));
input.on("data", (chunk: Buffer) => {
for (let i = 0; i < chunk.length; i++) crc = (crc >>> 8) ^ crc32tab[(crc ^ chunk[i]) & 0xff];
});
});
} else {
throw new Error("Unsupported input " + typeof input);
}
}

61
src/bin/tools/deflate.ts Normal file
View File

@ -0,0 +1,61 @@
import { PassThrough, Readable, TransformCallback, Writable } from "stream";
import { pipeline } from "stream/promises";
import { deflateRaw as deflateRawCb, createDeflateRaw } from "zlib";
import { promisify } from "util";
import { crc32 } from "./crc32";
import tee from "./tee";
const deflateRaw = promisify(deflateRawCb);
/**
* A stream transformer that records the number of bytes
* passed in its `size` property.
*/
class ByteCounter extends PassThrough {
size: number = 0;
_transform(chunk: any, encoding: BufferEncoding, callback: TransformCallback) {
if ("length" in chunk) this.size += chunk.length;
super._transform(chunk, encoding, callback);
}
}
/**
* @param data buffer containing the data to be compressed
* @returns a buffer containing the compressed/deflated data and the crc32 checksum
* of the source data
*/
export async function deflateBuffer(data: Buffer) {
const [deflated, checksum] = await Promise.all([deflateRaw(data), crc32(data)]);
return { deflated, crc32: checksum };
}
/**
* @param input a byte stream, containing data to be compressed
* @param sink a method that will accept chunks of compressed data; We don't pass
* a writable here, since we don't want the writablestream to be closed after
* a single file
* @returns a promise, which will resolve with the crc32 checksum and the
* compressed size
*/
export async function deflateStream(input: Readable, sink: (chunk: Buffer) => void) {
const deflateWriter = new Writable({
write(chunk, _, callback) {
sink(chunk);
callback();
}
});
// tee the input stream, so we can compress and calc crc32 in parallel
const [rs1, rs2] = tee(input);
const byteCounter = new ByteCounter();
const [_, crc] = await Promise.all([
// pipe input into zip compressor, count the bytes
// returned and pass compressed data to the sink
pipeline(rs1, createDeflateRaw(), byteCounter, deflateWriter),
// calc checksum
crc32(rs2)
]);
return { crc32: crc, compressedSize: byteCounter.size };
}

View File

@ -1,32 +1,275 @@
import { basename as pathBasename, join as pathJoin } from "path";
import { execSync } from "child_process";
import fs from "fs";
import { dirname as pathDirname, basename as pathBasename, join as pathJoin, join } from "path";
import { createReadStream, createWriteStream } from "fs";
import { stat, mkdir, unlink, writeFile } from "fs/promises";
import { transformCodebase } from "./transformCodebase";
import { rm_rf, rm, rm_r } from "./rm";
import { createHash } from "crypto";
import fetch from "make-fetch-happen";
import { createInflateRaw } from "zlib";
import type { Readable } from "stream";
import { homedir } from "os";
import { FetchOptions } from "make-fetch-happen";
import { exec as execCallback } from "child_process";
import { promisify } from "util";
/** assert url ends with .zip */
export function downloadAndUnzip(params: { url: string; destDirPath: string; pathOfDirToExtractInArchive?: string }) {
const { url, destDirPath, pathOfDirToExtractInArchive } = params;
const exec = promisify(execCallback);
const tmpDirPath = pathJoin(destDirPath, "..", "tmp_xxKdOxnEdx");
const zipFilePath = pathBasename(url);
rm_rf(tmpDirPath);
fs.mkdirSync(tmpDirPath, { "recursive": true });
execSync(`curl -L ${url} -o ${zipFilePath}`, { "cwd": tmpDirPath });
execSync(`unzip ${zipFilePath}${pathOfDirToExtractInArchive === undefined ? "" : ` "${pathOfDirToExtractInArchive}/*"`}`, {
"cwd": tmpDirPath,
});
rm(pathBasename(url), { "cwd": tmpDirPath });
transformCodebase({
"srcDirPath": pathOfDirToExtractInArchive === undefined ? tmpDirPath : pathJoin(tmpDirPath, pathOfDirToExtractInArchive),
destDirPath,
});
rm_r(tmpDirPath);
function hash(s: string) {
return createHash("sha256").update(s).digest("hex");
}
async function maybeStat(path: string) {
try {
return await stat(path);
} catch (error) {
if ((error as Error & { code: string }).code === "ENOENT") return undefined;
throw error;
}
}
/**
* Get an npm configuration value as string, undefined if not set.
*
* @param key
* @returns string or undefined
*/
async function getNmpConfig(key: string): Promise<string | undefined> {
const { stdout } = await exec(`npm config get ${key}`);
const value = stdout.trim();
return value && value !== "null" ? value : undefined;
}
/**
* Get proxy configuration from npm config files. Note that we don't care about
* proxy config in env vars, because make-fetch-happen will do that for us.
*
* @returns proxy configuration
*/
async function getNpmProxyConfig(): Promise<Pick<FetchOptions, "proxy" | "noProxy">> {
const proxy = (await getNmpConfig("https-proxy")) ?? (await getNmpConfig("proxy"));
const noProxy = (await getNmpConfig("noproxy")) ?? (await getNmpConfig("no-proxy"));
return { proxy, noProxy };
}
/**
* Download a file from `url` to `dir`. Will try to avoid downloading existing
* files by using the cache directory ~/.keycloakify/cache
*
* If the target directory does not exist, it will be created.
*
* If the target file exists, it will be overwritten.
*
* We use make-fetch-happen's internal file cache here, so we don't need to
* worry about redownloading the same file over and over. Unfortunately, that
* cache does not have a single file per entry, but bundles and indexes them,
* so we still need to write the contents to the target directory (possibly
* over and over), cause the current unzip implementation wants random access.
*
* @param url download url
* @param dir target directory
* @param filename target filename
* @returns promise for the full path of the downloaded file
*/
async function download(url: string, dir: string, filename: string): Promise<string> {
const proxyOpts = await getNpmProxyConfig();
const cacheRoot = process.env.XDG_CACHE_HOME ?? homedir();
const cachePath = join(cacheRoot, ".keycloakify/cache");
const opts: FetchOptions = { cachePath, ...proxyOpts };
const response = await fetch(url, opts);
const filepath = pathJoin(dir, filename);
await mkdir(dir, { recursive: true });
await writeFile(filepath, response.body);
return filepath;
}
/**
* @typedef
* @type MultiError = Error & { cause: Error[] }
*/
/**
* Extract the archive `zipFile` into the directory `dir`. If `archiveDir` is given,
* only that directory will be extracted, stripping the given path components.
*
* If dir does not exist, it will be created.
*
* If any archive file exists, it will be overwritten.
*
* Will unzip using all available nodejs worker threads.
*
* Will try to clean up extracted files on failure.
*
* If unpacking fails, will either throw an regular error, or
* possibly an `MultiError`, which contains a `cause` field with
* a number of root cause errors.
*
* Warning this method is not optimized for continuous reading of the zip
* archive, but is a trade-off between simplicity and allowing extraction
* of a single directory from the archive.
*
* @param zipFile the file to unzip
* @param dir the target directory
* @param archiveDir if given, unpack only files from this archive directory
* @throws {MultiError} error
* @returns Promise for a list of full file paths pointing to actually extracted files
*/
async function unzip(zipFile: string, dir: string, archiveDir?: string): Promise<string[]> {
await mkdir(dir, { recursive: true });
const promises: Promise<string>[] = [];
// Iterate over all files in the zip, skip files which are not in archiveDir,
// if given.
for await (const record of iterateZipArchive(zipFile)) {
const { path: recordPath, createReadStream: createRecordReadStream } = record;
const filePath = pathJoin(dir, recordPath);
const parent = pathDirname(filePath);
if (archiveDir && !recordPath.startsWith(archiveDir)) continue;
promises.push(
new Promise<string>(async (resolve, reject) => {
await mkdir(parent, { recursive: true });
// Pull the file out of the archive, write it to the target directory
const input = createRecordReadStream();
const output = createWriteStream(filePath);
output.on("error", e => reject(Object.assign(e, { filePath })));
output.on("finish", () => resolve(filePath));
input.pipe(output);
})
);
}
// Wait until _all_ files are either extracted or failed
const results = await Promise.allSettled(promises);
const success = results.filter(r => r.status === "fulfilled").map(r => (r as PromiseFulfilledResult<string>).value);
const failure = results.filter(r => r.status === "rejected").map(r => (r as PromiseRejectedResult).reason);
// If any extraction failed, try to clean up, then throw a MultiError,
// which has a `cause` field, containing a list of root cause errors.
if (failure.length) {
await Promise.all(success.map(path => unlink(path)));
await Promise.all(failure.map(e => e && e.path && unlink(e.path as string)));
const e = new Error("Failed to extract: " + failure.map(e => e.message).join(";"));
(e as any).cause = failure;
throw e;
}
return success;
}
/**
*
* @param file file to read
* @param start first byte to read
* @param end last byte to read
* @returns Promise of a buffer of read bytes
*/
async function readFileChunk(file: string, start: number, end: number): Promise<Buffer> {
const chunks: Buffer[] = [];
return new Promise((resolve, reject) => {
const stream = createReadStream(file, { start, end });
stream.on("error", e => reject(e));
stream.on("end", () => resolve(Buffer.concat(chunks)));
stream.on("data", chunk => chunks.push(chunk as Buffer));
});
}
type ZipRecord = {
path: string;
createReadStream: () => Readable;
compressionMethod: "deflate" | undefined;
};
type ZipRecordGenerator = AsyncGenerator<ZipRecord, void, unknown>;
/**
* Iterate over all records of a zipfile, and yield a ZipRecord.
* Use `record.createReadStream()` to actually read the file.
*
* Warning this method will only work with single-disk zip files.
* Warning this method may fail if the zip archive has an crazy amount
* of files and the central directory is not fully contained within the
* last 65k bytes of the zip file.
*
* @param zipFile
* @returns AsyncGenerator which will yield ZipRecords
*/
async function* iterateZipArchive(zipFile: string): ZipRecordGenerator {
// Need to know zip file size before we can do anything else
const { size } = await stat(zipFile);
const chunkSize = 65_535 + 22 + 1; // max comment size + end header size + wiggle
// Read last ~65k bytes. Zip files have an comment up to 65_535 bytes at the very end,
// before that comes the zip central directory end header.
let chunk = await readFileChunk(zipFile, size - chunkSize, size);
const unread = size - chunk.length;
let i = chunk.length - 4;
let found = false;
// Find central directory end header, reading backwards from the end
while (!found && i-- > 0) if (chunk[i] === 0x50 && chunk.readUInt32LE(i) === 0x06054b50) found = true;
if (!found) throw new Error("Not a zip file");
// This method will fail on a multi-disk zip, so bail early.
if (chunk.readUInt16LE(i + 4) !== 0) throw new Error("Multi-disk zip not supported");
let nFiles = chunk.readUint16LE(i + 10);
// Get the position of the central directory
const directorySize = chunk.readUint32LE(i + 12);
const directoryOffset = chunk.readUint32LE(i + 16);
if (directoryOffset === 0xffff_ffff) throw new Error("zip64 not supported");
if (directoryOffset > size) throw new Error(`Central directory offset ${directoryOffset} is outside file`);
i = directoryOffset - unread;
// If i < 0, it means that the central directory is not contained within `chunk`
if (i < 0) {
chunk = await readFileChunk(zipFile, directoryOffset, directoryOffset + directorySize);
i = 0;
}
// Now iterate the central directory records, yield an `ZipRecord` for every entry
while (nFiles-- > 0) {
// Check for marker bytes
if (chunk.readUInt32LE(i) !== 0x02014b50) throw new Error("No central directory record at position " + (unread + i));
const compressionMethod = ({ 8: "deflate" } as const)[chunk.readUint16LE(i + 10)];
const compressedFileSize = chunk.readUint32LE(i + 20);
const filenameLength = chunk.readUint16LE(i + 28);
const extraLength = chunk.readUint16LE(i + 30);
const commentLength = chunk.readUint16LE(i + 32);
// Start of the actual content byte stream is after the 'local' record header,
// which is 30 bytes long plus filename and extra field
const start = chunk.readUint32LE(i + 42) + 30 + filenameLength + extraLength;
const end = start + compressedFileSize;
const filename = chunk.slice(i + 46, i + 46 + filenameLength).toString("utf-8");
const createRecordReadStream = () => {
const input = createReadStream(zipFile, { start, end });
if (compressionMethod === "deflate") {
const inflate = createInflateRaw();
input.pipe(inflate);
return inflate;
}
return input;
};
if (end > start) yield { path: filename, createReadStream: createRecordReadStream, compressionMethod };
// advance pointer to next central directory entry
i += 46 + filenameLength + extraLength + commentLength;
}
}
export async function downloadAndUnzip({
url,
destDirPath,
pathOfDirToExtractInArchive,
cacheDirPath
}: {
isSilent: boolean;
url: string;
destDirPath: string;
pathOfDirToExtractInArchive?: string;
cacheDirPath: string;
}) {
const downloadHash = hash(JSON.stringify({ url, pathOfDirToExtractInArchive })).substring(0, 15);
const extractDirPath = pathJoin(cacheDirPath, `_${downloadHash}`);
const filename = pathBasename(url);
const zipFilepath = await download(url, cacheDirPath, filename);
const zipMtime = (await stat(zipFilepath)).mtimeMs;
const unzipMtime = (await maybeStat(extractDirPath))?.mtimeMs;
if (!unzipMtime || zipMtime > unzipMtime) await unzip(zipFilepath, extractDirPath, pathOfDirToExtractInArchive);
const srcDirPath = pathOfDirToExtractInArchive === undefined ? extractDirPath : pathJoin(extractDirPath, pathOfDirToExtractInArchive);
transformCodebase({ srcDirPath, destDirPath });
}

View File

@ -1,9 +1,17 @@
import { getProjectRoot } from "./getProjectRoot";
import { join as pathJoin } from "path";
import child_process from "child_process";
import { constants } from "fs";
import { chmod, stat } from "fs/promises";
Object.entries<string>(require(pathJoin(getProjectRoot(), "package.json"))["bin"]).forEach(([, scriptPath]) =>
child_process.execSync(`chmod +x ${scriptPath}`, {
"cwd": getProjectRoot(),
}),
);
(async () => {
const { bin } = await import(pathJoin(getProjectRoot(), "package.json"));
const promises = Object.values<string>(bin).map(async scriptPath => {
const fullPath = pathJoin(getProjectRoot(), scriptPath);
const oldMode = (await stat(fullPath)).mode;
const newMode = oldMode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH;
await chmod(fullPath, newMode);
});
await Promise.all(promises);
})();

102
src/bin/tools/jar.ts Normal file
View File

@ -0,0 +1,102 @@
import { Readable, Transform } from "stream";
import { dirname, relative, sep } from "path";
import { createWriteStream } from "fs";
import walk from "./walk";
import type { ZipSource } from "./zip";
import zip from "./zip";
import { mkdir } from "fs/promises";
/** Trim leading whitespace from every line */
const trimIndent = (s: string) => s.replace(/(\n)\s+/g, "$1");
type JarArgs = {
rootPath: string;
targetPath: string;
groupId: string;
artifactId: string;
version: string;
};
/**
* Create a jar archive, using the resources found at `rootPath` (a directory) and write the
* archive to `targetPath` (a file). Use `groupId`, `artifactId` and `version` to define
* the contents of the pom.properties file which is going to be added to the archive.
*/
export default async function jar({ groupId, artifactId, version, rootPath, targetPath }: JarArgs) {
const manifest: ZipSource = {
path: "META-INF/MANIFEST.MF",
data: Buffer.from(
trimIndent(
`Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Keycloakify
Built-By: unknown
Build-Jdk: 19.0.0`
)
)
};
const pomProps: ZipSource = {
path: `META-INF/maven/${groupId}/${artifactId}/pom.properties`,
data: Buffer.from(
trimIndent(
`# Generated by keycloakify
# ${new Date()}
artifactId=${artifactId}
groupId=${groupId}
version=${version}`
)
)
};
/**
* Convert every path entry to a ZipSource record, and when all records are
* processed, append records for MANIFEST.mf and pom.properties
*/
const pathToRecord = () =>
new Transform({
objectMode: true,
transform: function (fsPath, _, cb) {
const path = relative(rootPath, fsPath).split(sep).join("/");
this.push({ path, fsPath });
cb();
},
final: function () {
this.push(manifest);
this.push(pomProps);
this.push(null);
}
});
await mkdir(dirname(targetPath), { recursive: true });
// Create an async pipeline, wait until everything is fully processed
await new Promise<void>((resolve, reject) => {
// walk all files in `rootPath` recursively
Readable.from(walk(rootPath))
// transform every path into a ZipSource object
.pipe(pathToRecord())
// let the zip lib convert all ZipSource objects into a byte stream
.pipe(zip())
// write that byte stream to targetPath
.pipe(createWriteStream(targetPath, { encoding: "binary" }))
.on("finish", () => resolve())
.on("error", e => reject(e));
});
}
/**
* Standalone usage, call e.g. `ts-node jar.ts dirWithSources some-jar.jar`
*/
if (require.main === module) {
const main = () =>
jar({
rootPath: process.argv[2],
targetPath: process.argv[3],
artifactId: process.env.ARTIFACT_ID ?? "artifact",
groupId: process.env.GROUP_ID ?? "group",
version: process.env.VERSION ?? "1.0.0"
});
main().catch(e => console.error(e));
}

27
src/bin/tools/logger.ts Normal file
View File

@ -0,0 +1,27 @@
type LoggerOpts = {
force?: boolean;
};
type Logger = {
log: (message: string, opts?: LoggerOpts) => void;
warn: (message: string) => void;
error: (message: string) => void;
};
export const getLogger = ({ isSilent }: { isSilent?: boolean } = {}): Logger => {
return {
log: (message, { force } = {}) => {
if (isSilent && !force) {
return;
}
console.log(message);
},
warn: message => {
console.warn(message);
},
error: message => {
console.error(message);
}
};
};

View File

@ -0,0 +1,40 @@
import { listTagsFactory } from "./listTags";
import type { Octokit } from "@octokit/rest";
import { NpmModuleVersion } from "../NpmModuleVersion";
export function getLatestsSemVersionedTagFactory(params: { octokit: Octokit }) {
const { octokit } = params;
async function getLatestsSemVersionedTag(params: { owner: string; repo: string; doIgnoreBeta: boolean; count: number }): Promise<
{
tag: string;
version: NpmModuleVersion;
}[]
> {
const { owner, repo, doIgnoreBeta, count } = params;
const semVersionedTags: { tag: string; version: NpmModuleVersion }[] = [];
const { listTags } = listTagsFactory({ octokit });
for await (const tag of listTags({ owner, repo })) {
let version: NpmModuleVersion;
try {
version = NpmModuleVersion.parse(tag.replace(/^[vV]?/, ""));
} catch {
continue;
}
if (doIgnoreBeta && version.betaPreRelease !== undefined) {
continue;
}
semVersionedTags.push({ tag, version });
}
return semVersionedTags.sort(({ version: vX }, { version: vY }) => NpmModuleVersion.compare(vY, vX)).slice(0, count);
}
return { getLatestsSemVersionedTag };
}

View File

@ -0,0 +1,49 @@
import type { Octokit } from "@octokit/rest";
const per_page = 99;
export function listTagsFactory(params: { octokit: Octokit }) {
const { octokit } = params;
const octokit_repo_listTags = async (params: { owner: string; repo: string; per_page: number; page: number }) => {
return octokit.repos.listTags(params);
};
async function* listTags(params: { owner: string; repo: string }): AsyncGenerator<string> {
const { owner, repo } = params;
let page = 1;
while (true) {
const resp = await octokit_repo_listTags({
owner,
repo,
per_page,
"page": page++
});
for (const branch of resp.data.map(({ name }) => name)) {
yield branch;
}
if (resp.data.length < 99) {
break;
}
}
}
/** Returns the same "latest" tag as deno.land/x, not actually the latest though */
async function getLatestTag(params: { owner: string; repo: string }): Promise<string | undefined> {
const { owner, repo } = params;
const itRes = await listTags({ owner, repo }).next();
if (itRes.done) {
return undefined;
}
return itRes.value;
}
return { listTags, getLatestTag };
}

View File

@ -1,31 +0,0 @@
import { execSync } from "child_process";
function rmInternal(params: { pathToRemove: string; args: string | undefined; cwd: string | undefined }) {
const { pathToRemove, args, cwd } = params;
execSync(`rm ${args ? `-${args} ` : ""}${pathToRemove.replace(/ /g, "\\ ")}`, cwd !== undefined ? { cwd } : undefined);
}
export function rm(pathToRemove: string, options?: { cwd: string }) {
rmInternal({
pathToRemove,
"args": undefined,
"cwd": options?.cwd,
});
}
export function rm_r(pathToRemove: string, options?: { cwd: string }) {
rmInternal({
pathToRemove,
"args": "r",
"cwd": options?.cwd,
});
}
export function rm_rf(pathToRemove: string, options?: { cwd: string }) {
rmInternal({
pathToRemove,
"args": "rf",
"cwd": options?.cwd,
});
}

37
src/bin/tools/tee.ts Normal file
View File

@ -0,0 +1,37 @@
import { PassThrough, Readable } from "stream";
export default function tee(input: Readable) {
const a = new PassThrough();
const b = new PassThrough();
let aFull = false;
let bFull = false;
a.on("drain", () => {
aFull = false;
if (!aFull && !bFull) input.resume();
});
b.on("drain", () => {
bFull = false;
if (!aFull && !bFull) input.resume();
});
input.on("error", e => {
a.emit("error", e);
b.emit("error", e);
});
input.on("data", chunk => {
aFull = !a.write(chunk);
bFull = !b.write(chunk);
if (aFull || bFull) input.pause();
});
input.on("end", () => {
a.end();
b.end();
});
return [a, b] as const;
}

View File

@ -16,8 +16,8 @@ export function transformCodebase(params: { srcDirPath: string; destDirPath: str
srcDirPath,
destDirPath,
transformSourceCode = id<TransformSourceCode>(({ sourceCode }) => ({
"modifiedSourceCode": sourceCode,
})),
"modifiedSourceCode": sourceCode
}))
} = params;
for (const file_relative_path of crawl(srcDirPath)) {
@ -25,7 +25,7 @@ export function transformCodebase(params: { srcDirPath: string; destDirPath: str
const transformSourceCodeResult = transformSourceCode({
"sourceCode": fs.readFileSync(filePath),
"filePath": path.join(srcDirPath, file_relative_path),
"filePath": path.join(srcDirPath, file_relative_path)
});
if (transformSourceCodeResult === undefined) {
@ -33,14 +33,14 @@ export function transformCodebase(params: { srcDirPath: string; destDirPath: str
}
fs.mkdirSync(path.dirname(path.join(destDirPath, file_relative_path)), {
"recursive": true,
"recursive": true
});
const { newFileName, modifiedSourceCode } = transformSourceCodeResult;
fs.writeFileSync(
path.join(path.dirname(path.join(destDirPath, file_relative_path)), newFileName ?? path.basename(file_relative_path)),
modifiedSourceCode,
modifiedSourceCode
);
}
}

19
src/bin/tools/walk.ts Normal file
View File

@ -0,0 +1,19 @@
import { readdir } from "fs/promises";
import { resolve } from "path";
/**
* Asynchronously and recursively walk a directory tree, yielding every file and directory
* found
*
* @param root the starting directory
* @returns AsyncGenerator
*/
export default async function* walk(root: string): AsyncGenerator<string, void, void> {
for (const entry of await readdir(root, { withFileTypes: true })) {
const absolutePath = resolve(root, entry.name);
if (entry.isDirectory()) {
yield absolutePath;
yield* walk(absolutePath);
} else yield absolutePath;
}
}

246
src/bin/tools/zip.ts Normal file
View File

@ -0,0 +1,246 @@
import { Transform, TransformOptions } from "stream";
import { createReadStream } from "fs";
import { stat } from "fs/promises";
import { Blob } from "buffer";
import { deflateBuffer, deflateStream } from "./deflate";
/**
* Zip source
* @property filename the name of the entry in the archie
* @property path of the source file, if the source is an actual file
* @property data the actual data buffer, if the source is constructed in-memory
*/
export type ZipSource = { path: string } & ({ fsPath: string } | { data: Buffer });
export type ZipRecord = {
path: string;
compression: "deflate" | undefined;
uncompressedSize: number;
compressedSize?: number;
crc32?: number;
offset?: number;
};
/**
* @returns the actual byte size of an string
*/
function utf8size(s: string) {
return new Blob([s]).size;
}
/**
* @param record
* @returns a buffer representing a Zip local header
* @link https://en.wikipedia.org/wiki/ZIP_(file_format)#Local_file_header
*/
function localHeader(record: ZipRecord) {
const { path, compression, uncompressedSize } = record;
const filenameSize = utf8size(path);
const buf = Buffer.alloc(30 + filenameSize);
buf.writeUInt32LE(0x04_03_4b_50, 0); // local header signature
buf.writeUInt16LE(10, 4); // min version
// we write 0x08 because crc and compressed size are unknown at
buf.writeUInt16LE(0x08, 6); // general purpose bit flag
buf.writeUInt16LE(compression ? ({ "deflate": 8 } as const)[compression] : 0, 8);
buf.writeUInt16LE(0, 10); // modified time
buf.writeUInt16LE(0, 12); // modified date
buf.writeUInt32LE(0, 14); // crc unknown
buf.writeUInt32LE(0, 18); // compressed size unknown
buf.writeUInt32LE(uncompressedSize, 22);
buf.writeUInt16LE(filenameSize, 26);
buf.writeUInt16LE(0, 28); // extra field length
buf.write(path, 30, "utf-8");
return buf;
}
/**
* @param record
* @returns a buffer representing a Zip central header
* @link https://en.wikipedia.org/wiki/ZIP_(file_format)#Central_directory_file_header
*/
function centralHeader(record: ZipRecord) {
const { path, compression, crc32, compressedSize, uncompressedSize, offset } = record;
const filenameSize = utf8size(path);
const buf = Buffer.alloc(46 + filenameSize);
const isFile = !path.endsWith("/");
if (typeof offset === "undefined") throw new Error("Illegal argument");
// we don't want to deal with possibly messed up file or directory
// permissions, so we ignore the original permissions
const externalAttr = isFile ? 0x81a40000 : 0x41ed0000;
buf.writeUInt32LE(0x0201_4b50, 0); // central header signature
buf.writeUInt16LE(10, 4); // version
buf.writeUInt16LE(10, 6); // min version
buf.writeUInt16LE(0, 8); // general purpose bit flag
buf.writeUInt16LE(compression ? ({ "deflate": 8 } as const)[compression] : 0, 10);
buf.writeUInt16LE(0, 12); // modified time
buf.writeUInt16LE(0, 14); // modified date
buf.writeUInt32LE(crc32 || 0, 16);
buf.writeUInt32LE(compressedSize || 0, 20);
buf.writeUInt32LE(uncompressedSize, 24);
buf.writeUInt16LE(filenameSize, 28);
buf.writeUInt16LE(0, 30); // extra field length
buf.writeUInt16LE(0, 32); // comment field length
buf.writeUInt16LE(0, 34); // disk number
buf.writeUInt16LE(0, 36); // internal
buf.writeUInt32LE(externalAttr, 38); // external
buf.writeUInt32LE(offset, 42); // offset where file starts
buf.write(path, 46, "utf-8");
return buf;
}
/**
* @returns a buffer representing an Zip End-Of-Central-Directory block
* @link https://en.wikipedia.org/wiki/ZIP_(file_format)#End_of_central_directory_record_(EOCD)
*/
function eocd({ offset, cdSize, nRecords }: { offset: number; cdSize: number; nRecords: number }) {
const buf = Buffer.alloc(22);
buf.writeUint32LE(0x06054b50, 0); // eocd signature
buf.writeUInt16LE(0, 4); // disc number
buf.writeUint16LE(0, 6); // disc where central directory starts
buf.writeUint16LE(nRecords, 8); // records on this disc
buf.writeUInt16LE(nRecords, 10); // records total
buf.writeUInt32LE(cdSize, 12); // byte size of cd
buf.writeUInt32LE(offset, 16); // cd offset
buf.writeUint16LE(0, 20); // comment length
return buf;
}
/**
* @returns a stream Transform, which reads a stream of ZipRecords and
* writes a bytestream
*/
export default function zip() {
/**
* This is called when the input stream of ZipSource items is finished.
* Will write central directory and end-of-central-direcotry blocks.
*/
const final = () => {
// write central directory
let cdSize = 0;
for (const record of records) {
const head = centralHeader(record);
zipTransform.push(head);
cdSize += head.length;
}
// write end-of-central-directory
zipTransform.push(eocd({ offset, cdSize, nRecords: records.length }));
// signal stream end
zipTransform.push(null);
};
/**
* Write a directory entry to the archive
* @param path
*/
const writeDir = async (path: string) => {
const record: ZipRecord = {
path: path + "/",
offset,
compression: undefined,
uncompressedSize: 0
};
const head = localHeader(record);
zipTransform.push(head);
records.push(record);
offset += head.length;
};
/**
* Write a file entry to the archive
* @param archivePath path of the file in archive
* @param fsPath path to file on filesystem
* @param size of the actual, uncompressed, file
*/
const writeFile = async (archivePath: string, fsPath: string, size: number) => {
const record: ZipRecord = {
path: archivePath,
offset,
compression: "deflate",
uncompressedSize: size
};
const head = localHeader(record);
zipTransform.push(head);
const { crc32, compressedSize } = await deflateStream(createReadStream(fsPath), chunk => zipTransform.push(chunk));
record.crc32 = crc32;
record.compressedSize = compressedSize;
records.push(record);
offset += head.length + compressedSize;
};
/**
* Write archive record based on filesystem file or directory
* @param archivePath path of item in archive
* @param fsPath path to item on filesystem
*/
const writeFromPath = async (archivePath: string, fsPath: string) => {
const fileStats = await stat(fsPath);
fileStats.isDirectory() ? await writeDir(archivePath) /**/ : await writeFile(archivePath, fsPath, fileStats.size) /**/;
};
/**
* Write archive record based on data in a buffer
* @param path
* @param data
*/
const writeFromBuffer = async (path: string, data: Buffer) => {
const { deflated, crc32 } = await deflateBuffer(data);
const record: ZipRecord = {
path,
compression: "deflate",
crc32,
uncompressedSize: data.length,
compressedSize: deflated.length,
offset
};
const head = localHeader(record);
zipTransform.push(head);
zipTransform.push(deflated);
records.push(record);
offset += head.length + deflated.length;
};
/**
* Write an archive record
* @param source
*/
const writeRecord = async (source: ZipSource) => {
if ("fsPath" in source) await writeFromPath(source.path, source.fsPath);
else if ("data" in source) await writeFromBuffer(source.path, source.data);
else throw new Error("Illegal argument " + typeof source + " " + JSON.stringify(source));
};
/**
* The actual stream transform function
* @param source
* @param _ encoding, ignored
* @param cb
*/
const transform: TransformOptions["transform"] = async (source: ZipSource, _, cb) => {
await writeRecord(source);
cb();
};
/** offset and records keep local state during processing */
let offset = 0;
const records: ZipRecord[] = [];
const zipTransform = new Transform({
readableObjectMode: false,
writableObjectMode: true,
transform,
final
});
return zipTransform;
}

11
src/bin/tsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"extends": "../../tsproject.json",
"compilerOptions": {
"module": "CommonJS",
"target": "ES5",
"esModuleInterop": true,
"lib": ["es2015", "DOM", "ES2019.Object"],
"outDir": "../../dist/bin",
"rootDir": "."
}
}

100
src/lib/KcApp.tsx Normal file
View File

@ -0,0 +1,100 @@
import React, { lazy, Suspense } from "react";
import { __unsafe_useI18n as useI18n } from "./i18n";
import DefaultTemplate from "./Template";
import type { KcContextBase } from "./getKcContext/KcContextBase";
import type { PageProps } from "./KcProps";
import type { I18nBase } from "./i18n";
import type { SetOptional } from "./tools/SetOptional";
const Login = lazy(() => import("./pages/Login"));
const Register = lazy(() => import("./pages/Register"));
const RegisterUserProfile = lazy(() => import("./pages/RegisterUserProfile"));
const Info = lazy(() => import("./pages/Info"));
const Error = lazy(() => import("./pages/Error"));
const LoginResetPassword = lazy(() => import("./pages/LoginResetPassword"));
const LoginVerifyEmail = lazy(() => import("./pages/LoginVerifyEmail"));
const Terms = lazy(() => import("./pages/Terms"));
const LoginOtp = lazy(() => import("./pages/LoginOtp"));
const LoginPassword = lazy(() => import("./pages/LoginPassword"));
const LoginUsername = lazy(() => import("./pages/LoginUsername"));
const WebauthnAuthenticate = lazy(() => import("./pages/WebauthnAuthenticate"));
const LoginUpdatePassword = lazy(() => import("./pages/LoginUpdatePassword"));
const LoginUpdateProfile = lazy(() => import("./pages/LoginUpdateProfile"));
const LoginIdpLinkConfirm = lazy(() => import("./pages/LoginIdpLinkConfirm"));
const LoginPageExpired = lazy(() => import("./pages/LoginPageExpired"));
const LoginIdpLinkEmail = lazy(() => import("./pages/LoginIdpLinkEmail"));
const LoginConfigTotp = lazy(() => import("./pages/LoginConfigTotp"));
const LogoutConfirm = lazy(() => import("./pages/LogoutConfirm"));
const UpdateUserProfile = lazy(() => import("./pages/UpdateUserProfile"));
const IdpReviewUserProfile = lazy(() => import("./pages/IdpReviewUserProfile"));
export default function KcApp(props_: SetOptional<PageProps<KcContextBase, I18nBase>, "Template">) {
const { kcContext, i18n: userProvidedI18n, Template = DefaultTemplate, ...kcProps } = props_;
const i18n = (function useClosure() {
const i18n = useI18n({
kcContext,
"extraMessages": {},
"doSkip": userProvidedI18n !== undefined
});
return userProvidedI18n ?? i18n;
})();
if (i18n === null) {
return null;
}
const commonProps = { i18n, Template, ...kcProps };
return (
<Suspense>
{(() => {
switch (kcContext.pageId) {
case "login.ftl":
return <Login {...{ kcContext, ...commonProps }} />;
case "register.ftl":
return <Register {...{ kcContext, ...commonProps }} />;
case "register-user-profile.ftl":
return <RegisterUserProfile {...{ kcContext, ...commonProps }} />;
case "info.ftl":
return <Info {...{ kcContext, ...commonProps }} />;
case "error.ftl":
return <Error {...{ kcContext, ...commonProps }} />;
case "login-reset-password.ftl":
return <LoginResetPassword {...{ kcContext, ...commonProps }} />;
case "login-verify-email.ftl":
return <LoginVerifyEmail {...{ kcContext, ...commonProps }} />;
case "terms.ftl":
return <Terms {...{ kcContext, ...commonProps }} />;
case "login-otp.ftl":
return <LoginOtp {...{ kcContext, ...commonProps }} />;
case "login-username.ftl":
return <LoginUsername {...{ kcContext, ...commonProps }} />;
case "login-password.ftl":
return <LoginPassword {...{ kcContext, ...commonProps }} />;
case "webauthn-authenticate.ftl":
return <WebauthnAuthenticate {...{ kcContext, ...commonProps }} />;
case "login-update-password.ftl":
return <LoginUpdatePassword {...{ kcContext, ...commonProps }} />;
case "login-update-profile.ftl":
return <LoginUpdateProfile {...{ kcContext, ...commonProps }} />;
case "login-idp-link-confirm.ftl":
return <LoginIdpLinkConfirm {...{ kcContext, ...commonProps }} />;
case "login-idp-link-email.ftl":
return <LoginIdpLinkEmail {...{ kcContext, ...commonProps }} />;
case "login-page-expired.ftl":
return <LoginPageExpired {...{ kcContext, ...commonProps }} />;
case "login-config-totp.ftl":
return <LoginConfigTotp {...{ kcContext, ...commonProps }} />;
case "logout-confirm.ftl":
return <LogoutConfirm {...{ kcContext, ...commonProps }} />;
case "update-user-profile.ftl":
return <UpdateUserProfile {...{ kcContext, ...commonProps }} />;
case "idp-review-user-profile.ftl":
return <IdpReviewUserProfile {...{ kcContext, ...commonProps }} />;
}
})()}
</Suspense>
);
}

View File

@ -1,5 +1,8 @@
import { allPropertiesValuesToUndefined } from "../tools/allPropertiesValuesToUndefined";
import { allPropertiesValuesToUndefined } from "./tools/allPropertiesValuesToUndefined";
import { assert } from "tsafe/assert";
import type { KcContextBase } from "./getKcContext";
import type { ReactNode } from "react";
import { I18nBase } from "./i18n";
/** Class names can be provided as an array or separated by whitespace */
export type KcPropsGeneric<CssClasses extends string> = {
@ -37,7 +40,7 @@ export const defaultKcTemplateProps = {
"stylesCommon": [
"node_modules/patternfly/dist/css/patternfly.min.css",
"node_modules/patternfly/dist/css/patternfly-additions.min.css",
"lib/zocial/zocial.css",
"lib/zocial/zocial.css"
],
"styles": ["css/login.css"],
"scripts": [],
@ -60,7 +63,7 @@ export const defaultKcTemplateProps = {
"kcFormGroupClass": ["form-group"],
"kcLabelWrapperClass": ["col-xs-12", "col-sm-12", "col-md-12", "col-lg-12"],
"kcSignUpClass": ["login-pf-signup"],
"kcInfoAreaWrapperClass": [],
"kcInfoAreaWrapperClass": []
} as const;
assert<typeof defaultKcTemplateProps extends KcTemplateProps ? true : false>();
@ -84,6 +87,7 @@ export type KcProps = KcPropsGeneric<
| "kcFormSocialAccountDoubleListClass"
| "kcFormSocialAccountListLinkClass"
| "kcWebAuthnKeyIcon"
| "kcWebAuthnDefaultIcon"
| "kcFormClass"
| "kcFormGroupErrorClass"
| "kcLabelClass"
@ -105,12 +109,16 @@ export type KcProps = KcPropsGeneric<
| "kcSrOnlyClass"
| "kcSelectAuthListClass"
| "kcSelectAuthListItemClass"
| "kcSelectAuthListItemFillClass"
| "kcSelectAuthListItemInfoClass"
| "kcSelectAuthListItemLeftClass"
| "kcSelectAuthListItemBodyClass"
| "kcSelectAuthListItemDescriptionClass"
| "kcSelectAuthListItemHeadingClass"
| "kcSelectAuthListItemHelpTextClass"
| "kcSelectAuthListItemIconPropertyClass"
| "kcSelectAuthListItemIconClass"
| "kcSelectAuthListItemTitle"
| "kcAuthenticatorDefaultClass"
| "kcAuthenticatorPasswordClass"
| "kcAuthenticatorOTPClass"
@ -138,6 +146,7 @@ export const defaultKcProps = {
"kcFormSocialAccountDoubleListClass": ["login-pf-social-double-col"],
"kcFormSocialAccountListLinkClass": ["login-pf-social-link"],
"kcWebAuthnKeyIcon": ["pficon", "pficon-key"],
"kcWebAuthnDefaultIcon": ["pficon", "pficon-key"],
"kcFormClass": ["form-horizontal"],
"kcFormGroupErrorClass": ["has-error"],
@ -173,6 +182,10 @@ export const defaultKcProps = {
// css classes for select-authenticator form
"kcSelectAuthListClass": ["list-group", "list-view-pf"],
"kcSelectAuthListItemClass": ["list-group-item", "list-view-pf-stacked"],
"kcSelectAuthListItemFillClass": ["pf-l-split__item", "pf-m-fill"],
"kcSelectAuthListItemIconPropertyClass": ["fa-2x", "select-auth-box-icon-properties"],
"kcSelectAuthListItemIconClass": ["pf-l-split__item", "select-auth-box-icon"],
"kcSelectAuthListItemTitle": ["select-auth-box-paragraph"],
"kcSelectAuthListItemInfoClass": ["list-view-pf-main-info"],
"kcSelectAuthListItemLeftClass": ["list-view-pf-left"],
"kcSelectAuthListItemBodyClass": ["list-view-pf-body"],
@ -192,9 +205,32 @@ export const defaultKcProps = {
"kcSelectOTPListItemClass": ["card-pf-body", "card-pf-top-element"],
"kcAuthenticatorOtpCircleClass": ["fa", "fa-mobile", "card-pf-icon-circle"],
"kcSelectOTPItemHeadingClass": ["card-pf-title", "text-center"],
"kcFormOptionsWrapperClass": [],
"kcFormOptionsWrapperClass": []
} as const;
export type TemplateProps<KcContext extends KcContextBase.Common, I18n extends I18nBase> = {
kcContext: KcContext;
i18n: I18n;
doFetchDefaultThemeResources: boolean;
} & {
displayInfo?: boolean;
displayMessage?: boolean;
displayRequiredFields?: boolean;
displayWide?: boolean;
showAnotherWayIfPresent?: boolean;
headerNode: ReactNode;
showUsernameNode?: ReactNode;
formNode: ReactNode;
infoNode?: ReactNode;
} & KcTemplateProps;
export type PageProps<KcContext, I18n extends I18nBase> = {
kcContext: KcContext;
i18n: I18n;
doFetchDefaultThemeResources?: boolean;
Template: (props: TemplateProps<any, any>) => JSX.Element | null;
} & KcProps;
assert<typeof defaultKcProps extends KcProps ? true : false>();
/** Tu use if you don't want any default */

View File

@ -1,36 +1,13 @@
import { useReducer, useEffect, memo } from "react";
import type { ReactNode } from "react";
import { useKcMessage } from "../i18n/useKcMessage";
import { useKcLanguageTag } from "../i18n/useKcLanguageTag";
import type { KcContextBase } from "../getKcContext/KcContextBase";
import { assert } from "../tools/assert";
import type { KcLanguageTag } from "../i18n/KcLanguageTag";
import { getBestMatchAmongKcLanguageTag } from "../i18n/KcLanguageTag";
import { getKcLanguageTagLabel } from "../i18n/KcLanguageTag";
import { useCallbackFactory } from "powerhooks/useCallbackFactory";
import { headInsert } from "../tools/headInsert";
import { pathJoin } from "../tools/pathJoin";
import { useConstCallback } from "powerhooks/useConstCallback";
import type { KcTemplateProps } from "./KcProps";
import { useCssAndCx } from "tss-react";
import React, { useReducer, useEffect } from "react";
import { assert } from "./tools/assert";
import { headInsert } from "./tools/headInsert";
import { pathJoin } from "../bin/tools/pathJoin";
import { clsx } from "./tools/clsx";
import type { TemplateProps } from "./KcProps";
import type { KcContextBase } from "./getKcContext/KcContextBase";
import type { I18nBase } from "./i18n";
export type TemplateProps = {
displayInfo?: boolean;
displayMessage?: boolean;
displayRequiredFields?: boolean;
displayWide?: boolean;
showAnotherWayIfPresent?: boolean;
headerNode: ReactNode;
showUsernameNode?: ReactNode;
formNode: ReactNode;
infoNode?: ReactNode;
/** If you write your own page you probably want
* to avoid pulling the default theme assets.
*/
doFetchDefaultThemeResources: boolean;
} & { kcContext: KcContextBase } & KcTemplateProps;
export const Template = memo((props: TemplateProps) => {
export default function Template(props: TemplateProps<KcContextBase.Common, I18nBase>) {
const {
displayInfo = false,
displayMessage = true,
@ -42,123 +19,55 @@ export const Template = memo((props: TemplateProps) => {
formNode,
infoNode = null,
kcContext,
i18n,
doFetchDefaultThemeResources,
stylesCommon,
styles,
scripts,
kcHtmlClass
} = props;
const { cx } = useCssAndCx();
useEffect(() => {
console.log("Rendering this page with react using keycloakify");
}, []);
const { msg } = useKcMessage();
const { kcLanguageTag, setKcLanguageTag } = useKcLanguageTag();
const onChangeLanguageClickFactory = useCallbackFactory(([languageTag]: [KcLanguageTag]) => setKcLanguageTag(languageTag));
const onTryAnotherWayClick = useConstCallback(() => (document.forms["kc-select-try-another-way-form" as never].submit(), false));
const { msg, changeLocale, labelBySupportedLanguageTag, currentLanguageTag } = i18n;
const { realm, locale, auth, url, message, isAppInitiatedAction } = kcContext;
useEffect(() => {
if (!realm.internationalizationEnabled) {
return;
}
const { isReady } = usePrepareTemplate({
doFetchDefaultThemeResources,
stylesCommon,
styles,
scripts,
url,
kcHtmlClass
});
assert(locale !== undefined);
if (kcLanguageTag === getBestMatchAmongKcLanguageTag(locale.current)) {
return;
}
window.location.href = locale.supported.find(({ languageTag }) => languageTag === kcLanguageTag)!.url;
}, [kcLanguageTag]);
const [isExtraCssLoaded, setExtraCssLoaded] = useReducer(() => true, false);
useEffect(() => {
if (!doFetchDefaultThemeResources) {
setExtraCssLoaded();
return;
}
let isUnmounted = false;
const cleanups: (() => void)[] = [];
const toArr = (x: string | readonly string[] | undefined) => (typeof x === "string" ? x.split(" ") : x ?? []);
Promise.all(
[
...toArr(props.stylesCommon).map(relativePath => pathJoin(url.resourcesCommonPath, relativePath)),
...toArr(props.styles).map(relativePath => pathJoin(url.resourcesPath, relativePath)),
]
.reverse()
.map(href =>
headInsert({
"type": "css",
href,
"position": "prepend",
}),
),
).then(() => {
if (isUnmounted) {
return;
}
setExtraCssLoaded();
});
toArr(props.scripts).forEach(relativePath =>
headInsert({
"type": "javascript",
"src": pathJoin(url.resourcesPath, relativePath),
}),
);
if (props.kcHtmlClass !== undefined) {
const htmlClassList = document.getElementsByTagName("html")[0].classList;
const tokens = cx(props.kcHtmlClass).split(" ");
htmlClassList.add(...tokens);
cleanups.push(() => htmlClassList.remove(...tokens));
}
return () => {
isUnmounted = true;
cleanups.forEach(f => f());
};
}, [props.kcHtmlClass]);
if (!isExtraCssLoaded) {
if (!isReady) {
return null;
}
return (
<div className={cx(props.kcLoginClass)}>
<div id="kc-header" className={cx(props.kcHeaderClass)}>
<div id="kc-header-wrapper" className={cx(props.kcHeaderWrapperClass)}>
<div className={clsx(props.kcLoginClass)}>
<div id="kc-header" className={clsx(props.kcHeaderClass)}>
<div id="kc-header-wrapper" className={clsx(props.kcHeaderWrapperClass)}>
{msg("loginTitleHtml", realm.displayNameHtml)}
</div>
</div>
<div className={cx(props.kcFormCardClass, displayWide && props.kcFormCardAccountClass)}>
<header className={cx(props.kcFormHeaderClass)}>
<div className={clsx(props.kcFormCardClass, displayWide && props.kcFormCardAccountClass)}>
<header className={clsx(props.kcFormHeaderClass)}>
{realm.internationalizationEnabled && (assert(locale !== undefined), true) && locale.supported.length > 1 && (
<div id="kc-locale">
<div id="kc-locale-wrapper" className={cx(props.kcLocaleWrapperClass)}>
<div id="kc-locale-wrapper" className={clsx(props.kcLocaleWrapperClass)}>
<div className="kc-dropdown" id="kc-locale-dropdown">
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
<a href="#" id="kc-current-locale-link">
{getKcLanguageTagLabel(kcLanguageTag)}
{labelBySupportedLanguageTag[currentLanguageTag]}
</a>
<ul>
{locale.supported.map(({ languageTag }) => (
<li key={languageTag} className="kc-dropdown-item">
<a href="#" onClick={onChangeLanguageClickFactory(languageTag)}>
{getKcLanguageTagLabel(languageTag)}
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
<a href="#" onClick={() => changeLocale(languageTag)}>
{labelBySupportedLanguageTag[languageTag]}
</a>
</li>
))}
@ -169,8 +78,8 @@ export const Template = memo((props: TemplateProps) => {
)}
{!(auth !== undefined && auth.showUsername && !auth.showResetCredentials) ? (
displayRequiredFields ? (
<div className={cx(props.kcContentWrapperClass)}>
<div className={cx(props.kcLabelWrapperClass, "subtitle")}>
<div className={clsx(props.kcContentWrapperClass)}>
<div className={clsx(props.kcLabelWrapperClass, "subtitle")}>
<span className="subtitle">
<span className="required">*</span>
{msg("requiredFields")}
@ -184,20 +93,20 @@ export const Template = memo((props: TemplateProps) => {
<h1 id="kc-page-title">{headerNode}</h1>
)
) : displayRequiredFields ? (
<div className={cx(props.kcContentWrapperClass)}>
<div className={cx(props.kcLabelWrapperClass, "subtitle")}>
<div className={clsx(props.kcContentWrapperClass)}>
<div className={clsx(props.kcLabelWrapperClass, "subtitle")}>
<span className="subtitle">
<span className="required">*</span> {msg("requiredFields")}
</span>
</div>
<div className="col-md-10">
{showUsernameNode}
<div className={cx(props.kcFormGroupClass)}>
<div className={clsx(props.kcFormGroupClass)}>
<div id="kc-username">
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
<a id="reset-login" href={url.loginRestartFlowUrl}>
<div className="kc-login-tooltip">
<i className={cx(props.kcResetFlowIcon)}></i>
<i className={clsx(props.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
</div>
</a>
@ -208,12 +117,12 @@ export const Template = memo((props: TemplateProps) => {
) : (
<>
{showUsernameNode}
<div className={cx(props.kcFormGroupClass)}>
<div className={clsx(props.kcFormGroupClass)}>
<div id="kc-username">
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
<a id="reset-login" href={url.loginRestartFlowUrl}>
<div className="kc-login-tooltip">
<i className={cx(props.kcResetFlowIcon)}></i>
<i className={clsx(props.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
</div>
</a>
@ -226,15 +135,15 @@ export const Template = memo((props: TemplateProps) => {
<div id="kc-content-wrapper">
{/* App-initiated actions should not see warning messages about the need to complete the action during login. */}
{displayMessage && message !== undefined && (message.type !== "warning" || !isAppInitiatedAction) && (
<div className={cx("alert", `alert-${message.type}`)}>
{message.type === "success" && <span className={cx(props.kcFeedbackSuccessIcon)}></span>}
{message.type === "warning" && <span className={cx(props.kcFeedbackWarningIcon)}></span>}
{message.type === "error" && <span className={cx(props.kcFeedbackErrorIcon)}></span>}
{message.type === "info" && <span className={cx(props.kcFeedbackInfoIcon)}></span>}
<div className={clsx("alert", `alert-${message.type}`)}>
{message.type === "success" && <span className={clsx(props.kcFeedbackSuccessIcon)}></span>}
{message.type === "warning" && <span className={clsx(props.kcFeedbackWarningIcon)}></span>}
{message.type === "error" && <span className={clsx(props.kcFeedbackErrorIcon)}></span>}
{message.type === "info" && <span className={clsx(props.kcFeedbackInfoIcon)}></span>}
<span
className="kc-feedback-text"
dangerouslySetInnerHTML={{
"__html": message.summary,
"__html": message.summary
}}
/>
</div>
@ -245,12 +154,20 @@ export const Template = memo((props: TemplateProps) => {
id="kc-select-try-another-way-form"
action={url.loginAction}
method="post"
className={cx(displayWide && props.kcContentWrapperClass)}
className={clsx(displayWide && props.kcContentWrapperClass)}
>
<div className={cx(displayWide && [props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass])}>
<div className={cx(props.kcFormGroupClass)}>
<div className={clsx(displayWide && [props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass])}>
<div className={clsx(props.kcFormGroupClass)}>
<input type="hidden" name="tryAnotherWay" value="on" />
<a href="#" id="try-another-way" onClick={onTryAnotherWayClick}>
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
<a
href="#"
id="try-another-way"
onClick={() => {
document.forms["kc-select-try-another-way-form" as never].submit();
return false;
}}
>
{msg("doTryAnotherWay")}
</a>
</div>
@ -258,8 +175,8 @@ export const Template = memo((props: TemplateProps) => {
</form>
)}
{displayInfo && (
<div id="kc-info" className={cx(props.kcSignUpClass)}>
<div id="kc-info-wrapper" className={cx(props.kcInfoAreaWrapperClass)}>
<div id="kc-info" className={clsx(props.kcSignUpClass)}>
<div id="kc-info-wrapper" className={clsx(props.kcInfoAreaWrapperClass)}>
{infoNode}
</div>
</div>
@ -269,4 +186,80 @@ export const Template = memo((props: TemplateProps) => {
</div>
</div>
);
});
}
export function usePrepareTemplate(params: {
doFetchDefaultThemeResources: boolean;
stylesCommon: string | readonly string[] | undefined;
styles: string | readonly string[] | undefined;
scripts: string | readonly string[] | undefined;
url: {
resourcesCommonPath: string;
resourcesPath: string;
};
kcHtmlClass: string | readonly string[] | undefined;
}) {
const { doFetchDefaultThemeResources, stylesCommon, styles, url, scripts, kcHtmlClass } = params;
const [isReady, setReady] = useReducer(() => true, !doFetchDefaultThemeResources);
useEffect(() => {
if (!doFetchDefaultThemeResources) {
return;
}
let isUnmounted = false;
const toArr = (x: string | readonly string[] | undefined) => (typeof x === "string" ? x.split(" ") : x ?? []);
Promise.all(
[
...toArr(stylesCommon).map(relativePath => pathJoin(url.resourcesCommonPath, relativePath)),
...toArr(styles).map(relativePath => pathJoin(url.resourcesPath, relativePath))
]
.reverse()
.map(href =>
headInsert({
"type": "css",
href,
"position": "prepend"
})
)
).then(() => {
if (isUnmounted) {
return;
}
setReady();
});
toArr(scripts).forEach(relativePath =>
headInsert({
"type": "javascript",
"src": pathJoin(url.resourcesPath, relativePath)
})
);
return () => {
isUnmounted = true;
};
}, [kcHtmlClass]);
useEffect(() => {
if (kcHtmlClass === undefined) {
return;
}
const htmlClassList = document.getElementsByTagName("html")[0].classList;
const tokens = clsx(kcHtmlClass).split(" ");
htmlClassList.add(...tokens);
return () => {
htmlClassList.remove(...tokens);
};
}, [kcHtmlClass]);
return { isReady };
}

View File

@ -1,47 +0,0 @@
import { memo } from "react";
import type { KcContextBase } from "../getKcContext/KcContextBase";
import type { KcProps } from "./KcProps";
import { Login } from "./Login";
import { Register } from "./Register";
import { RegisterUserProfile } from "./RegisterUserProfile";
import { Info } from "./Info";
import { Error } from "./Error";
import { LoginResetPassword } from "./LoginResetPassword";
import { LoginVerifyEmail } from "./LoginVerifyEmail";
import { Terms } from "./Terms";
import { LoginOtp } from "./LoginOtp";
import { LoginUpdatePassword } from "./LoginUpdatePassword";
import { LoginUpdateProfile } from "./LoginUpdateProfile";
import { LoginIdpLinkConfirm } from "./LoginIdpLinkConfirm";
import { LoginPageExpired } from "./LoginPageExpired";
export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContextBase } & KcProps) => {
switch (kcContext.pageId) {
case "login.ftl":
return <Login {...{ kcContext, ...props }} />;
case "register.ftl":
return <Register {...{ kcContext, ...props }} />;
case "register-user-profile.ftl":
return <RegisterUserProfile {...{ kcContext, ...props }} />;
case "info.ftl":
return <Info {...{ kcContext, ...props }} />;
case "error.ftl":
return <Error {...{ kcContext, ...props }} />;
case "login-reset-password.ftl":
return <LoginResetPassword {...{ kcContext, ...props }} />;
case "login-verify-email.ftl":
return <LoginVerifyEmail {...{ kcContext, ...props }} />;
case "terms.ftl":
return <Terms {...{ kcContext, ...props }} />;
case "login-otp.ftl":
return <LoginOtp {...{ kcContext, ...props }} />;
case "login-update-password.ftl":
return <LoginUpdatePassword {...{ kcContext, ...props }} />;
case "login-update-profile.ftl":
return <LoginUpdateProfile {...{ kcContext, ...props }} />;
case "login-idp-link-confirm.ftl":
return <LoginIdpLinkConfirm {...{ kcContext, ...props }} />;
case "login-page-expired.ftl":
return <LoginPageExpired {...{ kcContext, ...props }} />;
}
});

View File

@ -1,46 +0,0 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react";
export const LoginIdpLinkConfirm = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LoginIdpLinkConfirm } & KcProps) => {
const { url, idpAlias } = kcContext;
const { msg } = useKcMessage();
const { cx } = useCssAndCx();
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
headerNode={msg("confirmLinkIdpTitle")}
formNode={
<form id="kc-register-form" action={url.loginAction} method="post">
<div className={cx(props.kcFormGroupClass)}>
<button
type="submit"
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonBlockClass, props.kcButtonLargeClass)}
name="submitAction"
id="updateProfile"
value="updateProfile"
>
{msg("confirmLinkIdpReviewProfile")}
</button>
<button
type="submit"
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonBlockClass, props.kcButtonLargeClass)}
name="submitAction"
id="linkAccount"
value="linkAccount"
>
{msg("confirmLinkIdpContinue", idpAlias)}
</button>
</div>
</form>
}
/>
);
});

View File

@ -1,66 +0,0 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react";
export const LoginResetPassword = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LoginResetPassword } & KcProps) => {
const { url, realm, auth } = kcContext;
const { msg, msgStr } = useKcMessage();
const { cx } = useCssAndCx();
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={msg("emailForgotTitle")}
formNode={
<form id="kc-reset-password-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post">
<div className={cx(props.kcFormGroupClass)}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="username" className={cx(props.kcLabelClass)}>
{!realm.loginWithEmailAllowed
? msg("username")
: !realm.registrationEmailAsUsername
? msg("usernameOrEmail")
: msg("email")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="username"
name="username"
className={cx(props.kcInputClass)}
autoFocus
defaultValue={auth !== undefined && auth.showUsername ? auth.attemptedUsername : undefined}
/>
</div>
</div>
<div className={cx(props.kcFormGroupClass, props.kcFormSettingClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)}>
<span>
<a href={url.loginUrl}>{msg("backToLogin")}</a>
</span>
</div>
</div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
<input
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonBlockClass, props.kcButtonLargeClass)}
type="submit"
value={msgStr("doSubmit")}
/>
</div>
</div>
</form>
}
infoNode={msg("emailInstruction")}
/>
);
});

View File

@ -1,120 +0,0 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react";
export const LoginUpdateProfile = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LoginUpdateProfile } & KcProps) => {
const { cx } = useCssAndCx();
const { msg, msgStr } = useKcMessage();
const { url, user, messagesPerField, isAppInitiatedAction } = kcContext;
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
headerNode={msg("loginProfileTitle")}
formNode={
<form id="kc-update-profile-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post">
{user.editUsernameAllowed && (
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("username", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="username" className={cx(props.kcLabelClass)}>
{msg("username")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="username"
name="username"
defaultValue={user.username ?? ""}
className={cx(props.kcInputClass)}
/>
</div>
</div>
)}
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("email", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="email" className={cx(props.kcLabelClass)}>
{msg("email")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input type="text" id="email" name="email" defaultValue={user.email ?? ""} className={cx(props.kcInputClass)} />
</div>
</div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("firstName", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="firstName" className={cx(props.kcLabelClass)}>
{msg("firstName")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type="text"
id="firstName"
name="firstName"
defaultValue={user.firstName ?? ""}
className={cx(props.kcInputClass)}
/>
</div>
</div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("lastName", props.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor="lastName" className={cx(props.kcLabelClass)}>
{msg("lastName")}
</label>
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input type="text" id="lastName" name="lastName" defaultValue={user.lastName ?? ""} className={cx(props.kcInputClass)} />
</div>
</div>
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)} />
</div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
{isAppInitiatedAction ? (
<>
<input
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonLargeClass)}
type="submit"
defaultValue={msgStr("doSubmit")}
/>
<button
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonLargeClass)}
type="submit"
name="cancel-aia"
value="true"
>
{msg("doCancel")}
</button>
</>
) : (
<input
className={cx(
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonBlockClass,
props.kcButtonLargeClass,
)}
type="submit"
defaultValue={msgStr("doSubmit")}
/>
)}
</div>
</div>
</form>
}
/>
);
});

View File

@ -1,30 +0,0 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
export const LoginVerifyEmail = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LoginVerifyEmail } & KcProps) => {
const { msg } = useKcMessage();
const { url } = kcContext;
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={msg("emailVerifyTitle")}
formNode={
<>
<p className="instruction">{msg("emailVerifyInstruction1")}</p>
<p className="instruction">
{msg("emailVerifyInstruction2")}
<a href={url.loginAction}>{msg("doClickHere")}</a>
{msg("emailVerifyInstruction3")}
</p>
</>
}
/>
);
});

View File

@ -1,193 +0,0 @@
import { useMemo, memo, useEffect, useState, Fragment } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import type { KcContextBase, Attribute } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react";
import type { ReactComponent } from "../tools/ReactComponent";
import { useCallbackFactory } from "powerhooks/useCallbackFactory";
import { useFormValidationSlice } from "../useFormValidationSlice";
export const RegisterUserProfile = memo(({ kcContext, ...props_ }: { kcContext: KcContextBase.RegisterUserProfile } & KcProps) => {
const { url, messagesPerField, recaptchaRequired, recaptchaSiteKey } = kcContext;
const { msg, msgStr } = useKcMessage();
const { cx, css } = useCssAndCx();
const props = useMemo(
() => ({
...props_,
"kcFormGroupClass": cx(props_.kcFormGroupClass, css({ "marginBottom": 20 })),
}),
[cx, css],
);
const [isFomSubmittable, setIsFomSubmittable] = useState(false);
return (
<Template
{...{ kcContext, ...props }}
displayMessage={messagesPerField.exists("global")}
displayRequiredFields={true}
doFetchDefaultThemeResources={true}
headerNode={msg("registerTitle")}
formNode={
<form id="kc-register-form" className={cx(props.kcFormClass)} action={url.registrationAction} method="post">
<UserProfileFormFields kcContext={kcContext} onIsFormSubmittableValueChange={setIsFomSubmittable} {...props} />
{recaptchaRequired && (
<div className="form-group">
<div className={cx(props.kcInputWrapperClass)}>
<div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey} />
</div>
</div>
)}
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)}>
<span>
<a href={url.loginUrl}>{msg("backToLogin")}</a>
</span>
</div>
</div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
<input
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonBlockClass, props.kcButtonLargeClass)}
type="submit"
value={msgStr("doRegister")}
disabled={!isFomSubmittable}
/>
</div>
</div>
</form>
}
/>
);
});
type UserProfileFormFieldsProps = { kcContext: KcContextBase.RegisterUserProfile } & KcProps &
Partial<Record<"BeforeField" | "AfterField", ReactComponent<{ attribute: Attribute }>>> & {
onIsFormSubmittableValueChange: (isFormSubmittable: boolean) => void;
};
const UserProfileFormFields = memo(({ kcContext, onIsFormSubmittableValueChange, ...props }: UserProfileFormFieldsProps) => {
const { cx, css } = useCssAndCx();
const { advancedMsg } = useKcMessage();
const {
formValidationState: { fieldStateByAttributeName, isFormSubmittable },
formValidationReducer,
attributesWithPassword,
} = useFormValidationSlice({
kcContext,
});
useEffect(() => {
onIsFormSubmittableValueChange(isFormSubmittable);
}, [isFormSubmittable]);
const onChangeFactory = useCallbackFactory(
(
[name]: [string],
[
{
target: { value },
},
]: [React.ChangeEvent<HTMLInputElement>],
) =>
formValidationReducer({
"action": "update value",
name,
"newValue": value,
}),
);
const onBlurFactory = useCallbackFactory(([name]: [string]) =>
formValidationReducer({
"action": "focus lost",
name,
}),
);
let currentGroup = "";
return (
<>
{attributesWithPassword.map((attribute, i) => {
const { group = "", groupDisplayHeader = "", groupDisplayDescription = "" } = attribute;
const { value, displayableErrors } = fieldStateByAttributeName[attribute.name];
const formGroupClassName = cx(props.kcFormGroupClass, displayableErrors.length !== 0 && props.kcFormGroupErrorClass);
return (
<Fragment key={i}>
{group !== currentGroup && (currentGroup = group) !== "" && (
<div className={formGroupClassName}>
<div className={cx(props.kcContentWrapperClass)}>
<label id={`header-${group}`} className={cx(props.kcFormGroupHeader)}>
{advancedMsg(groupDisplayHeader) || currentGroup}
</label>
</div>
{groupDisplayDescription !== "" && (
<div className={cx(props.kcLabelWrapperClass)}>
<label id={`description-${group}`} className={`${cx(props.kcLabelClass)}`}>
{advancedMsg(groupDisplayDescription)}
</label>
</div>
)}
</div>
)}
<div className={formGroupClassName}>
<div className={cx(props.kcLabelWrapperClass)}>
<label htmlFor={attribute.name} className={cx(props.kcLabelClass)}>
{advancedMsg(attribute.displayName ?? "")}
</label>
{attribute.required && <>*</>}
</div>
<div className={cx(props.kcInputWrapperClass)}>
<input
type={(() => {
switch (attribute.name) {
case "password-confirm":
case "password":
return "password";
default:
return "text";
}
})()}
id={attribute.name}
name={attribute.name}
value={value}
onChange={onChangeFactory(attribute.name)}
className={cx(props.kcInputClass)}
aria-invalid={displayableErrors.length !== 0}
disabled={attribute.readOnly}
autoComplete={attribute.autocomplete}
onBlur={onBlurFactory(attribute.name)}
/>
{displayableErrors.length !== 0 && (
<span
id={`input-error-${attribute.name}`}
className={cx(
props.kcInputErrorMessageClass,
css({
"position": displayableErrors.length === 1 ? "absolute" : undefined,
"& > span": { "display": "block" },
}),
)}
aria-live="polite"
>
{displayableErrors.map(({ errorMessage }) => errorMessage)}
</span>
)}
</div>
</div>
</Fragment>
);
})}
</>
);
});

View File

@ -1,51 +0,0 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useKcMessage } from "../i18n/useKcMessage";
import { useCssAndCx } from "tss-react";
export const Terms = memo(({ kcContext, ...props }: { kcContext: KcContextBase.Terms } & KcProps) => {
const { msg, msgStr } = useKcMessage();
const { cx } = useCssAndCx();
const { url } = kcContext;
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={msg("termsTitle")}
formNode={
<>
<div id="kc-terms-text">{msg("termsText")}</div>
<form className="form-actions" action={url.loginAction} method="POST">
<input
className={cx(
props.kcButtonClass,
props.kcButtonClass,
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonLargeClass,
)}
name="accept"
id="kc-accept"
type="submit"
value={msgStr("doAccept")}
/>
<input
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonLargeClass)}
name="cancel"
id="kc-decline"
type="submit"
value={msgStr("doDecline")}
/>
</form>
<div className="clearfix" />
</>
}
/>
);
});

View File

@ -1,9 +1,8 @@
import type { PageId } from "../../bin/build-keycloak-theme/generateFtl";
import type { KcLanguageTag } from "../i18n/KcLanguageTag";
import type { PageId } from "../../bin/keycloakify/generateFtl";
import { assert } from "tsafe/assert";
import type { Equals } from "tsafe";
import type { MessageKey } from "../i18n/useKcMessage";
import type { LanguageLabel } from "../i18n/KcLanguageTag";
import type { MessageKeyBase } from "../i18n";
import type { KcTemplateClassKey } from "../KcProps";
type ExtractAfterStartingWith<Prefix extends string, StrEnum> = StrEnum extends `${Prefix}${infer U}` ? U : never;
@ -21,10 +20,28 @@ export type KcContextBase =
| KcContextBase.LoginVerifyEmail
| KcContextBase.Terms
| KcContextBase.LoginOtp
| KcContextBase.LoginUsername
| KcContextBase.WebauthnAuthenticate
| KcContextBase.LoginPassword
| KcContextBase.LoginUpdatePassword
| KcContextBase.LoginUpdateProfile
| KcContextBase.LoginIdpLinkConfirm
| KcContextBase.LoginPageExpired;
| KcContextBase.LoginIdpLinkEmail
| KcContextBase.LoginPageExpired
| KcContextBase.LoginConfigTotp
| KcContextBase.LogoutConfirm
| KcContextBase.UpdateUserProfile
| KcContextBase.IdpReviewUserProfile;
export type WebauthnAuthenticator = {
credentialId: string;
transports: {
iconClass: KcTemplateClassKey;
displayNameProperties: MessageKeyBase[];
};
label: string;
createdAt: string;
};
export declare namespace KcContextBase {
export type Common = {
@ -46,18 +63,15 @@ export declare namespace KcContextBase {
locale?: {
supported: {
url: string;
languageTag: KcLanguageTag;
/** Is determined by languageTag. Ex: languageTag === "en" => label === "English"
* or getLanguageLabel(languageTag) === label
*/
//label: LanguageLabel;
label: string;
languageTag: string;
}[];
current: LanguageLabel;
currentLanguageTag: string;
};
auth?: {
showUsername: boolean;
showResetCredentials: boolean;
showTryAnotherWayLink: boolean;
showUsername?: boolean;
showResetCredentials?: boolean;
showTryAnotherWayLink?: boolean;
attemptedUsername?: string;
};
scripts: string[];
@ -155,7 +169,7 @@ export declare namespace KcContextBase {
export type Info = Common & {
pageId: "info.ftl";
messageHeader?: string;
requiredActions?: ExtractAfterStartingWith<"requiredAction.", MessageKey>[];
requiredActions?: ExtractAfterStartingWith<"requiredAction.", MessageKeyBase>[];
skipLink: boolean;
pageRedirectUri?: string;
actionUri?: string;
@ -181,6 +195,10 @@ export declare namespace KcContextBase {
export type LoginVerifyEmail = Common & {
pageId: "login-verify-email.ftl";
//NOTE: Optional because maybe it wasn't defined in older keycloak versions.
user?: {
email: string;
};
};
export type Terms = Common & {
@ -194,6 +212,77 @@ export declare namespace KcContextBase {
};
};
export type LoginUsername = Common & {
pageId: "login-username.ftl";
url: {
loginResetCredentialsUrl: string;
registrationUrl: string;
};
realm: {
loginWithEmailAllowed: boolean;
rememberMe: boolean;
password: boolean;
resetPasswordAllowed: boolean;
registrationAllowed: boolean;
};
registrationDisabled: boolean;
login: {
username?: string;
rememberMe?: boolean;
};
usernameHidden?: boolean;
social: {
displayInfo: boolean;
providers?: {
loginUrl: string;
alias: string;
providerId: string;
displayName: string;
}[];
};
};
export type LoginPassword = Common & {
pageId: "login-password.ftl";
url: {
loginResetCredentialsUrl: string;
registrationUrl: string;
};
realm: {
resetPasswordAllowed: boolean;
};
auth?: {
showUsername?: boolean;
showResetCredentials?: boolean;
showTryAnotherWayLink?: boolean;
attemptedUsername?: string;
};
social: {
displayInfo: boolean;
};
login: {
password?: string;
};
};
export type WebauthnAuthenticate = Common & {
pageId: "webauthn-authenticate.ftl";
authenticators: {
authenticators: WebauthnAuthenticator[];
};
challenge: string;
// I hate this:
userVerification: UserVerificationRequirement | "not specified";
rpId: string;
createTimeout: string;
isUserIdentified: "true" | "false";
shouldDisplayAuthenticators: boolean;
social: {
displayInfo: boolean;
};
login: {};
};
export type LoginUpdatePassword = Common & {
pageId: "login-update-password.ftl";
username: string;
@ -215,9 +304,76 @@ export declare namespace KcContextBase {
idpAlias: string;
};
export type LoginIdpLinkEmail = Common & {
pageId: "login-idp-link-email.ftl";
brokerContext: {
username: string;
};
idpAlias: string;
};
export type LoginPageExpired = Common & {
pageId: "login-page-expired.ftl";
};
export type LoginConfigTotp = Common & {
pageId: "login-config-totp.ftl";
mode?: "qr" | "manual" | undefined | null;
totp: {
totpSecretEncoded: string;
qrUrl: string;
policy: {
supportedApplications: string[];
algorithm: "HmacSHA1" | "HmacSHA256" | "HmacSHA512";
digits: number;
lookAheadWindow: number;
} & (
| {
type: "totp";
period: number;
}
| {
type: "hotp";
initialCounter: number;
}
);
totpSecretQrCode: string;
manualUrl: string;
totpSecret: string;
otpCredentials: { id: string; userLabel: string }[];
};
};
export type LogoutConfirm = Common & {
pageId: "logout-confirm.ftl";
url: {
logoutConfirmAction: string;
};
client: {
baseUrl?: string;
};
logoutConfirm: {
code: string;
skipLink?: boolean;
};
};
export type UpdateUserProfile = Common & {
pageId: "update-user-profile.ftl";
profile: {
attributes: Attribute[];
attributesByName: Record<string, Attribute>;
};
};
export type IdpReviewUserProfile = Common & {
pageId: "idp-review-user-profile.ftl";
profile: {
context: "IDP_REVIEW";
attributes: Attribute[];
attributesByName: Record<string, Attribute>;
};
};
}
export type Attribute = {
@ -315,6 +471,7 @@ export type Validators = Partial<{
name: string;
shouldBe: "equal" | "different";
};
options: Validators.Options;
}>;
export declare namespace Validators {
@ -331,6 +488,9 @@ export declare namespace Validators {
min?: `${number}`;
max?: `${number}`;
};
export type Options = {
options: string[];
};
}
assert<Equals<KcContextBase["pageId"], PageId>>();

View File

@ -7,6 +7,10 @@ import { exclude } from "tsafe/exclude";
import { assert } from "tsafe/assert";
import type { ExtendsKcContextBase } from "./getKcContextFromWindow";
import { getKcContextFromWindow } from "./getKcContextFromWindow";
import { pathJoin } from "../../bin/tools/pathJoin";
import { pathBasename } from "../tools/pathBasename";
import { mockTestingResourcesCommonPath } from "../../bin/mockTestingResourcesPath";
import { symToStr } from "tsafe/symToStr";
export function getKcContext<KcContextExtended extends { pageId: string } = never>(params?: {
mockPageId?: ExtendsKcContextBase<KcContextExtended>["pageId"];
@ -14,9 +18,19 @@ export function getKcContext<KcContextExtended extends { pageId: string } = neve
}): { kcContext: ExtendsKcContextBase<KcContextExtended> | undefined } {
const { mockPageId, mockData } = params ?? {};
if (mockPageId !== undefined) {
const realKcContext = getKcContextFromWindow<KcContextExtended>();
if (mockPageId !== undefined && realKcContext === undefined) {
//TODO maybe trow if no mock fo custom page
console.log(
[
`%cKeycloakify: ${symToStr({ mockPageId })} set to ${mockPageId}.`,
`If assets are missing make sure you have built your Keycloak theme at least once.`
].join(" "),
"background: red; color: yellow; font-size: medium"
);
const kcContextDefaultMock = kcContextMocks.find(({ pageId }) => pageId === mockPageId);
const partialKcContextCustomMock = mockData?.find(({ pageId }) => pageId === mockPageId);
@ -26,8 +40,8 @@ export function getKcContext<KcContextExtended extends { pageId: string } = neve
[
`WARNING: You declared the non build in page ${mockPageId} but you didn't `,
`provide mock data needed to debug the page outside of Keycloak as you are trying to do now.`,
`Please check the documentation of the getKcContext function`,
].join("\n"),
`Please check the documentation of the getKcContext function`
].join("\n")
);
}
@ -35,17 +49,25 @@ export function getKcContext<KcContextExtended extends { pageId: string } = neve
deepAssign({
"target": kcContext,
"source": kcContextDefaultMock !== undefined ? kcContextDefaultMock : { "pageId": mockPageId, ...kcContextCommonMock },
"source": kcContextDefaultMock !== undefined ? kcContextDefaultMock : { "pageId": mockPageId, ...kcContextCommonMock }
});
if (partialKcContextCustomMock !== undefined) {
deepAssign({
"target": kcContext,
"source": partialKcContextCustomMock,
"source": partialKcContextCustomMock
});
if (partialKcContextCustomMock.pageId === "register-user-profile.ftl") {
assert(kcContextDefaultMock?.pageId === "register-user-profile.ftl");
if (
partialKcContextCustomMock.pageId === "register-user-profile.ftl" ||
partialKcContextCustomMock.pageId === "update-user-profile.ftl" ||
partialKcContextCustomMock.pageId === "idp-review-user-profile.ftl"
) {
assert(
kcContextDefaultMock?.pageId === "register-user-profile.ftl" ||
kcContextDefaultMock?.pageId === "update-user-profile.ftl" ||
kcContextDefaultMock?.pageId === "idp-review-user-profile.ftl"
);
const { attributes } = kcContextDefaultMock.profile;
@ -53,7 +75,7 @@ export function getKcContext<KcContextExtended extends { pageId: string } = neve
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName = {};
const partialAttributes = [
...((partialKcContextCustomMock as DeepPartial<KcContextBase.RegisterUserProfile>).profile?.attributes ?? []),
...((partialKcContextCustomMock as DeepPartial<KcContextBase.RegisterUserProfile>).profile?.attributes ?? [])
].filter(exclude(undefined));
attributes.forEach(attribute => {
@ -63,7 +85,7 @@ export function getKcContext<KcContextExtended extends { pageId: string } = neve
deepAssign({
"target": augmentedAttribute,
"source": attribute,
"source": attribute
});
if (partialAttribute !== undefined) {
@ -71,7 +93,7 @@ export function getKcContext<KcContextExtended extends { pageId: string } = neve
deepAssign({
"target": augmentedAttribute,
"source": partialAttribute,
"source": partialAttribute
});
}
@ -79,19 +101,31 @@ export function getKcContext<KcContextExtended extends { pageId: string } = neve
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName[augmentedAttribute.name] = augmentedAttribute;
});
partialAttributes.forEach(partialAttribute => {
const { name } = partialAttribute;
partialAttributes
.map(partialAttribute => ({ "validators": {}, ...partialAttribute }))
.forEach(partialAttribute => {
const { name } = partialAttribute;
assert(name !== undefined, "If you define a mock attribute it must have at least a name");
assert(name !== undefined, "If you define a mock attribute it must have at least a name");
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributes.push(partialAttribute as any);
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName[name] = partialAttribute as any;
});
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributes.push(partialAttribute as any);
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName[name] = partialAttribute as any;
});
}
}
return { kcContext };
}
return { "kcContext": getKcContextFromWindow<KcContextExtended>() };
if (realKcContext === undefined) {
return { "kcContext": undefined };
}
{
const { url } = realKcContext;
url.resourcesCommonPath = pathJoin(url.resourcesPath, pathBasename(mockTestingResourcesCommonPath));
}
return { "kcContext": realKcContext };
}

View File

@ -1,6 +1,6 @@
import type { KcContextBase } from "./KcContextBase";
import type { AndByDiscriminatingKey } from "../tools/AndByDiscriminatingKey";
import { ftlValuesGlobalName } from "../../bin/build-keycloak-theme/ftlValuesGlobalName";
import { ftlValuesGlobalName } from "../../bin/keycloakify/ftlValuesGlobalName";
export type ExtendsKcContextBase<KcContextExtended extends { pageId: string }> = [KcContextExtended] extends [never]
? KcContextBase

View File

@ -0,0 +1,500 @@
import "minimal-polyfills/Object.fromEntries";
import type { KcContextBase, Attribute } from "./KcContextBase";
//NOTE: Aside because we want to be able to import them from node
import { mockTestingResourcesCommonPath, mockTestingResourcesPath } from "../../bin/mockTestingResourcesPath";
import { id } from "tsafe/id";
import { pathJoin } from "../../bin/tools/pathJoin";
const PUBLIC_URL = process.env["PUBLIC_URL"] ?? "/";
const attributes: Attribute[] = [
{
"validators": {
"username-prohibited-characters": {
"ignore.empty.value": true
},
"up-username-has-value": {},
"length": {
"ignore.empty.value": true,
"min": "3",
"max": "255"
},
"up-duplicate-username": {},
"up-username-mutation": {}
},
"displayName": "${username}",
"annotations": {},
"required": true,
"groupAnnotations": {},
"autocomplete": "username",
"readOnly": false,
"name": "username",
"value": "xxxx"
},
{
"validators": {
"up-email-exists-as-username": {},
"length": {
"max": "255",
"ignore.empty.value": true
},
"up-blank-attribute-value": {
"error-message": "missingEmailMessage",
"fail-on-null": false
},
"up-duplicate-email": {},
"email": {
"ignore.empty.value": true
},
"pattern": {
"ignore.empty.value": true,
"pattern": "gmail\\.com$"
}
},
"displayName": "${email}",
"annotations": {},
"required": true,
"groupAnnotations": {},
"autocomplete": "email",
"readOnly": false,
"name": "email"
},
{
"validators": {
"length": {
"max": "255",
"ignore.empty.value": true
},
"person-name-prohibited-characters": {
"ignore.empty.value": true
},
"up-immutable-attribute": {},
"up-attribute-required-by-metadata-value": {}
},
"displayName": "${firstName}",
"annotations": {},
"required": true,
"groupAnnotations": {},
"readOnly": false,
"name": "firstName"
},
{
"validators": {
"length": {
"max": "255",
"ignore.empty.value": true
},
"person-name-prohibited-characters": {
"ignore.empty.value": true
},
"up-immutable-attribute": {},
"up-attribute-required-by-metadata-value": {}
},
"displayName": "${lastName}",
"annotations": {},
"required": true,
"groupAnnotations": {},
"readOnly": false,
"name": "lastName"
}
];
const attributesByName = Object.fromEntries(attributes.map(attribute => [attribute.name, attribute])) as any;
export const kcContextCommonMock: KcContextBase.Common = {
"url": {
"loginAction": "#",
"resourcesPath": pathJoin(PUBLIC_URL, mockTestingResourcesPath),
"resourcesCommonPath": pathJoin(PUBLIC_URL, mockTestingResourcesCommonPath),
"loginRestartFlowUrl": "/auth/realms/myrealm/login-actions/restart?client_id=account&tab_id=HoAx28ja4xg",
"loginUrl": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg"
},
"realm": {
"name": "myrealm",
"displayName": "myrealm",
"displayNameHtml": "myrealm",
"internationalizationEnabled": true,
"registrationEmailAsUsername": false
},
"messagesPerField": {
"printIfExists": () => {
console.log("coucou");
return undefined;
},
"existsError": () => false,
"get": key => `Fake error for ${key}`,
"exists": () => false
},
"locale": {
"supported": [
/* spell-checker: disable */
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=de",
"label": "Deutsch",
"languageTag": "de"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=no",
"label": "Norsk",
"languageTag": "no"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ru",
"label": "РуссĐșĐžĐč",
"languageTag": "ru"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=sv",
"label": "Svenska",
"languageTag": "sv"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=pt-BR",
"label": "PortuguĂȘs (Brasil)",
"languageTag": "pt-BR"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=lt",
"label": "LietuviĆł",
"languageTag": "lt"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=en",
"label": "English",
"languageTag": "en"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=it",
"label": "Italiano",
"languageTag": "it"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=fr",
"label": "Français",
"languageTag": "fr"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=zh-CN",
"label": "äž­æ–‡çź€äœ“",
"languageTag": "zh-CN"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=es",
"label": "Español",
"languageTag": "es"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=cs",
"label": "Čeơtina",
"languageTag": "cs"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ja",
"label": "æ—„æœŹèȘž",
"languageTag": "ja"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=sk",
"label": "Slovenčina",
"languageTag": "sk"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=pl",
"label": "Polski",
"languageTag": "pl"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ca",
"label": "CatalĂ ",
"languageTag": "ca"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=nl",
"label": "Nederlands",
"languageTag": "nl"
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=tr",
"label": "TĂŒrkçe",
"languageTag": "tr"
}
/* spell-checker: enable */
],
"currentLanguageTag": "en"
},
"auth": {
"showUsername": false,
"showResetCredentials": false,
"showTryAnotherWayLink": false
},
"client": {
"clientId": "myApp"
},
"scripts": [],
"message": {
"type": "success",
"summary": "This is a test message"
},
"isAppInitiatedAction": false
};
const loginUrl = {
...kcContextCommonMock.url,
"loginResetCredentialsUrl": "/auth/realms/myrealm/login-actions/reset-credentials?client_id=account&tab_id=HoAx28ja4xg",
"registrationUrl": "/auth/realms/myrealm/login-actions/registration?client_id=account&tab_id=HoAx28ja4xg"
};
export const kcContextMocks: KcContextBase[] = [
id<KcContextBase.Login>({
...kcContextCommonMock,
"pageId": "login.ftl",
"url": loginUrl,
"realm": {
...kcContextCommonMock.realm,
"loginWithEmailAllowed": true,
"rememberMe": true,
"password": true,
"resetPasswordAllowed": true,
"registrationAllowed": true
},
"auth": kcContextCommonMock.auth!,
"social": {
"displayInfo": true
},
"usernameEditDisabled": false,
"login": {
"rememberMe": false
},
"registrationDisabled": false
}),
...(() => {
const registerCommon: KcContextBase.RegisterCommon = {
...kcContextCommonMock,
"url": {
...loginUrl,
"registrationAction":
"http://localhost:8080/auth/realms/myrealm/login-actions/registration?session_code=gwZdUeO7pbYpFTRxiIxRg_QtzMbtFTKrNu6XW_f8asM&execution=12146ce0-b139-4bbd-b25b-0eccfee6577e&client_id=account&tab_id=uS8lYfebLa0"
},
"scripts": [],
"isAppInitiatedAction": false,
"passwordRequired": true,
"recaptchaRequired": false,
"social": {
"displayInfo": true
}
};
return [
id<KcContextBase.Register>({
"pageId": "register.ftl",
...registerCommon,
"register": {
"formData": {}
}
}),
id<KcContextBase.RegisterUserProfile>({
"pageId": "register-user-profile.ftl",
...registerCommon,
"profile": {
"context": "REGISTRATION_PROFILE" as const,
attributes,
attributesByName
}
})
];
})(),
id<KcContextBase.Info>({
...kcContextCommonMock,
"pageId": "info.ftl",
"messageHeader": "<Message header>",
"requiredActions": undefined,
"skipLink": false,
"actionUri": "#",
"client": {
"clientId": "myApp",
"baseUrl": "#"
}
}),
id<KcContextBase.Error>({
...kcContextCommonMock,
"pageId": "error.ftl",
"client": {
"clientId": "myApp",
"baseUrl": "#"
},
"message": {
"type": "error",
"summary": "This is the error message"
}
}),
id<KcContextBase.LoginResetPassword>({
...kcContextCommonMock,
"pageId": "login-reset-password.ftl",
"realm": {
...kcContextCommonMock.realm,
"loginWithEmailAllowed": false
}
}),
id<KcContextBase.LoginVerifyEmail>({
...kcContextCommonMock,
"pageId": "login-verify-email.ftl",
"user": {
"email": "john.doe@gmail.com"
}
}),
id<KcContextBase.Terms>({
...kcContextCommonMock,
"pageId": "terms.ftl"
}),
id<KcContextBase.LoginOtp>({
...kcContextCommonMock,
"pageId": "login-otp.ftl",
"otpLogin": {
"userOtpCredentials": [
{
"id": "id1",
"userLabel": "label1"
},
{
"id": "id2",
"userLabel": "label2"
}
]
}
}),
id<KcContextBase.LoginUsername>({
...kcContextCommonMock,
"pageId": "login-username.ftl",
"url": loginUrl,
"realm": {
...kcContextCommonMock.realm,
"loginWithEmailAllowed": true,
"rememberMe": true,
"password": true,
"resetPasswordAllowed": true,
"registrationAllowed": true
},
"social": {
"displayInfo": true
},
"usernameHidden": false,
"login": {
"rememberMe": false
},
"registrationDisabled": false
}),
id<KcContextBase.LoginPassword>({
...kcContextCommonMock,
"pageId": "login-password.ftl",
"url": loginUrl,
"realm": {
...kcContextCommonMock.realm,
"resetPasswordAllowed": true
},
"social": {
"displayInfo": false
},
"login": {}
}),
id<KcContextBase.WebauthnAuthenticate>({
...kcContextCommonMock,
"pageId": "webauthn-authenticate.ftl",
"url": loginUrl,
"authenticators": {
"authenticators": []
},
"realm": {
...kcContextCommonMock.realm
},
"challenge": "",
"userVerification": "not specified",
"rpId": "",
"createTimeout": "0",
"isUserIdentified": "false",
"shouldDisplayAuthenticators": false,
"social": {
"displayInfo": false
},
"login": {}
}),
id<KcContextBase.LoginUpdatePassword>({
...kcContextCommonMock,
"pageId": "login-update-password.ftl",
"username": "anUsername"
}),
id<KcContextBase.LoginUpdateProfile>({
...kcContextCommonMock,
"pageId": "login-update-profile.ftl",
"user": {
"editUsernameAllowed": true,
"username": "anUsername",
"email": "foo@example.com",
"firstName": "aFirstName",
"lastName": "aLastName"
}
}),
id<KcContextBase.LoginIdpLinkConfirm>({
...kcContextCommonMock,
"pageId": "login-idp-link-confirm.ftl",
"idpAlias": "FranceConnect"
}),
id<KcContextBase.LoginIdpLinkEmail>({
...kcContextCommonMock,
"pageId": "login-idp-link-email.ftl",
"idpAlias": "FranceConnect",
"brokerContext": {
"username": "anUsername"
}
}),
id<KcContextBase.LoginConfigTotp>({
...kcContextCommonMock,
"pageId": "login-config-totp.ftl",
totp: {
totpSecretEncoded: "KVVF G2BY N4YX S6LB IUYT K2LH IFYE 4SBV",
qrUrl: "#",
totpSecretQrCode:
"iVBORw0KGgoAAAANSUhEUgAAAPYAAAD2AQAAAADNaUdlAAACM0lEQVR4Xu3OIZJgOQwDUDFd2UxiurLAVnnbHw4YGDKtSiWOn4Gxf81//7r/+q8b4HfLGBZDK9d85NmNR+sB42sXvOYrN5P1DcgYYFTGfOlbzE8gzwy3euweGizw7cfdl34/GRhlkxjKNV+5AebPXPORX1JuB9x8ZfbyyD2y1krWAKsbMq1HnqQDaLfa77p4+MqvzEGSqvSAD/2IHW2yHaigR9tX3m8dDIYGcNf3f+gDpVBZbZU77zyJ6Rlcy+qoTMG887KAPD9hsh6a1Sv3gJUHGHUAxSMzj7zqDDe7Phmt2eG+8UsMxjRGm816MAO+8VMl1R1jGHOrZB/5Zo/WXAPgxixm9Mo96vDGrM1eOto8c4Ax4wF437mifOXlpiPzCnN7Y9l95NnEMxgMY9AAGA8fucH14Y1aVb6N/cqrmyh0BVht7k1e+bU8LK0Cg5vmVq9c5vHIjOfqxDIfeTraNVTwewa4wVe+SW5N+uP1qACeudUZbqGOfA6VZV750Noq2Xx3kpveV44ZelSV1V7KFHzkWyVrrlUwG0Pl9pWnoy3vsQoME6vKI69i5osVgwWzHT7zjmJtMcNUSVn1oYMd7ZodbgowZl45VG0uVuLPUr1yc79uaQBag/mqR34xhlWyHm1prplHboCWdZ4TeZjsK8+dI+jbz1C5hl65mcpgB5dhcj8+dGO+0Ko68+lD37JDD83dpDLzzK+TrQyaVwGj6pUboGV+7+AyN8An/pf84/7rv/4/1l4OCc/1BYMAAAAASUVORK5CYII=",
manualUrl: "#",
totpSecret: "G4nsI8lQagRMUchH8jEG",
otpCredentials: [],
policy: {
supportedApplications: ["FreeOTP", "Google Authenticator"],
algorithm: "HmacSHA1",
digits: 6,
lookAheadWindow: 1,
type: "totp",
period: 30
}
}
}),
id<KcContextBase.LogoutConfirm>({
...kcContextCommonMock,
"pageId": "logout-confirm.ftl",
"url": {
...kcContextCommonMock.url,
"logoutConfirmAction": "Continuer?"
},
"client": {
"clientId": "myApp",
"baseUrl": "#"
},
"logoutConfirm": { "code": "123", skipLink: false }
}),
id<KcContextBase.UpdateUserProfile>({
...kcContextCommonMock,
"pageId": "update-user-profile.ftl",
"profile": {
attributes,
attributesByName
}
}),
id<KcContextBase.IdpReviewUserProfile>({
...kcContextCommonMock,
"pageId": "idp-review-user-profile.ftl",
"profile": {
context: "IDP_REVIEW",
attributes,
attributesByName
}
})
];

View File

@ -1 +0,0 @@
export * from "./kcContextMocks";

View File

@ -1,370 +0,0 @@
import "minimal-polyfills/Object.fromEntries";
import type { KcContextBase, Attribute } from "../KcContextBase";
import { getEvtKcLanguage } from "../../i18n/useKcLanguageTag";
import { getKcLanguageTagLabel } from "../../i18n/KcLanguageTag";
//NOTE: Aside because we want to be able to import them from node
import { resourcesCommonPath, resourcesPath } from "./urlResourcesPath";
import { id } from "tsafe/id";
import { pathJoin } from "../../tools/pathJoin";
const PUBLIC_URL = process.env["PUBLIC_URL"] ?? "/";
export const kcContextCommonMock: KcContextBase.Common = {
"url": {
"loginAction": "#",
"resourcesPath": pathJoin(PUBLIC_URL, resourcesPath),
"resourcesCommonPath": pathJoin(PUBLIC_URL, resourcesCommonPath),
"loginRestartFlowUrl": "/auth/realms/myrealm/login-actions/restart?client_id=account&tab_id=HoAx28ja4xg",
"loginUrl": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg",
},
"realm": {
"name": "myrealm",
"displayName": "myrealm",
"displayNameHtml": "myrealm",
"internationalizationEnabled": true,
"registrationEmailAsUsername": false,
},
"messagesPerField": {
"printIfExists": (...[, x]) => x,
"existsError": () => true,
"get": key => `Fake error for ${key}`,
"exists": () => true,
},
"locale": {
"supported": [
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=de",
"languageTag": "de",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=no",
"languageTag": "no",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ru",
"languageTag": "ru",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=sv",
"languageTag": "sv",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=pt-BR",
"languageTag": "pt-BR",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=lt",
"languageTag": "lt",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=en",
"languageTag": "en",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=it",
"languageTag": "it",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=fr",
"languageTag": "fr",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=zh-CN",
"languageTag": "zh-CN",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=es",
"languageTag": "es",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=cs",
"languageTag": "cs",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ja",
"languageTag": "ja",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=sk",
"languageTag": "sk",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=pl",
"languageTag": "pl",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ca",
"languageTag": "ca",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=nl",
"languageTag": "nl",
},
{
"url": "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=tr",
"languageTag": "tr",
},
],
//"current": null as any
"current": "English",
},
"auth": {
"showUsername": false,
"showResetCredentials": false,
"showTryAnotherWayLink": false,
},
"client": {
"clientId": "myApp",
},
"scripts": [],
"message": {
"type": "success",
"summary": "This is a test message",
},
"isAppInitiatedAction": false,
};
Object.defineProperty(kcContextCommonMock.locale!, "current", {
"get": () => getKcLanguageTagLabel(getEvtKcLanguage().state),
"enumerable": true,
});
const loginUrl = {
...kcContextCommonMock.url,
"loginResetCredentialsUrl": "/auth/realms/myrealm/login-actions/reset-credentials?client_id=account&tab_id=HoAx28ja4xg",
"registrationUrl": "/auth/realms/myrealm/login-actions/registration?client_id=account&tab_id=HoAx28ja4xg",
};
export const kcContextMocks: KcContextBase[] = [
id<KcContextBase.Login>({
...kcContextCommonMock,
"pageId": "login.ftl",
"url": loginUrl,
"realm": {
...kcContextCommonMock.realm,
"loginWithEmailAllowed": true,
"rememberMe": true,
"password": true,
"resetPasswordAllowed": true,
"registrationAllowed": true,
},
"auth": kcContextCommonMock.auth!,
"social": {
"displayInfo": true,
},
"usernameEditDisabled": false,
"login": {
"rememberMe": false,
},
"registrationDisabled": false,
}),
...(() => {
const registerCommon: KcContextBase.RegisterCommon = {
...kcContextCommonMock,
"url": {
...loginUrl,
"registrationAction":
"http://localhost:8080/auth/realms/myrealm/login-actions/registration?session_code=gwZdUeO7pbYpFTRxiIxRg_QtzMbtFTKrNu6XW_f8asM&execution=12146ce0-b139-4bbd-b25b-0eccfee6577e&client_id=account&tab_id=uS8lYfebLa0",
},
"scripts": [],
"isAppInitiatedAction": false,
"passwordRequired": true,
"recaptchaRequired": false,
"social": {
"displayInfo": true,
},
};
return [
id<KcContextBase.Register>({
"pageId": "register.ftl",
...registerCommon,
"register": {
"formData": {},
},
}),
id<KcContextBase.RegisterUserProfile>({
"pageId": "register-user-profile.ftl",
...registerCommon,
"profile": {
"context": "REGISTRATION_PROFILE" as const,
...(() => {
const attributes: Attribute[] = [
{
"validators": {
"username-prohibited-characters": {
"ignore.empty.value": true,
},
"up-username-has-value": {},
"length": {
"ignore.empty.value": true,
"min": "3",
"max": "255",
},
"up-duplicate-username": {},
"up-username-mutation": {},
},
"displayName": "${username}",
"annotations": {},
"required": true,
"groupAnnotations": {},
"autocomplete": "username",
"readOnly": false,
"name": "username",
"value": "xxxx",
},
{
"validators": {
"up-email-exists-as-username": {},
"length": {
"max": "255",
"ignore.empty.value": true,
},
"up-blank-attribute-value": {
"error-message": "missingEmailMessage",
"fail-on-null": false,
},
"up-duplicate-email": {},
"email": {
"ignore.empty.value": true,
},
"pattern": {
"ignore.empty.value": true,
"pattern": "gmail\\.com$",
},
},
"displayName": "${email}",
"annotations": {},
"required": true,
"groupAnnotations": {},
"autocomplete": "email",
"readOnly": false,
"name": "email",
},
{
"validators": {
"length": {
"max": "255",
"ignore.empty.value": true,
},
"person-name-prohibited-characters": {
"ignore.empty.value": true,
},
"up-immutable-attribute": {},
"up-attribute-required-by-metadata-value": {},
},
"displayName": "${firstName}",
"annotations": {},
"required": true,
"groupAnnotations": {},
"readOnly": false,
"name": "firstName",
},
{
"validators": {
"length": {
"max": "255",
"ignore.empty.value": true,
},
"person-name-prohibited-characters": {
"ignore.empty.value": true,
},
"up-immutable-attribute": {},
"up-attribute-required-by-metadata-value": {},
},
"displayName": "${lastName}",
"annotations": {},
"required": true,
"groupAnnotations": {},
"readOnly": false,
"name": "lastName",
},
];
return {
attributes,
"attributesByName": Object.fromEntries(attributes.map(attribute => [attribute.name, attribute])) as any,
} as any;
})(),
},
}),
];
})(),
id<KcContextBase.Info>({
...kcContextCommonMock,
"pageId": "info.ftl",
"messageHeader": "<Message header>",
"requiredActions": undefined,
"skipLink": false,
"actionUri": "#",
"client": {
"clientId": "myApp",
"baseUrl": "#",
},
}),
id<KcContextBase.Error>({
...kcContextCommonMock,
"pageId": "error.ftl",
"client": {
"clientId": "myApp",
"baseUrl": "#",
},
"message": {
"type": "error",
"summary": "This is the error message",
},
}),
id<KcContextBase.LoginResetPassword>({
...kcContextCommonMock,
"pageId": "login-reset-password.ftl",
"realm": {
...kcContextCommonMock.realm,
"loginWithEmailAllowed": false,
},
}),
id<KcContextBase.LoginVerifyEmail>({
...kcContextCommonMock,
"pageId": "login-verify-email.ftl",
}),
id<KcContextBase.Terms>({
...kcContextCommonMock,
"pageId": "terms.ftl",
}),
id<KcContextBase.LoginOtp>({
...kcContextCommonMock,
"pageId": "login-otp.ftl",
"otpLogin": {
"userOtpCredentials": [
{
"id": "id1",
"userLabel": "label1",
},
{
"id": "id2",
"userLabel": "label2",
},
],
},
}),
id<KcContextBase.LoginUpdatePassword>({
...kcContextCommonMock,
"pageId": "login-update-password.ftl",
"username": "anUsername",
}),
id<KcContextBase.LoginUpdateProfile>({
...kcContextCommonMock,
"pageId": "login-update-profile.ftl",
"user": {
"editUsernameAllowed": true,
"username": "anUsername",
"email": "foo@example.com",
"firstName": "aFirstName",
"lastName": "aLastName",
},
}),
id<KcContextBase.LoginIdpLinkConfirm>({
...kcContextCommonMock,
"pageId": "login-idp-link-confirm.ftl",
"idpAlias": "FranceConnect",
}),
];

View File

@ -1,5 +0,0 @@
import { pathJoin } from "../../tools/pathJoin";
export const subDirOfPublicDirBasename = "keycloak_static";
export const resourcesPath = pathJoin(subDirOfPublicDirBasename, "resources");
export const resourcesCommonPath = pathJoin(subDirOfPublicDirBasename, "resources_common");

View File

@ -1,63 +0,0 @@
import { objectKeys } from "tsafe/objectKeys";
import { kcMessages } from "./kcMessages/login";
export type KcLanguageTag = keyof typeof kcMessages;
const kcLanguageByTagLabel = {
/* spell-checker: disable */
"es": "Español",
"it": "Italiano",
"fr": "Français",
"ca": "CatalĂ ",
"en": "English",
"de": "Deutsch",
"no": "Norsk",
"pt-BR": "PortuguĂȘs (Brasil)",
"ru": "РуссĐșĐžĐč",
"sk": "Slovenčina",
"ja": "æ—„æœŹèȘž",
"pl": "Polski",
"zh-CN": "äž­æ–‡çź€äœ“",
"sv": "Svenska",
"lt": "LietuviĆł",
"cs": "Čeơtina",
"nl": "Nederlands",
"tr": "TĂŒrkçe",
"da": "Dansk",
"hu": "Magyar",
/* spell-checker: enable */
} as const;
export type LanguageLabel = typeof kcLanguageByTagLabel[keyof typeof kcLanguageByTagLabel];
export function getKcLanguageTagLabel(language: KcLanguageTag): LanguageLabel {
return kcLanguageByTagLabel[language] ?? language;
}
export const kcLanguageTags = objectKeys(kcMessages);
/**
* Pass in "fr-FR" or "français" for example, it will return the AvailableLanguage
* it corresponds to: "fr".
* If there is no reasonable match it's guessed from navigator.language.
* If still no matches "en" is returned.
*/
export function getBestMatchAmongKcLanguageTag(languageLike: string): KcLanguageTag {
const iso2LanguageLike = languageLike.split("-")[0].toLowerCase();
const kcLanguageTag = kcLanguageTags.find(
language =>
language.toLowerCase().includes(iso2LanguageLike) ||
getKcLanguageTagLabel(language).toLocaleLowerCase() === languageLike.toLocaleLowerCase(),
);
if (kcLanguageTag !== undefined) {
return kcLanguageTag;
}
if (languageLike !== navigator.language) {
return getBestMatchAmongKcLanguageTag(navigator.language);
}
return "en";
}

File diff suppressed because it is too large Load Diff

View File

@ -1,253 +0,0 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
export const kcMessages = {
"ca": {
"invalidPasswordHistoryMessage": "Contrasenya incorrecta: no pot ser igual a cap de les Ășltimes {0} contrasenyes.",
"invalidPasswordMinDigitsMessage": "Contraseña incorrecta: debe contener al menos {0} caracteres numéricos.",
"invalidPasswordMinLengthMessage": "Contrasenya incorrecta: longitud mĂ­nima {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres minĂșscules.",
"invalidPasswordMinSpecialCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} carĂ cters especials.",
"invalidPasswordMinUpperCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres majĂșscules.",
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d'usuari.",
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l'expressiĂł regular.",
},
"de": {
"invalidPasswordMinLengthMessage": "UngĂŒltiges Passwort: muss mindestens {0} Zeichen beinhalten.",
"invalidPasswordMinLowerCaseCharsMessage": "UngĂŒltiges Passwort: muss mindestens {0} Kleinbuchstaben beinhalten.",
"invalidPasswordMinDigitsMessage": "UngĂŒltiges Passwort: muss mindestens {0} Ziffern beinhalten.",
"invalidPasswordMinUpperCaseCharsMessage": "UngĂŒltiges Passwort: muss mindestens {0} Großbuchstaben beinhalten.",
"invalidPasswordMinSpecialCharsMessage": "UngĂŒltiges Passwort: muss mindestens {0} Sonderzeichen beinhalten.",
"invalidPasswordNotUsernameMessage": "UngĂŒltiges Passwort: darf nicht identisch mit dem Benutzernamen sein.",
"invalidPasswordRegexPatternMessage": "UngĂŒltiges Passwort: stimmt nicht mit Regex-Muster ĂŒberein.",
"invalidPasswordHistoryMessage": "UngĂŒltiges Passwort: darf nicht identisch mit einem der letzten {0} Passwörter sein.",
"invalidPasswordBlacklistedMessage": "UngĂŒltiges Passwort: Passwort ist zu bekannt und auf der schwarzen Liste.",
"invalidPasswordGenericMessage": "UngĂŒltiges Passwort: neues Passwort erfĂŒllt die Passwort-Anforderungen nicht.",
},
"en": {
"invalidPasswordMinLengthMessage": "Invalid password: minimum length {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Invalid password: must contain at least {0} lower case characters.",
"invalidPasswordMinDigitsMessage": "Invalid password: must contain at least {0} numerical digits.",
"invalidPasswordMinUpperCaseCharsMessage": "Invalid password: must contain at least {0} upper case characters.",
"invalidPasswordMinSpecialCharsMessage": "Invalid password: must contain at least {0} special characters.",
"invalidPasswordNotUsernameMessage": "Invalid password: must not be equal to the username.",
"invalidPasswordRegexPatternMessage": "Invalid password: fails to match regex pattern(s).",
"invalidPasswordHistoryMessage": "Invalid password: must not be equal to any of last {0} passwords.",
"invalidPasswordBlacklistedMessage": "Invalid password: password is blacklisted.",
"invalidPasswordGenericMessage": "Invalid password: new password does not match password policies.",
"ldapErrorInvalidCustomFilter": 'Custom configured LDAP filter does not start with "(" or does not end with ")".',
"ldapErrorConnectionTimeoutNotNumber": "Connection Timeout must be a number",
"ldapErrorReadTimeoutNotNumber": "Read Timeout must be a number",
"ldapErrorMissingClientId": "Client ID needs to be provided in config when Realm Roles Mapping is not used.",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType":
"Not possible to preserve group inheritance and use UID membership type together.",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "Can not set write only when LDAP provider mode is not WRITABLE",
"ldapErrorCantWriteOnlyAndReadOnly": "Can not set write-only and read-only together",
"ldapErrorCantEnableStartTlsAndConnectionPooling": "Can not enable both StartTLS and connection pooling.",
"ldapErrorCantEnableUnsyncedAndImportOff": "Can not disable Importing users when LDAP provider mode is UNSYNCED",
"ldapErrorMissingGroupsPathGroup": "Groups path group does not exist - please create the group on specified path first",
"clientRedirectURIsFragmentError": "Redirect URIs must not contain an URI fragment",
"clientRootURLFragmentError": "Root URL must not contain an URL fragment",
"clientRootURLIllegalSchemeError": "Root URL uses an illegal scheme",
"clientBaseURLIllegalSchemeError": "Base URL uses an illegal scheme",
"clientRedirectURIsIllegalSchemeError": "A redirect URI uses an illegal scheme",
"clientBaseURLInvalid": "Base URL is not a valid URL",
"clientRootURLInvalid": "Root URL is not a valid URL",
"clientRedirectURIsInvalid": "A redirect URI is not a valid URI",
"pairwiseMalformedClientRedirectURI": "Client contained an invalid redirect URI.",
"pairwiseClientRedirectURIsMissingHost": "Client redirect URIs must contain a valid host component.",
"pairwiseClientRedirectURIsMultipleHosts":
"Without a configured Sector Identifier URI, client redirect URIs must not contain multiple host components.",
"pairwiseMalformedSectorIdentifierURI": "Malformed Sector Identifier URI.",
"pairwiseFailedToGetRedirectURIs": "Failed to get redirect URIs from the Sector Identifier URI.",
"pairwiseRedirectURIsMismatch": "Client redirect URIs does not match redirect URIs fetched from the Sector Identifier URI.",
},
"es": {
"invalidPasswordMinLengthMessage": "Contraseña incorrecta: longitud mínima {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Contraseña incorrecta: debe contener al menos {0} letras minĂșsculas.",
"invalidPasswordMinDigitsMessage": "Contraseña incorrecta: debe contener al menos {0} caracteres numéricos.",
"invalidPasswordMinUpperCaseCharsMessage": "Contraseña incorrecta: debe contener al menos {0} letras mayĂșsculas.",
"invalidPasswordMinSpecialCharsMessage": "Contraseña incorrecta: debe contener al menos {0} caracteres especiales.",
"invalidPasswordNotUsernameMessage": "Contraseña incorrecta: no puede ser igual al nombre de usuario.",
"invalidPasswordRegexPatternMessage": "Contraseña incorrecta: no cumple la expresión regular.",
"invalidPasswordHistoryMessage": "Contraseña incorrecta: no puede ser igual a ninguna de las Ășltimas {0} contraseñas.",
},
"fr": {
"invalidPasswordMinLengthMessage": "Mot de passe invalide : longueur minimale requise de {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Mot de passe invalide : doit contenir au moins {0} lettre(s) en minuscule.",
"invalidPasswordMinDigitsMessage": "Mot de passe invalide : doit contenir au moins {0} chiffre(s).",
"invalidPasswordMinUpperCaseCharsMessage": "Mot de passe invalide : doit contenir au moins {0} lettre(s) en majuscule.",
"invalidPasswordMinSpecialCharsMessage": "Mot de passe invalide : doit contenir au moins {0} caractÚre(s) spéciaux.",
"invalidPasswordNotUsernameMessage": "Mot de passe invalide : ne doit pas ĂȘtre identique au nom d'utilisateur.",
"invalidPasswordRegexPatternMessage": "Mot de passe invalide : ne valide pas l'expression rationnelle.",
"invalidPasswordHistoryMessage": "Mot de passe invalide : ne doit pas ĂȘtre Ă©gal aux {0} derniers mot de passe.",
},
"it": {},
"ja": {
"invalidPasswordMinLengthMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: æœ€ć°{0}ăźé•·ă•ăŒćż…èŠă§ă™ă€‚",
"invalidPasswordMinLowerCaseCharsMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: 民ăȘくべも{0}æ–‡ć­—ăźć°æ–‡ć­—ă‚’ć«ă‚€ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"invalidPasswordMinDigitsMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: 民ăȘくべも{0}æ–‡ć­—ăźæ•°ć­—ă‚’ć«ă‚€ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"invalidPasswordMinUpperCaseCharsMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: 民ăȘくべも{0}æ–‡ć­—ăźć€§æ–‡ć­—ă‚’ć«ă‚€ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"invalidPasswordMinSpecialCharsMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: 民ăȘくべも{0}æ–‡ć­—ăźç‰čæźŠæ–‡ć­—ă‚’ć«ă‚€ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"invalidPasswordNotUsernameMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: ăƒŠăƒŒă‚¶ăƒŒćăšćŒă˜ăƒ‘ă‚čăƒŻăƒŒăƒ‰ăŻçŠæ­ąă•ă‚ŒăŠă„ăŸă™ă€‚",
"invalidPasswordRegexPatternMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: æ­ŁèŠèĄšçŸăƒ‘ă‚żăƒŒăƒłăšäž€è‡Žă—ăŸă›ă‚“ă€‚",
"invalidPasswordHistoryMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: æœ€èż‘ăź{0}パă‚čăƒŻăƒŒăƒ‰ăźă„ăšă‚Œă‹ăšćŒă˜ăƒ‘ă‚čăƒŻăƒŒăƒ‰ăŻçŠæ­ąă•ă‚ŒăŠă„ăŸă™ă€‚",
"invalidPasswordBlacklistedMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: パă‚čăƒŻăƒŒăƒ‰ăŒăƒ–ăƒ©ăƒƒă‚ŻăƒȘă‚čăƒˆă«ć«ăŸă‚ŒăŠă„ăŸă™ă€‚",
"invalidPasswordGenericMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: æ–°ă—ă„ăƒ‘ă‚čăƒŻăƒŒăƒ‰ăŻăƒ‘ă‚čăƒŻăƒŒăƒ‰ăƒ»ăƒăƒȘă‚·ăƒŒăšäž€è‡Žă—ăŸă›ă‚“ă€‚",
"ldapErrorInvalidCustomFilter": "LDAPăƒ•ă‚Łăƒ«ă‚żăƒŒăźă‚«ă‚čă‚żăƒ èš­ćźšăŒă€ă€Œ(ă€ă‹ă‚‰é–‹ć§‹ăŸăŸăŻă€Œ)ă€ă§ç”‚äș†ăšăȘăŁăŠă„ăŸă›ă‚“ă€‚",
"ldapErrorConnectionTimeoutNotNumber": "æŽ„ç¶šă‚żă‚€ăƒ ă‚ąă‚ŠăƒˆăŻæ•°ć­—ă§ăȘければăȘă‚ŠăŸă›ă‚“",
"ldapErrorReadTimeoutNotNumber": "èȘ­ăżć–ă‚Šă‚żă‚€ăƒ ă‚ąă‚ŠăƒˆăŻæ•°ć­—ă§ăȘければăȘă‚ŠăŸă›ă‚“",
"ldapErrorMissingClientId": "ăƒŹăƒ«ăƒ ăƒ­ăƒŒăƒ«ăƒ»ăƒžăƒƒăƒ”ăƒłă‚°ă‚’äœżç”šă—ăȘă„ć ŽćˆăŻă€ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆIDăŻèš­ćźšć†…ă§æäŸ›ă•ă‚Œă‚‹ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType":
"ă‚°ăƒ«ăƒŒăƒ—ăźç¶™æ‰żă‚’ç¶­æŒă™ă‚‹ă“ăšăšă€UIDăƒĄăƒłăƒăƒŒă‚·ăƒƒăƒ—ăƒ»ă‚żă‚€ăƒ—ă‚’äœżç”šă™ă‚‹ă“ăšăŻćŒæ™‚ă«ă§ăăŸă›ă‚“ă€‚",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "LDAPăƒ—ăƒ­ăƒă‚€ăƒ€ăƒŒăƒ»ăƒąăƒŒăƒ‰ăŒWRITABLEではăȘい栮搈は、write onlyă‚’èš­ćźšă™ă‚‹ă“ăšăŻă§ăăŸă›ă‚“ă€‚",
"ldapErrorCantWriteOnlyAndReadOnly": "write-onlyずread-onlyă‚’äž€ç·’ă«èš­ćźšă™ă‚‹ă“ăšăŻă§ăăŸă›ă‚“ă€‚",
"ldapErrorCantEnableStartTlsAndConnectionPooling": "StartTLSăšæŽ„ç¶šăƒ—ăƒŒăƒȘングぼ価æ–čă‚’æœ‰ćŠčă«ă§ăăŸă›ă‚“ă€‚",
"clientRedirectURIsFragmentError": "ăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIにURIăƒ•ăƒ©ă‚°ăƒĄăƒłăƒˆă‚’ć«ă‚ă‚‹ă“ăšăŻă§ăăŸă›ă‚“ă€‚",
"clientRootURLFragmentError": "ăƒ«ăƒŒăƒˆURLにURLăƒ•ăƒ©ă‚°ăƒĄăƒłăƒˆă‚’ć«ă‚ă‚‹ă“ăšăŻă§ăăŸă›ă‚“ă€‚",
"pairwiseMalformedClientRedirectURI": "ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆă«ç„ĄćŠčăȘăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIăŒć«ăŸă‚ŒăŠă„ăŸă—ăŸă€‚",
"pairwiseClientRedirectURIsMissingHost": "ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆăźăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIă«ăŻæœ‰ćŠčăȘホă‚čăƒˆăƒ»ă‚łăƒłăƒăƒŒăƒăƒłăƒˆăŒć«ăŸă‚ŒăŠă„ă‚‹ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"pairwiseClientRedirectURIsMultipleHosts":
"èš­ćźšă•ă‚ŒăŸă‚»ăƒŹă‚Żă‚żăƒŒè­˜ćˆ„ć­URIがăȘă„ć ŽćˆăŻă€ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆăźăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIăŻè€‡æ•°ăźăƒ›ă‚čăƒˆăƒ»ă‚łăƒłăƒăƒŒăƒăƒłăƒˆă‚’ć«ă‚€ă“ăšăŻă§ăăŸă›ă‚“ă€‚",
"pairwiseMalformedSectorIdentifierURI": "äžæ­ŁăȘă‚»ăƒŹă‚Żă‚żăƒŒè­˜ćˆ„ć­URIです。",
"pairwiseFailedToGetRedirectURIs": "ă‚»ă‚Żă‚żăƒŒè­˜ćˆ„ć­URIからăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIă‚’ć–ćŸ—ă§ăăŸă›ă‚“ă§ă—ăŸă€‚",
"pairwiseRedirectURIsMismatch": "ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆăźăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIăŻă€ă‚»ă‚Żă‚żăƒŒè­˜ćˆ„ć­URIからフェッチされたăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIăšäž€è‡Žă—ăŸă›ă‚“ă€‚",
},
"lt": {
"invalidPasswordMinLengthMessage": "Per trumpas slaptaĆŸodis: maĆŸiausias ilgis {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Neteisingas slaptaĆŸodis: privaloma ÄŻvesti {0} maĆŸÄ…ją raidę.",
"invalidPasswordMinDigitsMessage": "Neteisingas slaptaĆŸodis: privaloma ÄŻvesti {0} skaitmenÄŻ.",
"invalidPasswordMinUpperCaseCharsMessage": "Neteisingas slaptaĆŸodis: privaloma ÄŻvesti {0} didĆŸiąją raidę.",
"invalidPasswordMinSpecialCharsMessage": "Neteisingas slaptaĆŸodis: privaloma ÄŻvesti {0} specialĆł simbolÄŻ.",
"invalidPasswordNotUsernameMessage": "Neteisingas slaptaĆŸodis: slaptaĆŸodis negali sutapti su naudotojo vardu.",
"invalidPasswordRegexPatternMessage": "Neteisingas slaptaĆŸodis: slaptaĆŸodis netenkina regex taisyklės(iĆł).",
"invalidPasswordHistoryMessage": "Neteisingas slaptaĆŸodis: slaptaĆŸodis negali sutapti su prieĆĄ tai buvusiais {0} slaptaĆŸodĆŸiais.",
"ldapErrorInvalidCustomFilter": 'Sukonfigƫruotas LDAP filtras neprasideda "(" ir nesibaigia ")" simboliais.',
"ldapErrorMissingClientId": "Privaloma nurodyti kliento ID kai srities roliƳ susiejimas nėra nenaudojamas.",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType": "GrupiĆł paveldėjimo ir UID narystės tipas kartu negali bĆ«ti naudojami.",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "Negalima nustatyti raĆĄymo rÄ—ĆŸimo kuomet LDAP teikėjo rÄ—ĆŸimas ne WRITABLE",
"ldapErrorCantWriteOnlyAndReadOnly": "Negalima nustatyti tik raĆĄyti ir tik skaityti kartu",
"clientRedirectURIsFragmentError": "Nurodykite URI fragmentą, kurio negali bĆ«ti peradresuojamuose URI adresuose",
"clientRootURLFragmentError": "Nurodykite URL fragmentą, kurio negali bĆ«ti ĆĄakniniame URL adrese",
"pairwiseMalformedClientRedirectURI": "Klientas pateikė neteisingą nukreipimo nuorodą.",
"pairwiseClientRedirectURIsMissingHost": "Kliento nukreipimo nuorodos privalo bƫti nurodytos su serverio vardo komponentu.",
"pairwiseClientRedirectURIsMultipleHosts":
"Kuomet nesukonfigĆ«ruotas sektoriaus identifikatoriaus URL, kliento nukreipimo nuorodos privalo talpinti ne daugiau kaip vieną skirtingą serverio vardo komponentą.",
"pairwiseMalformedSectorIdentifierURI": "Neteisinga sektoriaus identifikatoriaus URI.",
"pairwiseFailedToGetRedirectURIs": "Nepavyko gauti nukreipimo nuorodĆł iĆĄ sektoriaus identifikatoriaus URI.",
"pairwiseRedirectURIsMismatch": "Kliento nukreipimo nuoroda neatitinka nukreipimo nuorodĆł iĆĄ sektoriaus identifikatoriaus URI.",
},
"nl": {
"invalidPasswordMinLengthMessage": "Ongeldig wachtwoord: de minimale lengte is {0} karakters.",
"invalidPasswordMinLowerCaseCharsMessage": "Ongeldig wachtwoord: het moet minstens {0} kleine letters bevatten.",
"invalidPasswordMinDigitsMessage": "Ongeldig wachtwoord: het moet minstens {0} getallen bevatten.",
"invalidPasswordMinUpperCaseCharsMessage": "Ongeldig wachtwoord: het moet minstens {0} hoofdletters bevatten.",
"invalidPasswordMinSpecialCharsMessage": "Ongeldig wachtwoord: het moet minstens {0} speciale karakters bevatten.",
"invalidPasswordNotUsernameMessage": "Ongeldig wachtwoord: het mag niet overeenkomen met de gebruikersnaam.",
"invalidPasswordRegexPatternMessage": "Ongeldig wachtwoord: het voldoet niet aan het door de beheerder ingestelde patroon.",
"invalidPasswordHistoryMessage": "Ongeldig wachtwoord: het mag niet overeen komen met een van de laatste {0} wachtwoorden.",
"invalidPasswordGenericMessage": "Ongeldig wachtwoord: het nieuwe wachtwoord voldoet niet aan het wachtwoordbeleid.",
"ldapErrorInvalidCustomFilter": 'LDAP filter met aangepaste configuratie start niet met "(" of eindigt niet met ")".',
"ldapErrorConnectionTimeoutNotNumber": "Verbindingstimeout moet een getal zijn",
"ldapErrorReadTimeoutNotNumber": "Lees-timeout moet een getal zijn",
"ldapErrorMissingClientId": "Client ID moet ingesteld zijn als Realm Roles Mapping niet gebruikt wordt.",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType": "Kan groepsovererving niet behouden bij UID-lidmaatschapstype.",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "Alleen-schrijven niet mogelijk als LDAP provider mode niet WRITABLE is",
"ldapErrorCantWriteOnlyAndReadOnly": "Alleen-schrijven en alleen-lezen mogen niet tegelijk ingesteld zijn",
"clientRedirectURIsFragmentError": "Redirect URIs mogen geen URI fragment bevatten",
"clientRootURLFragmentError": "Root URL mag geen URL fragment bevatten",
"pairwiseMalformedClientRedirectURI": "Client heeft een ongeldige redirect URI.",
"pairwiseClientRedirectURIsMissingHost": "Client redirect URIs moeten een geldige host-component bevatten.",
"pairwiseClientRedirectURIsMultipleHosts":
"Zonder een geconfigureerde Sector Identifier URI mogen client redirect URIs niet meerdere host componenten hebben.",
"pairwiseMalformedSectorIdentifierURI": "Onjuist notatie in Sector Identifier URI.",
"pairwiseFailedToGetRedirectURIs": "Kon geen redirect URIs verkrijgen van de Sector Identifier URI.",
"pairwiseRedirectURIsMismatch": "Client redirect URIs komen niet overeen met redict URIs ontvangen van de Sector Identifier URI.",
},
"no": {
"invalidPasswordMinLengthMessage": "Ugyldig passord: minimum lengde {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Ugyldig passord: mÄ inneholde minst {0} smÄ bokstaver.",
"invalidPasswordMinDigitsMessage": "Ugyldig passord: mÄ inneholde minst {0} sifre.",
"invalidPasswordMinUpperCaseCharsMessage": "Ugyldig passord: mÄ inneholde minst {0} store bokstaver.",
"invalidPasswordMinSpecialCharsMessage": "Ugyldig passord: mÄ inneholde minst {0} spesialtegn.",
"invalidPasswordNotUsernameMessage": "Ugyldig passord: kan ikke vĂŠre likt brukernavn.",
"invalidPasswordRegexPatternMessage": "Ugyldig passord: tilfredsstiller ikke kravene for passord-mĂžnster.",
"invalidPasswordHistoryMessage": "Ugyldig passord: kan ikke vÊre likt noen av de {0} foregÄende passordene.",
"ldapErrorInvalidCustomFilter": 'Tilpasset konfigurasjon av LDAP-filter starter ikke med "(" eller slutter ikke med ")".',
"ldapErrorMissingClientId": "KlientID mÄ vÊre tilgjengelig i config nÄr sikkerhetsdomenerollemapping ikke brukes.",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType": "Ikke mulig Ă„ bevare gruppearv og samtidig bruke UID medlemskapstype.",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "Kan ikke sette write-only nÄr LDAP leverandÞr-modus ikke er WRITABLE",
"ldapErrorCantWriteOnlyAndReadOnly": "Kan ikke sette bÄde write-only og read-only",
},
"pl": {},
"pt-BR": {
"invalidPasswordMinLengthMessage": "Senha invĂĄlida: deve conter ao menos {0} caracteres.",
"invalidPasswordMinLowerCaseCharsMessage": "Senha invĂĄlida: deve conter ao menos {0} caracteres minĂșsculos.",
"invalidPasswordMinDigitsMessage": "Senha invålida: deve conter ao menos {0} digitos numéricos.",
"invalidPasswordMinUpperCaseCharsMessage": "Senha invĂĄlida: deve conter ao menos {0} caracteres maiĂșsculos.",
"invalidPasswordMinSpecialCharsMessage": "Senha invĂĄlida: deve conter ao menos {0} caracteres especiais.",
"invalidPasswordNotUsernameMessage": "Senha invĂĄlida: nĂŁo deve ser igual ao nome de usuĂĄrio.",
"invalidPasswordRegexPatternMessage": "Senha invålida: falha ao passar por padrÔes.",
"invalidPasswordHistoryMessage": "Senha invĂĄlida: nĂŁo deve ser igual Ă s Ășltimas {0} senhas.",
"ldapErrorInvalidCustomFilter": 'Filtro LDAP nĂŁo inicia com "(" ou nĂŁo termina com ")".',
"ldapErrorMissingClientId": "ID do cliente precisa ser definido na configuração quando mapeamentos de Roles do Realm não é utilizado.",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType":
"Não é possível preservar herança de grupos e usar tipo de associação de UID ao mesmo tempo.",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "NĂŁo Ă© possĂ­vel definir modo de somente escrita quando o provedor LDAP nĂŁo suporta escrita",
"ldapErrorCantWriteOnlyAndReadOnly": "NĂŁo Ă© possĂ­vel definir somente escrita e somente leitura ao mesmo tempo",
"clientRedirectURIsFragmentError": "URIs de redirecionamento nĂŁo podem conter fragmentos",
"clientRootURLFragmentError": "URL raiz nĂŁo pode conter fragmentos",
},
"ru": {
"invalidPasswordMinLengthMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐŽĐ»ĐžĐœĐ° ĐżĐ°Ń€ĐŸĐ»Ń ĐŽĐŸĐ»Đ¶ĐœĐ° Đ±Ń‹Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} ŃĐžĐŒĐČĐŸĐ»ĐŸĐČ(а).",
"invalidPasswordMinDigitsMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} цофр(ы).",
"invalidPasswordMinLowerCaseCharsMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} ŃĐžĐŒĐČĐŸĐ»ĐŸĐČ(а) ĐČ ĐœĐžĐ¶ĐœĐ”ĐŒ рДгОстрД.",
"invalidPasswordMinUpperCaseCharsMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} ŃĐžĐŒĐČĐŸĐ»ĐŸĐČ(а) ĐČ ĐČĐ”Ń€Ń…ĐœĐ”ĐŒ рДгОстрД.",
"invalidPasswordMinSpecialCharsMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} ŃĐżĐ”Ń†ŃĐžĐŒĐČĐŸĐ»ĐŸĐČ(а).",
"invalidPasswordNotUsernameMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐœĐ” ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐČпаЮать с ĐžĐŒĐ”ĐœĐ”ĐŒ ĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Ń‚Đ”Đ»Ń.",
"invalidPasswordRegexPatternMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐœĐ” ĐżŃ€ĐŸŃˆĐ”Đ» ĐżŃ€ĐŸĐČДрĐșу ĐżĐŸ Ń€Đ”ĐłŃƒĐ»ŃŃ€ĐœĐŸĐŒŃƒ ĐČŃ‹Ń€Đ°Đ¶Đ”ĐœĐžŃŽ.",
"invalidPasswordHistoryMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐœĐ” ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐČпаЮать с ĐżĐŸŃĐ»Đ”ĐŽĐœĐžĐŒ(Đž) {0} ĐżĐ°Ń€ĐŸĐ»Đ”ĐŒ(ŃĐŒĐž).",
"invalidPasswordGenericMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐœĐŸĐČыĐč ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐœĐ” ŃĐŸĐŸŃ‚ĐČДтстĐČŃƒĐ”Ń‚ праĐČĐžĐ»Đ°ĐŒ ĐżĐ°Ń€ĐŸĐ»Ń.",
"ldapErrorInvalidCustomFilter": 'ĐĄĐșĐŸĐœŃ„ĐžĐłŃƒŃ€ĐžŃ€ĐŸĐČĐ°ĐœĐœŃ‹Đč ĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Ń‚Đ”Đ»Đ”ĐŒ Ń„ĐžĐ»ŃŒŃ‚Ń€ LDAP ĐœĐ” ĐŽĐŸĐ»Đ¶Đ”Đœ ĐœĐ°Ń‡ĐžĐœĐ°Ń‚ŃŒŃŃ с "(" ОлО заĐșĐ°ĐœŃ‡ĐžĐČаться ĐœĐ° ")".',
"ldapErrorMissingClientId": "Client ID ĐŽĐŸĐ»Đ¶Đ”Đœ Đ±Ń‹Ń‚ŃŒ ĐœĐ°ŃŃ‚Ń€ĐŸĐ”Đœ ĐČ ĐșĐŸĐœŃ„ĐžĐłŃƒŃ€Đ°Ń†ĐžĐž, ДслО ĐœĐ” ĐžŃĐżĐŸĐ»ŃŒĐ·ŃƒĐ”Ń‚ŃŃ ŃĐŸĐżĐŸŃŃ‚Đ°ĐČĐ»Đ”ĐœĐžĐ” Ń€ĐŸĐ»Đ”Đč ĐČ realm.",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType": "ĐĐ” ŃƒĐŽĐ°Đ»ĐŸŃŃŒ ŃƒĐœĐ°ŃĐ»Đ”ĐŽĐŸĐČать группу Đž ĐžŃĐżĐŸĐ»ŃŒĐ·ĐŸĐČать Ń‡Đ»Đ”ĐœŃŃ‚ĐČĐŸ UID топа ĐČĐŒĐ”ŃŃ‚Đ”.",
"ldapErrorCantWriteOnlyForReadOnlyLdap": 'ĐĐ”ĐČĐŸĐ·ĐŒĐŸĐ¶ĐœĐŸ ŃƒŃŃ‚Đ°ĐœĐŸĐČоть Ń€Đ”Đ¶ĐžĐŒ "Ń‚ĐŸĐ»ŃŒĐșĐŸ ĐœĐ° Đ·Đ°ĐżĐžŃŃŒ", ĐșĐŸĐłĐŽĐ° LDAP ĐżŃ€ĐŸĐČаĐčЎДр ĐœĐ” ĐČ Ń€Đ”Đ¶ĐžĐŒĐ” WRITABLE',
"ldapErrorCantWriteOnlyAndReadOnly": 'ĐĐ”ĐČĐŸĐ·ĐŒĐŸĐ¶ĐœĐŸ ĐŸĐŽĐœĐŸĐČŃ€Đ”ĐŒĐ”ĐœĐœĐŸ ŃƒŃŃ‚Đ°ĐœĐŸĐČоть Ń€Đ”Đ¶ĐžĐŒŃ‹ "Ń‚ĐŸĐ»ŃŒĐșĐŸ ĐœĐ° Ń‡Ń‚Đ”ĐœĐžĐ”" Đž "Ń‚ĐŸĐ»ŃŒĐșĐŸ ĐœĐ° Đ·Đ°ĐżĐžŃŃŒ"',
"clientRedirectURIsFragmentError": "URI ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžŃ ĐœĐ” ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ Ń„Ń€Đ°ĐłĐŒĐ”ĐœŃ‚ URI",
"clientRootURLFragmentError": "ĐšĐŸŃ€ĐœĐ”ĐČĐŸĐč URL ĐœĐ” ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ Ń„Ń€Đ°ĐłĐŒĐ”ĐœŃ‚ URL ",
"pairwiseMalformedClientRedirectURI": "ĐšĐ»ĐžĐ”ĐœŃ‚ ŃĐŸĐŽĐ”Ń€Đ¶ĐžŃ‚ ĐœĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč URI ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžŃ.",
"pairwiseClientRedirectURIsMissingHost": "URI ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžŃ ĐșĐ»ĐžĐ”ĐœŃ‚Đ° ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚ Ń…ĐŸŃŃ‚Đ°.",
"pairwiseClientRedirectURIsMultipleHosts":
"БДз ĐșĐŸĐœŃ„ĐžĐłŃƒŃ€Đ°Ń†ĐžĐž ĐżĐŸ часто ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Đ° URI, URI ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžŃ ĐșĐ»ĐžĐ”ĐœŃ‚Đ° ĐœĐ” ĐŒĐŸĐ¶Đ”Ń‚ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ”ŃĐșĐŸĐ»ŃŒĐșĐŸ ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚ĐŸĐČ Ń…ĐŸŃŃ‚Đ°.",
"pairwiseMalformedSectorIdentifierURI": "ИсĐșĐ°Đ¶Đ”ĐœĐœĐ°Ń часть ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Đ° URI.",
"pairwiseFailedToGetRedirectURIs": "ĐĐ” ŃƒĐŽĐ°Đ»ĐŸŃŃŒ ĐżĐŸĐ»ŃƒŃ‡ĐžŃ‚ŃŒ ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Ń‹ URI ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžŃ Оз часто ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Đ° URI.",
"pairwiseRedirectURIsMismatch": "ĐšĐ»ĐžĐ”ĐœŃ‚ URI пДрДаЎрДсацОО ĐœĐ” ŃĐŸĐŸŃ‚ĐČДтстĐČŃƒĐ”Ń‚ URI пДрДаЎрДсацОО, ĐżĐŸĐ»ŃƒŃ‡Đ”ĐœĐœĐŸĐč Оз часто ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Đ° URI.",
},
"zh-CN": {
"invalidPasswordMinLengthMessage": "æ— æ•ˆçš„ćŻ†ç ïŒšæœ€çŸ­é•żćșŠ {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "æ— æ•ˆçš„ćŻ†ç ïŒšè‡łć°‘ćŒ…ć« {0} ć°ć†™ć­—æŻ",
"invalidPasswordMinDigitsMessage": "æ— æ•ˆçš„ćŻ†ç ïŒšè‡łć°‘ćŒ…ć« {0} äžȘæ•°ć­—",
"invalidPasswordMinUpperCaseCharsMessage": "æ— æ•ˆçš„ćŻ†ç ïŒšæœ€çŸ­é•żćșŠ {0} ć€§ć†™ć­—æŻ",
"invalidPasswordMinSpecialCharsMessage": "æ— æ•ˆçš„ćŻ†ç ïŒšæœ€çŸ­é•żćșŠ {0} ç‰čæźŠć­—çŹŠ",
"invalidPasswordNotUsernameMessage": "æ— æ•ˆçš„ćŻ†ç ïŒš äžćŻä»„äžŽç”šæˆ·ćç›žćŒ",
"invalidPasswordRegexPatternMessage": "æ— æ•ˆçš„ćŻ†ç ïŒš æ— æł•äžŽæ­Łćˆ™èĄšèŸŸćŒćŒč配",
"invalidPasswordHistoryMessage": "æ— æ•ˆçš„ćŻ†ç ïŒšäžèƒœäžŽæœ€ćŽäœżç”šçš„ {0} äžȘ毆码盾搌",
"ldapErrorInvalidCustomFilter": 'ćźšćˆ¶çš„ LDAPèż‡æ»€ć™šäžæ˜Żä»„ "(" ćŒ€ć€Žæˆ–ä»„ ")"ç»“ć°Ÿ.',
"ldapErrorConnectionTimeoutNotNumber": "Connection Timeout ćż…éĄ»æ˜ŻäžȘæ•°ć­—",
"ldapErrorMissingClientId": "ćœ“ćŸŸè§’è‰Čæ˜ ć°„æœȘćŻç”šæ—¶ïŒŒćźąæˆ·ç«Ż ID éœ€èŠæŒ‡ćźšă€‚",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType": "æ— æł•ćœšäœżç”šUIDæˆć‘˜ç±»ćž‹çš„ćŒæ—¶ç»ŽæŠ€ç»„ç»§æ‰żć±žæ€§ă€‚",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "ćœ“LDAP提䟛æ–čäžæ˜ŻćŻć†™æšĄćŒæ—¶ïŒŒæ— æł•èźŸçœźćȘ憙",
"ldapErrorCantWriteOnlyAndReadOnly": "æ— æł•ćŒæ—¶èźŸçœźćȘèŻ»ć’ŒćȘ憙",
"clientRedirectURIsFragmentError": "重漚搑URL䞍ćș”ćŒ…ć«URIç‰‡æź”",
"clientRootURLFragmentError": "æ čURL 䞍ćș”ćŒ…ć« URL ç‰‡æź”",
"pairwiseMalformedClientRedirectURI": "ćźąæˆ·ç«ŻćŒ…ć«äž€äžȘæ— æ•ˆçš„é‡ćźšć‘URL",
"pairwiseClientRedirectURIsMissingHost": "ćźąæˆ·ç«Żé‡ćźšć‘URL需芁有䞀äžȘ有效的䞻æœș",
"pairwiseClientRedirectURIsMultipleHosts":
"Without a configured Sector Identifier URI, client redirect URIs must not contain multiple host components.",
"pairwiseMalformedSectorIdentifierURI": "Malformed Sector Identifier URI.",
"pairwiseFailedToGetRedirectURIs": "æ— æł•ä»ŽæœćŠĄć™šèŽ·ćŸ—é‡ćźšć‘URL",
"pairwiseRedirectURIsMismatch": "ćźąæˆ·ç«Żçš„é‡ćźšć‘URIäžŽæœćŠĄć™šç«ŻèŽ·ć–çš„URIé…çœźäžćŒč配。",
},
};
/* spell-checker: enable */

View File

@ -1,853 +0,0 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
export const kcMessages = {
"ca": {
"emailVerificationSubject": "VerificaciĂł d'email",
"emailVerificationBody":
"AlgĂș ha creat un compte de {2} amb aquesta adreça de correu electrĂČnic. Si has estat tu, fes clic a l'enllaç segĂŒent per verificar la teva adreça de correu electrĂČnic.\n\n{0}\n\nAquest enllaç expirarĂ  en {1} minuts.\n\nSi tu no has creat aquest compte, simplement ignora aquest missatge.",
"emailVerificationBodyHtml":
'<p>AlgĂș ha creat un compte de {2} amb aquesta adreça de correu electrĂČnic. Si has estat tu, fes clic a l\'enllaç segĂŒent per verificar la teva adreça de correu electrĂČnic.</p><p><a href="{0}">{0}</a></p><p> Aquest enllaç expirarĂ  en {1} minuts.</p><p> Si tu no has creat aquest compte, simplement ignora aquest missatge.</p>',
"passwordResetSubject": "Reinicia contrasenya",
"passwordResetBody":
"AlgĂș ha demanat de canviar les credencials del teu compte de {2}. Si has estat tu, fes clic a l'enllaç segĂŒent per a reiniciar-les.\n\n{0}\n\nAquest enllaç expirarĂ  en {1} minuts.\n\nSi no vols reiniciar les teves credencials, simplement ignora aquest missatge i no es realitzarĂ  cap canvi.",
"passwordResetBodyHtml":
'<p>AlgĂș ha demanat de canviar les credencials del teu compte de {2}. Si has estat tu, fes clic a l\'enllaç segĂŒent per a reiniciar-les.</p><p><a href="{0}">{0}</a></p><p>Aquest enllaç expirarĂ  en {1} minuts.</p><p>Si no vols reiniciar les teves credencials, simplement ignora aquest missatge i no es realitzarĂ  cap canvi.</p>',
"executeActionsSubject": "Actualitza el teu compte",
"executeActionsBody":
"L'administrador ha sol·licitat que actualitzis el teu compte de {2}. Fes clic a l'enllaç inferior per iniciar aquest procĂ©s.\n\n{0}\n\nAquest enllaç expirarĂ  en {1} minutes.\n\nSi no estĂ s al tant que l'administrador hagi sol·licitat aixĂČ, simplement ignora aquest missatge i no es realitzarĂ  cap canvi.",
"executeActionsBodyHtml":
"<p>L'administrador ha sol·licitat que actualitzis el teu compte de {2}. Fes clic a l'enllaç inferior per iniciar aquest procĂ©s.</p><p><a href=\"{0}\">{0}</a></p><p>Aquest enllaç expirarĂ  en {1} minutes.</p><p>Si no estĂ s al tant que l'administrador hagi sol·licitat aixĂČ, simplement ignora aquest missatge i no es realitzarĂ  cap canvi.</p>",
"eventLoginErrorSubject": "Fallada en l'inici de sessiĂł",
"eventLoginErrorBody":
"S'ha detectat un intent d'accés fallit al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador.",
"eventLoginErrorBodyHtml":
"<p>S'ha detectat un intent d'accés fallit al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador.</p>",
"eventRemoveTotpSubject": "Esborrat OTP",
"eventRemoveTotpBody": "OTP s'ha eliminat del teu compte el {0} des de {1}. Si no has estat tu, per favor contacta amb l'administrador.",
"eventRemoveTotpBodyHtml":
"<p>OTP s'ha eliminat del teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador. </ P>",
"eventUpdatePasswordSubject": "ActualitzaciĂł de contrasenya",
"eventUpdatePasswordBody":
"La teva contrasenya s'ha actualitzat el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador.",
"eventUpdatePasswordBodyHtml":
"<p>La teva contrasenya s'ha actualitzat el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador.</p>",
"eventUpdateTotpSubject": "ActualitzaciĂł de OTP",
"eventUpdateTotpBody": "OTP s'ha actualitzat al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador.",
"eventUpdateTotpBodyHtml":
"<p>OTP s'ha actualitzat al teu compte el {0} des de {1}. Si no has estat tu, si us plau contacta amb l'administrador.</p>",
},
"cs": {
"emailVerificationSubject": "Ověƙení e-mailu",
"emailVerificationBody":
"Někdo vytvoƙil Ășčet {2} s touto e-mailovou adresou. Pokud jste to vy, klikněte na nĂ­ĆŸe uvedenĂœ odkaz a ověƙte svou e-mailovou adresu \n\n{0}\n\nTento odkaz vyprĆĄĂ­ za {1} minuty.\n\nPokud jste tento Ășčet nevytvoƙili, tuto zprĂĄvu ignorujte.",
"emailVerificationBodyHtml":
'<p>Někdo vytvoƙil Ășčet {2} s touto e-mailovou adresou. Pokud jste to vy, klikněte na nĂ­ĆŸe uvedenĂœ odkaz a ověƙte svou e-mailovou adresu. </p><p><a href="{0}">Odkaz na ověƙenĂ­ e-mailovĂ© adresy</a></p><p>Platnost odkazu vyprĆĄĂ­ za {1} minut.</p><p>Pokud jste tento Ășčet nevytvoƙili, tuto zprĂĄvu ignorujte.</p>',
"emailTestSubject": "[KEYCLOAK] - testovacĂ­ zprĂĄva",
"emailTestBody": "Toto je testovacĂ­ zprĂĄva",
"emailTestBodyHtml": "<p>Toto je testovacĂ­ zprĂĄva </p>",
"identityProviderLinkSubject": "Odkaz {0}",
"identityProviderLinkBody":
'Někdo chce propojit vĂĄĆĄ Ășčet "{1}" s Ășčtem "{0}" uĆŸivatele {2}. Pokud jste to vy, klikněte na nĂ­ĆŸe uvedenĂœ odkaz a propojte Ășčty. \n\n{3}\n\nPlatnost tohoto odkazu je {5}.\n\nPokud nechcete propojit Ășčet, tuto zprĂĄvu ignorujte. Pokud propojĂ­te Ășčty, budete se moci pƙihlĂĄsit jako {1} pomocĂ­ {0}.',
"identityProviderLinkBodyHtml":
'<p>Někdo prĂĄvě poĆŸĂĄdal o změnu hesla u vaĆĄeho Ășčtu {2}. Pokud jste to vy, pro jeho změnu klikněte na odkaz nĂ­ĆŸe.</p><p><a href="{0}">Odkaz na změnu hesla.</a></p><p>Platnost tohoto odkazu je {3}.</p><p>Pokud heslo změnit nechcete, tuto zprĂĄvu ignorujte a nic se nezměnĂ­.</p>',
"passwordResetSubject": "Zapomenuté heslo",
"passwordResetBody":
"Někdo prĂĄvě poĆŸĂĄdal o změnu hesla u vaĆĄeho Ășčtu {2}. Pokud jste to vy, pro jeho změnu klikněte na odkaz nĂ­ĆŸe.\n\n{0}\n\nPlatnost tohoto odkazu je {3}.\n\nPokud heslo změnit nechcete, tuto zprĂĄvu ignorujte a nic se nezměnĂ­.",
"passwordResetBodyHtml":
'<p> Někdo prĂĄvě poĆŸĂĄdal o změnu pověƙenĂ­ vaĆĄeho Ășčtu {2}. Pokud jste to vy, klikněte na odkaz nĂ­ĆŸe, abyste je resetovali.</p><p><a href="{0}">Odkaz na obnovenĂ­ pověƙenĂ­ </a></p><p> Platnost tohoto odkazu vyprĆĄĂ­ během {1} minut.</p><p> Pokud nechcete obnovit vaĆĄe pověƙenĂ­, ignorujte tuto zprĂĄvu a nic se nezměnĂ­.</p>',
"executeActionsSubject": "Aktualizujte svĆŻj Ășčet",
"executeActionsBody":
"VĂĄĆĄ administrĂĄtor vĂĄs poĆŸĂĄdal o provedenĂ­ nĂĄsledujĂ­cĂ­ch akcĂ­ u Ășčtu {2}: {3}. Začněte kliknutĂ­m na nĂ­ĆŸe uvedenĂœ odkaz.\n\n{0}\n\nPlatnost tohoto odkazu je {4}.\n\nPokud si nejste jisti, zda je tento poĆŸadavek v poƙádku, ignorujte tuto zprĂĄvu.",
"executeActionsBodyHtml":
'<p>VĂĄĆĄ administrĂĄtor vĂĄs poĆŸĂĄdal o provedenĂ­ nĂĄsledujĂ­cĂ­ch akcĂ­ u Ășčtu {2}: {3}. Začněte kliknutĂ­m na nĂ­ĆŸe uvedenĂœ odkaz.</p><p><a href="{0}">Odkaz na aktualizaci Ășčtu.</a></p><p>Platnost tohoto odkazu je {4}.</p><p>Pokud si nejste jisti, zda je tento poĆŸadavek v poƙádku, ignorujte tuto zprĂĄvu.</p>',
"eventLoginErrorSubject": "Chyba pƙihláơení",
"eventLoginErrorBody": "Někdo se neĂșspěơně pokusil pƙihlĂĄsit k Ășčtu {0} z {1}. Pokud jste to nebyli vy, kontaktujte administrĂĄtora.",
"eventLoginErrorBodyHtml":
"<p>Někdo se neĂșspěơně pokusil pƙihlĂĄsit k Ășčtu {0} z {1}. Pokud jste to nebyli vy, kontaktujte administrĂĄtora.</p>",
"eventRemoveTotpSubject": "Odebrat TOTP",
"eventRemoveTotpBody": "V Ășčtu {0} bylo odebrĂĄno nastavenĂ­ OTP z {1}. Pokud jste to nebyli vy, kontaktujte administrĂĄtora.",
"eventRemoveTotpBodyHtml": "<p>V Ășčtu {0} bylo odebrĂĄno nastavenĂ­ OTP z {1}. Pokud jste to nebyli vy, kontaktujte administrĂĄtora.</p>",
"eventUpdatePasswordSubject": "Aktualizace hesla",
"eventUpdatePasswordBody": "V Ășčtu {0} bylo změněno heslo z {1}. Pokud jste to nebyli vy, kontaktujte administrĂĄtora.",
"eventUpdatePasswordBodyHtml": "<p>V Ășčtu {0} bylo změněno heslo z {1}. Pokud jste to nebyli vy, kontaktujte administrĂĄtora.</p>",
"eventUpdateTotpSubject": "Aktualizace OTP",
"eventUpdateTotpBody": "V Ășčtu {0} bylo změněno nastavenĂ­ OTP z {1}. Pokud jste to nebyli vy, kontaktujte administrĂĄtora.",
"eventUpdateTotpBodyHtml": "<p>V Ășčtu {0} bylo změněno nastavenĂ­ OTP z {1}. Pokud jste to nebyli vy, kontaktujte administrĂĄtora.</p>",
"requiredAction.CONFIGURE_TOTP": "Konfigurace OTP",
"requiredAction.terms_and_conditions": "SmluvnĂ­ podmĂ­nky",
"requiredAction.UPDATE_PASSWORD": "Aktualizace hesla",
"requiredAction.UPDATE_PROFILE": "Aktualizace profilu",
"requiredAction.VERIFY_EMAIL": "Ověƙení e-mailu",
"linkExpirationFormatter.timePeriodUnit.seconds": "sekund",
"linkExpirationFormatter.timePeriodUnit.seconds.1": "sekunda",
"linkExpirationFormatter.timePeriodUnit.seconds.2": "sekundy",
"linkExpirationFormatter.timePeriodUnit.seconds.3": "sekundy",
"linkExpirationFormatter.timePeriodUnit.seconds.4": "sekundy",
"linkExpirationFormatter.timePeriodUnit.minutes": "minut",
"linkExpirationFormatter.timePeriodUnit.minutes.1": "minuta",
"linkExpirationFormatter.timePeriodUnit.minutes.2": "minuty",
"linkExpirationFormatter.timePeriodUnit.minutes.3": "minuty",
"linkExpirationFormatter.timePeriodUnit.minutes.4": "minuty",
"linkExpirationFormatter.timePeriodUnit.hours": "hodin",
"linkExpirationFormatter.timePeriodUnit.hours.1": "hodina",
"linkExpirationFormatter.timePeriodUnit.hours.2": "hodiny",
"linkExpirationFormatter.timePeriodUnit.hours.3": "hodiny",
"linkExpirationFormatter.timePeriodUnit.hours.4": "hodiny",
"linkExpirationFormatter.timePeriodUnit.days": "dnĂ­",
"linkExpirationFormatter.timePeriodUnit.days.1": "den",
"linkExpirationFormatter.timePeriodUnit.days.2": "dny",
"linkExpirationFormatter.timePeriodUnit.days.3": "dny",
"linkExpirationFormatter.timePeriodUnit.days.4": "dny",
},
"de": {
"emailVerificationSubject": "E-Mail verifizieren",
"emailVerificationBody":
"Jemand hat ein {2} Konto mit dieser E-Mail-Adresse erstellt. Falls Sie das waren, dann klicken Sie auf den Link, um die E-Mail-Adresse zu verifizieren.\n\n{0}\n\nDieser Link wird in {1} Minuten ablaufen.\n\nFalls Sie dieses Konto nicht erstellt haben, dann können sie diese Nachricht ignorieren.",
"emailVerificationBodyHtml":
'<p>Jemand hat ein {2} Konto mit dieser E-Mail-Adresse erstellt. Falls das Sie waren, klicken Sie auf den Link, um die E-Mail-Adresse zu verifizieren.</p><p><a href="{0}">Link zur BestÀtigung der E-Mail-Adresse</a></p><p>Dieser Link wird in {1} Minuten ablaufen.</p><p>Falls Sie dieses Konto nicht erstellt haben, dann können sie diese Nachricht ignorieren.</p>',
"identityProviderLinkSubject": "Link {0}",
"identityProviderLinkBody":
"Es wurde beantragt Ihren Account {1} mit dem Account {0} von Benutzer {2} zu verlinken. Sollten Sie dies beantragt haben, klicken Sie auf den unten stehenden Link.\n\n{3}\n\n Die GĂŒltigkeit des Links wird in {4} Minuten verfallen.\n\nSollten Sie Ihren Account nicht verlinken wollen, ignorieren Sie diese Nachricht. Wenn Sie die Accounts verlinken wird ein Login auf {1} ĂŒber {0} ermöglicht.",
"identityProviderLinkBodyHtml":
'<p>Es wurde beantragt Ihren Account {1} mit dem Account {0} von Benutzer {2} zu verlinken. Sollten Sie dies beantragt haben, klicken Sie auf den unten stehenden Link.</p><p><a href="{3}">Link zur BestĂ€tigung der KontoverknĂŒpfung</a></p><p>Die GĂŒltigkeit des Links wird in {4} Minuten verfallen.</p><p>Sollten Sie Ihren Account nicht verlinken wollen, ignorieren Sie diese Nachricht. Wenn Sie die Accounts verlinken wird ein Login auf {1} ĂŒber {0} ermöglicht.</p>',
"passwordResetSubject": "Passwort zurĂŒcksetzen",
"passwordResetBody":
"Es wurde eine Änderung der Anmeldeinformationen fĂŒr Ihren Account {2} angefordert. Wenn Sie diese Änderung beantragt haben, klicken Sie auf den unten stehenden Link.\n\n{0}\n\nDie GĂŒltigkeit des Links wird in {1} Minuten verfallen.\n\nSollten Sie keine Änderung vollziehen wollen können Sie diese Nachricht ignorieren und an Ihrem Account wird nichts geĂ€ndert.",
"passwordResetBodyHtml":
'<p>Es wurde eine Änderung der Anmeldeinformationen fĂŒr Ihren Account {2} angefordert. Wenn Sie diese Änderung beantragt haben, klicken Sie auf den unten stehenden Link.</p><p><a href="{0}">Link zum ZurĂŒcksetzen von Anmeldeinformationen</a></p><p>Die GĂŒltigkeit des Links wird in {1} Minuten verfallen.</p><p>Sollten Sie keine Änderung vollziehen wollen können Sie diese Nachricht ignorieren und an Ihrem Account wird nichts geĂ€ndert.</p>',
"executeActionsSubject": "Aktualisieren Sie Ihr Konto",
"executeActionsBody":
"Ihr Administrator hat Sie aufgefordert Ihren Account {2} zu aktualisieren. Klicken Sie auf den unten stehenden Link um den Prozess zu starten.\n\n{0}\n\nDie GĂŒltigkeit des Links wird in {1} Minuten verfallen.\n\nSollten Sie sich dieser Aufforderung nicht bewusst sein, ignorieren Sie diese Nachricht und Ihr Account bleibt unverĂ€ndert.",
"executeActionsBodyHtml":
'<p>Ihr Administrator hat Sie aufgefordert Ihren Account {2} zu aktualisieren. Klicken Sie auf den unten stehenden Link um den Prozess zu starten.</p><p><a href="{0}">Link zum Account-Update</a></p><p>Die GĂŒltigkeit des Links wird in {1} Minuten verfallen.</p><p>Sollten Sie sich dieser Aufforderung nicht bewusst sein, ignorieren Sie diese Nachricht und Ihr Account bleibt unverĂ€ndert.</p>',
"eventLoginErrorSubject": "Fehlgeschlagene Anmeldung",
"eventLoginErrorBody":
"Jemand hat um {0} von {1} versucht, sich mit Ihrem Konto anzumelden. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.",
"eventLoginErrorBodyHtml":
"<p>Jemand hat um {0} von {1} versucht, sich mit Ihrem Konto anzumelden. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.</p>",
"eventRemoveTotpSubject": "OTP Entfernt",
"eventRemoveTotpBody":
"OTP wurde von Ihrem Konto am {0} von {1} entfernt. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.",
"eventRemoveTotpBodyHtml":
"<p>OTP wurde von Ihrem Konto am {0} von {1} entfernt. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.</p>",
"eventUpdatePasswordSubject": "Passwort Aktualisiert",
"eventUpdatePasswordBody": "Ihr Passwort wurde am {0} von {1} geÀndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.",
"eventUpdatePasswordBodyHtml":
"<p>Ihr Passwort wurde am {0} von {1} geÀndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.</p>",
"eventUpdateTotpSubject": "OTP Aktualisiert",
"eventUpdateTotpBody": "OTP wurde am {0} von {1} geÀndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.",
"eventUpdateTotpBodyHtml": "<p>OTP wurde am {0} von {1} geÀndert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.</p>",
},
"en": {
"emailVerificationSubject": "Verify email",
"emailVerificationBody":
"Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address\n\n{0}\n\nThis link will expire within {3}.\n\nIf you didn't create this account, just ignore this message.",
"emailVerificationBodyHtml":
'<p>Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address</p><p><a href="{0}">Link to e-mail address verification</a></p><p>This link will expire within {3}.</p><p>If you didn\'t create this account, just ignore this message.</p>',
"emailTestSubject": "[KEYCLOAK] - SMTP test message",
"emailTestBody": "This is a test message",
"emailTestBodyHtml": "<p>This is a test message</p>",
"identityProviderLinkSubject": "Link {0}",
"identityProviderLinkBody":
'Someone wants to link your "{1}" account with "{0}" account of user {2} . If this was you, click the link below to link accounts\n\n{3}\n\nThis link will expire within {5}.\n\nIf you don\'t want to link account, just ignore this message. If you link accounts, you will be able to login to {1} through {0}.',
"identityProviderLinkBodyHtml":
'<p>Someone wants to link your <b>{1}</b> account with <b>{0}</b> account of user {2} . If this was you, click the link below to link accounts</p><p><a href="{3}">Link to confirm account linking</a></p><p>This link will expire within {5}.</p><p>If you don\'t want to link account, just ignore this message. If you link accounts, you will be able to login to {1} through {0}.</p>',
"passwordResetSubject": "Reset password",
"passwordResetBody":
"Someone just requested to change your {2} account's credentials. If this was you, click on the link below to reset them.\n\n{0}\n\nThis link and code will expire within {3}.\n\nIf you don't want to reset your credentials, just ignore this message and nothing will be changed.",
"passwordResetBodyHtml":
"<p>Someone just requested to change your {2} account's credentials. If this was you, click on the link below to reset them.</p><p><a href=\"{0}\">Link to reset credentials</a></p><p>This link will expire within {3}.</p><p>If you don't want to reset your credentials, just ignore this message and nothing will be changed.</p>",
"executeActionsSubject": "Update Your Account",
"executeActionsBody":
"Your administrator has just requested that you update your {2} account by performing the following action(s): {3}. Click on the link below to start this process.\n\n{0}\n\nThis link will expire within {4}.\n\nIf you are unaware that your administrator has requested this, just ignore this message and nothing will be changed.",
"executeActionsBodyHtml":
'<p>Your administrator has just requested that you update your {2} account by performing the following action(s): {3}. Click on the link below to start this process.</p><p><a href="{0}">Link to account update</a></p><p>This link will expire within {4}.</p><p>If you are unaware that your administrator has requested this, just ignore this message and nothing will be changed.</p>',
"eventLoginErrorSubject": "Login error",
"eventLoginErrorBody":
"A failed login attempt was detected to your account on {0} from {1}. If this was not you, please contact an administrator.",
"eventLoginErrorBodyHtml":
"<p>A failed login attempt was detected to your account on {0} from {1}. If this was not you, please contact an administrator.</p>",
"eventRemoveTotpSubject": "Remove OTP",
"eventRemoveTotpBody": "OTP was removed from your account on {0} from {1}. If this was not you, please contact an administrator.",
"eventRemoveTotpBodyHtml": "<p>OTP was removed from your account on {0} from {1}. If this was not you, please contact an administrator.</p>",
"eventUpdatePasswordSubject": "Update password",
"eventUpdatePasswordBody": "Your password was changed on {0} from {1}. If this was not you, please contact an administrator.",
"eventUpdatePasswordBodyHtml": "<p>Your password was changed on {0} from {1}. If this was not you, please contact an administrator.</p>",
"eventUpdateTotpSubject": "Update OTP",
"eventUpdateTotpBody": "OTP was updated for your account on {0} from {1}. If this was not you, please contact an administrator.",
"eventUpdateTotpBodyHtml": "<p>OTP was updated for your account on {0} from {1}. If this was not you, please contact an administrator.</p>",
"requiredAction.CONFIGURE_TOTP": "Configure OTP",
"requiredAction.terms_and_conditions": "Terms and Conditions",
"requiredAction.UPDATE_PASSWORD": "Update Password",
"requiredAction.UPDATE_PROFILE": "Update Profile",
"requiredAction.VERIFY_EMAIL": "Verify Email",
"linkExpirationFormatter.timePeriodUnit.seconds": "seconds",
"linkExpirationFormatter.timePeriodUnit.seconds.1": "second",
"linkExpirationFormatter.timePeriodUnit.minutes": "minutes",
"linkExpirationFormatter.timePeriodUnit.minutes.1": "minute",
"linkExpirationFormatter.timePeriodUnit.hours": "hours",
"linkExpirationFormatter.timePeriodUnit.hours.1": "hour",
"linkExpirationFormatter.timePeriodUnit.days": "days",
"linkExpirationFormatter.timePeriodUnit.days.1": "day",
"emailVerificationBodyCode": "Please verify your email address by entering in the following code.\n\n{0}\n\n.",
"emailVerificationBodyCodeHtml": "<p>Please verify your email address by entering in the following code.</p><p><b>{0}</b></p>",
},
"es": {
"emailVerificationSubject": "VerificaciĂłn de email",
"emailVerificationBody":
"Alguien ha creado una cuenta de {2} con esta direcciĂłn de email. Si has sido tĂș, haz click en el enlace siguiente para verificar tu direcciĂłn de email.\n\n{0}\n\nEste enlace expirarĂĄ en {1} minutos.\n\nSi tĂș no has creado esta cuenta, simplemente ignora este mensaje.",
"emailVerificationBodyHtml":
'<p>Alguien ha creado una cuenta de {2} con esta direcciĂłn de email. Si has sido tĂș, haz click en el enlace siguiente para verificar tu direcciĂłn de email.</p><p><a href="{0}">{0}</a></p><p>Este enlace expirarĂĄ en {1} minutos.</p><p>Si tĂș no has creado esta cuenta, simplemente ignora este mensaje.</p>',
"passwordResetSubject": "Reiniciar contraseña",
"passwordResetBody":
"Alguien ha solicitado cambiar las credenciales de tu cuenta de {2}. Si has sido tĂș, haz clic en el enlace siguiente para reiniciarlas.\n\n{0}\n\nEste enlace expirarĂĄ en {1} minutos.\n\nSi no quieres reiniciar tus credenciales, simplemente ignora este mensaje y no se realizarĂĄ ningĂșn cambio.",
"passwordResetBodyHtml":
'<p>Alguien ha solicitado cambiar las credenciales de tu cuenta de {2}. Si has sido tĂș, haz clic en el enlace siguiente para reiniciarlas.</p><p><a href="{0}">{0}</a></p><p>Este enlace expirarĂĄ en {1} minutos.</p><p>Si no quieres reiniciar tus credenciales, simplemente ignora este mensaje y no se realizarĂĄ ningĂșn cambio.</p>',
"executeActionsSubject": "Actualiza tu cuenta",
"executeActionsBody":
"El administrador ha solicitado que actualices tu cuenta de {2}. Haz clic en el enlace inferior para iniciar este proceso.\n\n{0}\n\nEste enlace expirarĂĄ en {1} minutos.\n\nSi no estĂĄs al tanto de que el administrador haya solicitado esto, simplemente ignora este mensaje y no se realizarĂĄ ningĂșn cambio.",
"executeActionsBodyHtml":
'<p>El administrador ha solicitado que actualices tu cuenta de {2}. Haz clic en el enlace inferior para iniciar este proceso.</p><p><a href="{0}">{0}</a></p><p>Este enlace expirarĂĄ en {1} minutos.</p><p>Si no estĂĄs al tanto de que el administrador haya solicitado esto, simplemente ignora este mensaje y no se realizarĂĄ ningĂșn cambio.</p>',
"eventLoginErrorSubject": "Fallo en el inicio de sesiĂłn",
"eventLoginErrorBody":
"Se ha detectado un intento de acceso fallido a tu cuenta el {0} desde {1}. Si no has sido tĂș, por favor contacta con el administrador.",
"eventLoginErrorBodyHtml":
"<p>Se ha detectado un intento de acceso fallido a tu cuenta el {0} desde {1}. Si no has sido tĂș, por favor contacta con el administrador.</p>",
"eventRemoveTotpSubject": "Borrado OTP",
"eventRemoveTotpBody": "OTP fue eliminado de tu cuenta el {0} desde {1}. Si no has sido tĂș, por favor contacta con el administrador.",
"eventRemoveTotpBodyHtml":
"<p>OTP fue eliminado de tu cuenta el {0} desde {1}. Si no has sido tĂș, por favor contacta con el administrador.</p>",
"eventUpdatePasswordSubject": "Actualización de contraseña",
"eventUpdatePasswordBody": "Tu contraseña se ha actualizado el {0} desde {1}. Si no has sido tĂș, por favor contacta con el administrador.",
"eventUpdatePasswordBodyHtml":
"<p>Tu contraseña se ha actualizado el {0} desde {1}. Si no has sido tĂș, por favor contacta con el administrador.</p>",
"eventUpdateTotpSubject": "ActualizaciĂłn de OTP",
"eventUpdateTotpBody": "OTP se ha actualizado en tu cuenta el {0} desde {1}. Si no has sido tĂș, por favor contacta con el administrador.",
"eventUpdateTotpBodyHtml":
"<p>OTP se ha actualizado en tu cuenta el {0} desde {1}. Si no has sido tĂș, por favor contacta con el administrador.</p>",
},
"fr": {
"emailVerificationSubject": "Vérification du courriel",
"emailVerificationBody":
"Quelqu'un vient de crĂ©er un compte \"{2}\" avec votre courriel. Si vous ĂȘtes Ă  l'origine de cette requĂȘte, veuillez cliquer sur le lien ci-dessous afin de vĂ©rifier votre adresse de courriel\n\n{0}\n\nCe lien expire dans {1} minute(s).\n\nSinon, veuillez ignorer ce message.",
"emailVerificationBodyHtml":
'<p>Quelqu\'un vient de crĂ©er un compte "{2}" avec votre courriel. Si vous ĂȘtes Ă  l\'origine de cette requĂȘte, veuillez cliquer sur le lien ci-dessous afin de vĂ©rifier votre adresse de courriel</p><p><a href="{0}">{0}</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Sinon, veuillez ignorer ce message.</p>',
"passwordResetSubject": "Réinitialiser le mot de passe",
"passwordResetBody":
"Quelqu'un vient de demander une rĂ©initialisation de mot de passe pour votre compte {2}. Si vous ĂȘtes Ă  l'origine de cette requĂȘte, veuillez cliquer sur le lien ci-dessous pour le mettre Ă  jour.\n\n{0}\n\nCe lien expire dans {1} minute(s).\n\nSinon, veuillez ignorer ce message ; aucun changement ne sera effectuĂ© sur votre compte.",
"passwordResetBodyHtml":
"<p>Quelqu'un vient de demander une rĂ©initialisation de mot de passe pour votre compte {2}. Si vous ĂȘtes Ă  l'origine de cette requĂȘte, veuillez cliquer sur le lien ci-dessous pour le mettre Ă  jour.</p><p><a href=\"{0}\">Lien pour rĂ©initialiser votre mot de passe</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Sinon, veuillez ignorer ce message ; aucun changement ne sera effectuĂ© sur votre compte.</p>",
"executeActionsSubject": "Mettre Ă  jour votre compte",
"executeActionsBody":
"Votre administrateur vient de demander une mise Ă  jour de votre compte {2}. Veuillez cliquer sur le lien ci-dessous afin de commencer le processus.\n\n{0}\n\nCe lien expire dans {1} minute(s).\n\nSi vous n'ĂȘtes pas Ă  l'origine de cette requĂȘte, veuillez ignorer ce message ; aucun changement ne sera effectuĂ© sur votre compte.",
"executeActionsBodyHtml":
"<p>Votre administrateur vient de demander une mise Ă  jour de votre compte {2}. Veuillez cliquer sur le lien ci-dessous afin de commencer le processus.</p><p><a href=\"{0}\">{0}</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Si vous n'ĂȘtes pas Ă  l'origine de cette requĂȘte, veuillez ignorer ce message ; aucun changement ne sera effectuĂ© sur votre compte.</p>",
"eventLoginErrorSubject": "Erreur de connexion",
"eventLoginErrorBody":
"Une tentative de connexion a Ă©tĂ© dĂ©tectĂ©e sur votre compte {0} depuis {1}. Si vous n'ĂȘtes pas Ă  l'origine de cette requĂȘte, veuillez contacter votre administrateur.",
"eventLoginErrorBodyHtml":
"<p>Une tentative de connexion a Ă©tĂ© dĂ©tectĂ©e sur votre compte {0} depuis {1}. Si vous n'ĂȘtes pas Ă  l'origine de cette requĂȘte, veuillez contacter votre administrateur.</p>",
"eventRemoveTotpSubject": "Suppression du OTP",
"eventRemoveTotpBody":
"Le OTP a Ă©tĂ© supprimĂ© de votre compte {0} depuis {1}. Si vous n'Ă©tiez pas Ă  l'origine de cette requĂȘte, veuillez contacter votre administrateur.",
"eventRemoveTotpBodyHtml":
"<p>Le OTP a Ă©tĂ© supprimĂ© de votre compte {0} depuis {1}. Si vous n'Ă©tiez pas Ă  l'origine de cette requĂȘte, veuillez contacter votre administrateur.</p>",
"eventUpdatePasswordSubject": "Mise Ă  jour du mot de passe",
"eventUpdatePasswordBody":
"Votre mot de passe pour votre compte {0} a Ă©tĂ© modifiĂ© depuis {1}. Si vous n'Ă©tiez pas Ă  l'origine de cette requĂȘte, veuillez contacter votre administrateur.",
"eventUpdatePasswordBodyHtml":
"<p>Votre mot de passe pour votre compte {0} a Ă©tĂ© modifiĂ© depuis {1}. Si vous n'Ă©tiez pas Ă  l'origine de cette requĂȘte, veuillez contacter votre administrateur.</p>",
"eventUpdateTotpSubject": "Mise Ă  jour du OTP",
"eventUpdateTotpBody":
"Le OTP a Ă©tĂ© mis Ă  jour pour votre compte {0} depuis {1}. Si vous n'Ă©tiez pas Ă  l'origine de cette requĂȘte, veuillez contacter votre administrateur.",
"eventUpdateTotpBodyHtml":
"<p>Le OTP a Ă©tĂ© mis Ă  jour pour votre compte {0} depuis {1}. Si vous n'Ă©tiez pas Ă  l'origine de cette requĂȘte, veuillez contacter votre administrateur.</p>",
},
"it": {
"emailVerificationSubject": "Verifica l'email",
"emailVerificationBody":
"Qualcuno ha creato un account {2} con questo indirizzo email. Se sei stato tu, fai clic sul link seguente per verificare il tuo indirizzo email\n\n{0}\n\nQuesto link scadrĂ  in {3}.\n\nSe non sei stato tu a creare questo account, ignora questo messaggio.",
"emailVerificationBodyHtml":
'<p>Qualcuno ha creato un account {2} con questo indirizzo email. Se sei stato tu, fai clic sul link seguente per verificare il tuo indirizzo email</p><p><a href="{0}">{0}</a></p><p>Questo link scadrĂ  in {3}.</p><p>Se non sei stato tu a creare questo account, ignora questo messaggio.</p>',
"emailTestSubject": "[KEYCLOAK] - messaggio di test SMTP",
"emailTestBody": "Questo Ăš un messaggio di test",
"emailTestBodyHtml": "<p>Questo Ăš un messaggio di test</p>",
"identityProviderLinkSubject": "Link {0}",
"identityProviderLinkBody":
'Qualcuno vuole associare il tuo account "{1}" con l\'account "{0}" dell\'utente {2}. Se sei stato tu, fai clic sul link seguente per associare gli account\n\n{3}\n\nQuesto link scadrĂ  in {5}.\n\nSe non vuoi associare l\'account, ignora questo messaggio. Se associ gli account, potrai accedere a {1} attraverso {0}.',
"identityProviderLinkBodyHtml":
"<p>Qualcuno vuole associare il tuo account <b>{1}</b> con l'account <b>{0}</b> dell'utente {2}. Se sei stato tu, fai clic sul link seguente per associare gli account</p><p><a href=\"{3}\">{3}</a></p><p>Questo link scadrĂ  in {5}.</p><p>Se non vuoi associare l'account, ignora questo messaggio. Se associ gli account, potrai accedere a {1} attraverso {0}.</p>",
"passwordResetSubject": "Reimposta la password",
"passwordResetBody":
"Qualcuno ha appena richiesto di cambiare le credenziali di accesso al tuo account {2}. Se sei stato tu, fai clic sul link seguente per reimpostarle.\n\n{0}\n\nQuesto link e codice scadranno in {3}.\n\nSe non vuoi reimpostare le tue credenziali di accesso, ignora questo messaggio e non verrĂ  effettuato nessun cambio.",
"passwordResetBodyHtml":
'<p>Qualcuno ha appena richiesto di cambiare le credenziali di accesso al tuo account {2}. Se sei stato tu, fai clic sul link seguente per reimpostarle.</p><p><a href="{0}">{0}</a></p><p>Questo link scadrĂ  in {3}.</p><p>Se non vuoi reimpostare le tue credenziali di accesso, ignora questo messaggio e non verrĂ  effettuato nessun cambio.</p>',
"executeActionsSubject": "Aggiorna il tuo account",
"executeActionsBody":
"Il tuo amministratore ha appena richiesto un aggiornamento del tuo account {2} ed Ăš necessario che tu esegua la/le seguente/i azione/i: {3}. Fai clic sul link seguente per iniziare questo processo.\n\n{0}\n\nQuesto link scadrĂ  in {4}.\n\nSe non sei a conoscenza della richiesta del tuo amministratore, ignora questo messaggio e non verrĂ  effettuato nessun cambio.",
"executeActionsBodyHtml":
'<p>Il tuo amministratore ha appena richiesto un aggiornamento del tuo account {2} ed Ăš necessario che tu esegua la/le seguente/i azione/i: {3}. Fai clic sul link seguente per iniziare questo processo.</p><p><a href="{0}">Link to account update</a></p><p>Questo link scadrĂ  in {4}.</p><p>Se non sei a conoscenza della richiesta del tuo amministratore, ignora questo messaggio e non verrĂ  effettuato nessun cambio.</p>',
"eventLoginErrorSubject": "Errore di accesso",
"eventLoginErrorBody":
"È stato rilevato un tentativo fallito di accesso al tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.",
"eventLoginErrorBodyHtml":
"<p>È stato rilevato un tentativo fallito di accesso al tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.</p>",
"eventRemoveTotpSubject": "Rimozione OTP (password temporanea valida una volta sola)",
"eventRemoveTotpBody":
"La OTP (password temporanea valida una volta sola) Ăš stata rimossa dal tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.",
"eventRemoveTotpBodyHtml":
"<p>La OTP (password temporanea valida una volta sola) Ăš stata rimossa dal tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.</p>",
"eventUpdatePasswordSubject": "Aggiornamento password",
"eventUpdatePasswordBody": "La tua password Ăš stata cambiata il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.",
"eventUpdatePasswordBodyHtml":
"<p>La tua password Ăš stata cambiata il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.</p>",
"eventUpdateTotpSubject": "Aggiornamento OTP (password temporanea valida una volta sola)",
"eventUpdateTotpBody":
"La OTP (password temporanea valida una volta sola) Ăš stata aggiornata per il tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.",
"eventUpdateTotpBodyHtml":
"<p>La OTP (password temporanea valida una volta sola) Ăš stata aggiornata per il tuo account il {0} da {1}. Se non sei stato tu, per favore contatta l'amministratore.</p>",
"requiredAction.CONFIGURE_TOTP": "Configurazione OTP",
"requiredAction.terms_and_conditions": "Termini e condizioni",
"requiredAction.UPDATE_PASSWORD": "Aggiornamento password",
"requiredAction.UPDATE_PROFILE": "Aggiornamento profilo",
"requiredAction.VERIFY_EMAIL": "Verifica dell'indirizzo email",
"linkExpirationFormatter.timePeriodUnit.seconds": "secondi",
"linkExpirationFormatter.timePeriodUnit.seconds.1": "secondo",
"linkExpirationFormatter.timePeriodUnit.minutes": "minuti",
"linkExpirationFormatter.timePeriodUnit.minutes.1": "minuto",
"linkExpirationFormatter.timePeriodUnit.hours": "ore",
"linkExpirationFormatter.timePeriodUnit.hours.1": "ora",
"linkExpirationFormatter.timePeriodUnit.days": "giorni",
"linkExpirationFormatter.timePeriodUnit.days.1": "giorno",
"emailVerificationBodyCode": "Per favore verifica il tuo indirizzo email inserendo il codice seguente.\n\n{0}\n\n.",
"emailVerificationBodyCodeHtml": "<p>Per favore verifica il tuo indirizzo email inserendo il codice seguente.</p><p><b>{0}</b></p>",
},
"ja": {
"emailVerificationSubject": "EăƒĄăƒŒăƒ«ăźçąșèȘ",
"emailVerificationBody":
"ă“ăźăƒĄăƒŒăƒ«ă‚ąăƒ‰ăƒŹă‚čで{2}ă‚ąă‚«ă‚ŠăƒłăƒˆăŒäœœæˆă•ă‚ŒăŸă—ăŸă€‚ä»„äž‹ăźăƒȘンクをクăƒȘăƒƒă‚Żă—ăŠăƒĄăƒŒăƒ«ă‚ąăƒ‰ăƒŹă‚čたçąșèȘă‚’ćźŒäș†ă—ăŠăă ă•ă„ă€‚\n\n{0}\n\nこぼăƒȘンクは{3}ă ă‘æœ‰ćŠčです。\n\nă‚‚ă—ă“ăźă‚ąă‚«ă‚Šăƒłăƒˆăźäœœæˆă«ćżƒćœ“ăŸă‚ŠăŒăȘă„ć ŽćˆăŻă€ă“ăźăƒĄăƒŒăƒ«ă‚’ç„ĄèŠ–ă—ăŠăă ă•ă„ă€‚",
"emailVerificationBodyHtml":
'<p>ă“ăźăƒĄăƒŒăƒ«ă‚ąăƒ‰ăƒŹă‚čで{2}ă‚ąă‚«ă‚ŠăƒłăƒˆăŒäœœæˆă•ă‚ŒăŸă—ăŸă€‚ä»„äž‹ăźăƒȘンクをクăƒȘăƒƒă‚Żă—ăŠăƒĄăƒŒăƒ«ă‚ąăƒ‰ăƒŹă‚čたçąșèȘă‚’ćźŒäș†ă—ăŠăă ă•ă„ă€‚</p><p><a href="{0}">ăƒĄăƒŒăƒ«ă‚ąăƒ‰ăƒŹă‚čたçąșèȘ</a></p><p>こぼăƒȘンクは{3}ă ă‘æœ‰ćŠčです。</p><p>ă‚‚ă—ă“ăźă‚ąă‚«ă‚Šăƒłăƒˆăźäœœæˆă«ćżƒćœ“ăŸă‚ŠăŒăȘă„ć ŽćˆăŻă€ă“ăźăƒĄăƒŒăƒ«ă‚’ç„ĄèŠ–ă—ăŠăă ă•ă„ă€‚</p>',
"emailTestSubject": "[KEYCLOAK] - SMTPテă‚čăƒˆăƒĄăƒƒă‚»ăƒŒă‚ž",
"emailTestBody": "これはテă‚čăƒˆăƒĄăƒƒă‚»ăƒŒă‚žă§ă™",
"emailTestBodyHtml": "<p>これはテă‚čăƒˆăƒĄăƒƒă‚»ăƒŒă‚žă§ă™</p>",
"identityProviderLinkSubject": "ăƒȘンク {0}",
"identityProviderLinkBody":
'あăȘたぼ"{1}"ă‚ąă‚«ă‚Šăƒłăƒˆăš{2}ăƒŠăƒŒă‚¶ăƒŒăź"{0}"ă‚ąă‚«ă‚ŠăƒłăƒˆăźăƒȘăƒłă‚ŻăŒèŠæ±‚ă•ă‚ŒăŸă—ăŸă€‚ä»„äž‹ăźăƒȘンクをクăƒȘăƒƒă‚Żă—ăŠă‚ąă‚«ă‚ŠăƒłăƒˆăźăƒȘăƒłă‚Żă‚’èĄŒăŁăŠăă ă•ă„ă€‚\n\n{3}\n\nこぼăƒȘンクは{5}ă ă‘æœ‰ćŠčです。\n\nă‚‚ă—ă‚ąă‚«ă‚ŠăƒłăƒˆăźăƒȘăƒłă‚Żă‚’èĄŒă‚ăȘă„ć ŽćˆăŻă€ă“ăźăƒĄăƒƒă‚»ăƒŒă‚žă‚’ç„ĄèŠ–ă—ăŠăă ă•ă„ă€‚ă‚ąă‚«ă‚ŠăƒłăƒˆăźăƒȘăƒłă‚Żă‚’èĄŒă†ă“ăšă§ă€{0}ç”Œç”±ă§{1}ă«ăƒ­ă‚°ă‚€ăƒłă™ă‚‹ă“ăšăŒă§ăă‚‹ă‚ˆă†ă«ăȘă‚ŠăŸă™ă€‚',
"identityProviderLinkBodyHtml":
'<p>あăȘたぼ<b>{1}</b>ă‚ąă‚«ă‚Šăƒłăƒˆăš{2}ăƒŠăƒŒă‚¶ăƒŒăź<b>{0}</b>ă‚ąă‚«ă‚ŠăƒłăƒˆăźăƒȘăƒłă‚ŻăŒèŠæ±‚ă•ă‚ŒăŸă—ăŸă€‚ä»„äž‹ăźăƒȘンクをクăƒȘăƒƒă‚Żă—ăŠă‚ąă‚«ă‚ŠăƒłăƒˆăźăƒȘăƒłă‚Żă‚’èĄŒăŁăŠăă ă•ă„ă€‚</p><p><a href="{3}">ă‚ąă‚«ă‚ŠăƒłăƒˆăƒȘンクぼçąșèȘ</a></p><p>こぼăƒȘンクは{5}ă ă‘æœ‰ćŠčです。</p><p>ă‚‚ă—ă‚ąă‚«ă‚ŠăƒłăƒˆăźăƒȘăƒłă‚Żă‚’èĄŒă‚ăȘă„ć ŽćˆăŻă€ă“ăźăƒĄăƒƒă‚»ăƒŒă‚žă‚’ç„ĄèŠ–ă—ăŠăă ă•ă„ă€‚ă‚ąă‚«ă‚ŠăƒłăƒˆăźăƒȘăƒłă‚Żă‚’èĄŒă†ă“ăšă§ă€{0}ç”Œç”±ă§{1}ă«ăƒ­ă‚°ă‚€ăƒłă™ă‚‹ă“ăšăŒă§ăă‚‹ă‚ˆă†ă«ăȘă‚ŠăŸă™ă€‚</p>',
"passwordResetSubject": "パă‚čăƒŻăƒŒăƒ‰ăźăƒȘă‚»ăƒƒăƒˆ",
"passwordResetBody":
"あăȘたぼ{2}ă‚ąă‚«ă‚Šăƒłăƒˆăźăƒ‘ă‚čăƒŻăƒŒăƒ‰ăźć€‰æ›ŽăŒèŠæ±‚ă•ă‚ŒăŠă„ăŸă™ă€‚ä»„äž‹ăźăƒȘンクをクăƒȘックしどパă‚čăƒŻăƒŒăƒ‰ăźăƒȘă‚»ăƒƒăƒˆă‚’èĄŒăŁăŠăă ă•ă„ă€‚\n\n{0}\n\nこぼăƒȘンクは{3}ă ă‘æœ‰ćŠčです。\n\nもしパă‚čăƒŻăƒŒăƒ‰ăźăƒȘă‚»ăƒƒăƒˆă‚’èĄŒă‚ăȘă„ć ŽćˆăŻă€ă“ăźăƒĄăƒƒă‚»ăƒŒă‚žă‚’ç„ĄèŠ–ă—ăŠăă ă•ă„ă€‚äœ•ă‚‚ć€‰æ›Žă•ă‚ŒăŸă›ă‚“ă€‚",
"passwordResetBodyHtml":
'<p>あăȘたぼ{2}ă‚ąă‚«ă‚Šăƒłăƒˆăźăƒ‘ă‚čăƒŻăƒŒăƒ‰ăźć€‰æ›ŽăŒèŠæ±‚ă•ă‚ŒăŠă„ăŸă™ă€‚ä»„äž‹ăźăƒȘンクをクăƒȘックしどパă‚čăƒŻăƒŒăƒ‰ăźăƒȘă‚»ăƒƒăƒˆă‚’èĄŒăŁăŠăă ă•ă„ă€‚</p><p><a href="{0}">パă‚čăƒŻăƒŒăƒ‰ăźăƒȘă‚»ăƒƒăƒˆ</a></p><p>こぼăƒȘンクは{3}ă ă‘æœ‰ćŠčです。</p><p>もしパă‚čăƒŻăƒŒăƒ‰ăźăƒȘă‚»ăƒƒăƒˆă‚’èĄŒă‚ăȘă„ć ŽćˆăŻă€ă“ăźăƒĄăƒƒă‚»ăƒŒă‚žă‚’ç„ĄèŠ–ă—ăŠăă ă•ă„ă€‚äœ•ă‚‚ć€‰æ›Žă•ă‚ŒăŸă›ă‚“ă€‚</p>',
"executeActionsSubject": "ă‚ąă‚«ă‚Šăƒłăƒˆăźæ›Žæ–°",
"executeActionsBody":
"æŹĄăźă‚ąă‚Żă‚·ăƒ§ăƒłă‚’ćźŸèĄŒă™ă‚‹ă“ăšă«ă‚ˆă‚Šă€çźĄç†è€…ă‚ˆă‚Šă‚ăȘたぼ{2}ă‚ąă‚«ă‚Šăƒłăƒˆăźæ›Žæ–°ăŒèŠæ±‚ă•ă‚ŒăŠă„ăŸă™: {3}。仄䞋たăƒȘンクをクăƒȘăƒƒă‚Żă—ăŠă“ăźăƒ—ăƒ­ă‚»ă‚čを開構しどください。\n\n{0}\n\nこぼăƒȘンクは{4}ă ă‘æœ‰ćŠčです。\n\nçźĄç†è€…ă‹ă‚‰ăźă“ăźć€‰æ›ŽèŠæ±‚ă«ă€ă„ăŠă”ć­˜çŸ„ăȘă„ć ŽćˆăŻă€ă“ăźăƒĄăƒƒă‚»ăƒŒă‚žă‚’ç„ĄèŠ–ă—ăŠăă ă•ă„ă€‚äœ•ă‚‚ć€‰æ›Žă•ă‚ŒăŸă›ă‚“ă€‚",
"executeActionsBodyHtml":
'<p>æŹĄăźă‚ąă‚Żă‚·ăƒ§ăƒłă‚’ćźŸèĄŒă™ă‚‹ă“ăšă«ă‚ˆă‚Šă€çźĄç†è€…ă‚ˆă‚Šă‚ăȘたぼ{2}ă‚ąă‚«ă‚Šăƒłăƒˆăźæ›Žæ–°ăŒèŠæ±‚ă•ă‚ŒăŠă„ăŸă™: {3}。仄䞋たăƒȘンクをクăƒȘăƒƒă‚Żă—ăŠă“ăźăƒ—ăƒ­ă‚»ă‚čを開構しどください。</p><p><a href="{0}">ă‚ąă‚«ă‚Šăƒłăƒˆăźæ›Žæ–°</a></p><p>こぼăƒȘンクは{4}ă ă‘æœ‰ćŠčです。</p><p>çźĄç†è€…ă‹ă‚‰ăźă“ăźć€‰æ›ŽèŠæ±‚ă«ă€ă„ăŠă”ć­˜çŸ„ăȘă„ć ŽćˆăŻă€ă“ăźăƒĄăƒƒă‚»ăƒŒă‚žă‚’ç„ĄèŠ–ă—ăŠăă ă•ă„ă€‚äœ•ă‚‚ć€‰æ›Žă•ă‚ŒăŸă›ă‚“ă€‚</p>',
"eventLoginErrorSubject": "ăƒ­ă‚°ă‚€ăƒłă‚šăƒ©ăƒŒ",
"eventLoginErrorBody": "{0}に{1}ă‹ă‚‰ăźăƒ­ă‚°ă‚€ăƒłć€±æ•—ăŒă‚ăȘăŸăźă‚ąă‚«ă‚Šăƒłăƒˆă§æ€œć‡șă•ă‚ŒăŸă—ăŸă€‚ćżƒćœ“ăŸă‚ŠăŒăȘă„ć ŽćˆăŻă€çźĄç†è€…ă«é€Łç”Ąă—ăŠăă ă•ă„ă€‚",
"eventLoginErrorBodyHtml":
"<p>{0}に{1}ă‹ă‚‰ăźăƒ­ă‚°ă‚€ăƒłć€±æ•—ăŒă‚ăȘăŸăźă‚ąă‚«ă‚Šăƒłăƒˆă§æ€œć‡șă•ă‚ŒăŸă—ăŸă€‚ćżƒćœ“ăŸă‚ŠăŒăȘă„ć ŽćˆăŻçźĄç†è€…ă«é€Łç”Ąă—ăŠăă ă•ă„ă€‚</p>",
"eventRemoveTotpSubject": "OTPた扊陀",
"eventRemoveTotpBody": "{0}に{1}ă‹ă‚‰ăźæ“äœœă§OTPăŒć‰Šé™€ă•ă‚ŒăŸă—ăŸă€‚ćżƒćœ“ăŸă‚ŠăŒăȘă„ć ŽćˆăŻă€çźĄç†è€…ă«é€Łç”Ąă—ăŠăă ă•ă„ă€‚",
"eventRemoveTotpBodyHtml": "<p>{0}に{1}ă‹ă‚‰ăźæ“äœœă§OTPăŒć‰Šé™€ă•ă‚ŒăŸă—ăŸă€‚ćżƒćœ“ăŸă‚ŠăŒăȘă„ć ŽćˆăŻă€çźĄç†è€…ă«é€Łç”Ąă—ăŠăă ă•ă„ă€‚</p>",
"eventUpdatePasswordSubject": "パă‚čăƒŻăƒŒăƒ‰ăźæ›Žæ–°",
"eventUpdatePasswordBody": "{0}に{1}ă‹ă‚‰ăźæ“äœœă§ă‚ăȘたぼパă‚čăƒŻăƒŒăƒ‰ăŒć€‰æ›Žă•ă‚ŒăŸă—ăŸă€‚ćżƒćœ“ăŸă‚ŠăŒăȘă„ć ŽćˆăŻă€çźĄç†è€…ă«é€Łç”Ąă—ăŠăă ă•ă„ă€‚",
"eventUpdatePasswordBodyHtml":
"<p>{0}に{1}ă‹ă‚‰ăźæ“äœœă§ă‚ăȘたぼパă‚čăƒŻăƒŒăƒ‰ăŒć€‰æ›Žă•ă‚ŒăŸă—ăŸă€‚ćżƒćœ“ăŸă‚ŠăŒăȘă„ć ŽćˆăŻă€çźĄç†è€…ă«é€Łç”Ąă—ăŠăă ă•ă„ă€‚</p>",
"eventUpdateTotpSubject": "OTPăźæ›Žæ–°",
"eventUpdateTotpBody": "{0}に{1}ă‹ă‚‰ăźæ“äœœă§OTPăŒæ›Žæ–°ă•ă‚ŒăŸă—ăŸă€‚ćżƒćœ“ăŸă‚ŠăŒăȘă„ć ŽćˆăŻă€çźĄç†è€…ă«é€Łç”Ąă—ăŠăă ă•ă„ă€‚",
"eventUpdateTotpBodyHtml": "<p>{0}に{1}ă‹ă‚‰ăźæ“äœœă§OTPăŒæ›Žæ–°ă•ă‚ŒăŸă—ăŸă€‚ćżƒćœ“ăŸă‚ŠăŒăȘă„ć ŽćˆăŻă€çźĄç†è€…ă«é€Łç”Ąă—ăŠăă ă•ă„ă€‚</p>",
"requiredAction.CONFIGURE_TOTP": "OTPăźèš­ćźš",
"requiredAction.terms_and_conditions": "ćˆ©ç”šèŠçŽ„",
"requiredAction.UPDATE_PASSWORD": "パă‚čăƒŻăƒŒăƒ‰ăźæ›Žæ–°",
"requiredAction.UPDATE_PROFILE": "ăƒ—ăƒ­ăƒ•ă‚Ąă‚€ăƒ«ăźæ›Žæ–°",
"requiredAction.VERIFY_EMAIL": "EăƒĄăƒŒăƒ«ăźçąșèȘ",
"linkExpirationFormatter.timePeriodUnit.seconds": "秒",
"linkExpirationFormatter.timePeriodUnit.seconds.1": "秒",
"linkExpirationFormatter.timePeriodUnit.minutes": "戆",
"linkExpirationFormatter.timePeriodUnit.minutes.1": "戆",
"linkExpirationFormatter.timePeriodUnit.hours": "時間",
"linkExpirationFormatter.timePeriodUnit.hours.1": "時間",
"linkExpirationFormatter.timePeriodUnit.days": "æ—„",
"linkExpirationFormatter.timePeriodUnit.days.1": "æ—„",
"emailVerificationBodyCode": "æŹĄăźă‚łăƒŒăƒ‰ă‚’ć…„ćŠ›ă—ăŠăƒĄăƒŒăƒ«ă‚ąăƒ‰ăƒŹă‚čをçąșèȘă—ăŠăă ă•ă„ă€‚\n\n{0}\n\n.",
"emailVerificationBodyCodeHtml": "<p>æŹĄăźă‚łăƒŒăƒ‰ă‚’ć…„ćŠ›ă—ăŠăƒĄăƒŒăƒ«ă‚ąăƒ‰ăƒŹă‚čをçąșèȘă—ăŠăă ă•ă„ă€‚</p><p><b>{0}</b></p>",
},
"lt": {
"emailVerificationSubject": "El. paĆĄto patvirtinimas",
"emailVerificationBody":
"Paskyra {2} sukurta naudojant ĆĄÄŻ el. paĆĄto adresą. Jei tai buvote JĆ«s, tuomet paspauskite ĆŸemiau esančią nuorodą\n\n{0}\n\nĆ i nuoroda galioja {1} min.\n\nJei paskyros nekĆ«rėte, tuomet ignuoruokite ĆĄÄŻ laiĆĄką. ",
"emailVerificationBodyHtml":
'<p>Paskyra {2} sukurta naudojant ĆĄÄŻ el. paĆĄto adresą. Jei tao buvote JĆ«s, tuomet paspauskite ĆŸemiau esančią nuorodą</p><p><a href=LT"{0}">{0}</a></p><p>Ć i nuoroda galioja {1} min.</p><p>nJei paskyros nekĆ«rėte, tuomet ignuoruokite ĆĄÄŻ laiĆĄką.</p>',
"identityProviderLinkSubject": "Sąsaja {0}",
"identityProviderLinkBody":
'KaĆŸas pageidauja susieti JĆ«sĆł "{1}" paskyrą su "{0}" {2} naudotojo paskyrą. Jei tai buvote JĆ«s, tuomet paspauskite ĆŸemiau esančią nuorodą norėdami susieti paskyras\n\n{3}\n\nĆ i nuoroda galioja {4} min.\n\nJei paskyrĆł susieti nenorite, tuomet ignoruokite ĆĄÄŻ laiĆĄką. Jei paskyras susiesite, tuomet prie {1} galėsiste prisijungti per {0}.',
"identityProviderLinkBodyHtml":
'<p>ĆŸas pageidauja susieti JĆ«sĆł <b>{1}</b> paskyrą su <b>{0}</b> {2} naudotojo paskyrą. Jei tai buvote JĆ«s, tuomet paspauskite ĆŸemiau esančią nuorodą norėdami susieti paskyras</p><p><a href=LT"{3}">{3}</a></p><p>Ć i nuoroda galioja {4} min.</p><p>Jei paskyrĆł susieti nenorite, tuomet ignoruokite ĆĄÄŻ laiĆĄką. Jei paskyras susiesite, tuomet prie {1} galėsiste prisijungti per {0}.</p>',
"passwordResetSubject": "SlaptaĆŸodĆŸio atkĆ«rimas",
"passwordResetBody":
"KaĆŸkas pageidauja pakeisti JĆ«sĆł paskyros {2} slaptaĆŸodÄŻ. Jei tai buvote JĆ«s, tuomet paspauskite ĆŸemiau esančią nuorodą slaptaĆŸodĆŸio pakeitimui.\n\n{0}\n\nĆ i nuoroda ir kodas galioja {1} min.\n\nJei nepageidajate keisti slaptaĆŸodĆŸio, tuomet ignoruokite ĆĄÄŻ laiĆĄką ir niekas nebus pakeista.",
"passwordResetBodyHtml":
'<p>KaĆŸkas pageidauja pakeisti JĆ«sĆł paskyros {2} slaptaĆŸodÄŻ. Jei tai buvote JĆ«s, tuomet paspauskite ĆŸemiau esančią nuorodą slaptaĆŸodĆŸio pakeitimui.</p><p><a href=LT"{0}">{0}</a></p><p>Ć i nuoroda ir kodas galioja {1} min.</p><p>Jei nepageidajate keisti slaptaĆŸodĆŸio, tuomet ignoruokite ĆĄÄŻ laiĆĄką ir niekas nebus pakeista.</p>',
"executeActionsSubject": "Atnaujinkite savo paskyrą",
"executeActionsBody":
"Sistemos administratorius pageidauja, kad JĆ«s atnaujintumėte savo {2} paskyrą. Paspauskite ĆŸemiau esančią nuorodą paskyros duomenĆł atnaujinimui.\n\n{0}\n\nĆ i nuoroda galioja {1} min.\n\nJei JĆ«s neasate tikri, kad tai administratoriaus pageidavimas, tuomet ignoruokite ĆĄÄŻ laiĆĄką ir niekas nebus pakeista.",
"executeActionsBodyHtml":
'<p>Sistemos administratorius pageidauja, kad JĆ«s atnaujintumėte savo {2} paskyrą. Paspauskite ĆŸemiau esančią nuorodą paskyros duomenĆł atnaujinimui.</p><p><a href=LT"{0}">{0}</a></p><p>Ć i nuoroda galioja {1} min.</p><p>Jei JĆ«s neasate tikri, kad tai administratoriaus pageidavimas, tuomet ignoruokite ĆĄÄŻ laiĆĄką ir niekas nebus pakeista.</p>',
"eventLoginErrorSubject": "Nesėkmingas bandymas prisijungti prie jĆ«sĆł paskyros",
"eventLoginErrorBody":
"Bandymas prisijungti prie jĆ«sĆł paskyros {0} iĆĄ {1} nesėkmingas. Jei tai nebuvote jĆ«s, tuomet susisiekite su administratoriumi",
"eventLoginErrorBodyHtml":
"<p>Bandymas prisijungti prie jĆ«sĆł paskyros {0} iĆĄ {1} nesėkmingas. Jei tai nebuvote jĆ«s, tuomet susisiekite su administratoriumi</p>",
"eventRemoveTotpSubject": "OTP paĆĄalinimas",
"eventRemoveTotpBody":
"KaĆŸkas pageidauja atsieti TOPT JĆ«sĆł {1} paskyroje su {0}. Jei tai nebuvote JĆ«s, tuomet susisiekite su administratoriumi",
"eventRemoveTotpBodyHtml":
"<p>KaĆŸkas pageidauja atsieti TOPT JĆ«sĆł <b>{1}</b> paskyroje su <b>{0}</b>. Jei tai nebuvote JĆ«s, tuomet susisiekite su administratoriumi</p>",
"eventUpdatePasswordSubject": "SlaptaĆŸodĆŸio atnaujinimas",
"eventUpdatePasswordBody": "{1} paskyroje {0} pakeisas jĆ«sĆł slaptaĆŸodis. Jei JĆ«s nekeitėte, tuomet susisiekite su administratoriumi",
"eventUpdatePasswordBodyHtml":
"<p>{1} paskyroje {0} pakeisas jĆ«sĆł slaptaĆŸodis. Jei JĆ«s nekeitėte, tuomet susisiekite su administratoriumi</p>",
"eventUpdateTotpSubject": "OTP atnaujinimas",
"eventUpdateTotpBody": "OTP JƫsƳ {1} paskyroje su {0} buvo atnaujintas. Jei tai nebuvote Jƫs, tuomet susisiekite su administratoriumi",
"eventUpdateTotpBodyHtml":
"<p>OTP JƫsƳ {1} paskyroje su {0} buvo atnaujintas. Jei tai nebuvote Jƫs, tuomet susisiekite su administratoriumi</p>",
},
"nl": {
"emailVerificationSubject": "Bevestig e-mailadres",
"emailVerificationBody":
"Iemand heeft een {2} account aangemaakt met dit e-mailadres. Als u dit was, klikt u op de onderstaande koppeling om uw e-mailadres te bevestigen \n\n{0}\n\nDeze koppeling zal binnen {3} vervallen.\n\nU kunt dit bericht negeren indien u dit account niet heeft aangemaakt.",
"emailVerificationBodyHtml":
'<p>Iemand heeft een {2} account aangemaakt met dit e-mailadres. Als u dit was, klikt u op de onderstaande koppeling om uw e-mailadres te bevestigen</p><p><a href="{0}">Koppeling naar e-mailadres bevestiging</a></p><p>Deze koppeling zal binnen {3} vervallen.</p<p>U kunt dit bericht negeren indien u dit account niet heeft aangemaakt.</p>',
"emailTestSubject": "[KEYCLOAK] - SMTP testbericht",
"emailTestBody": "Dit is een testbericht",
"emailTestBodyHtml": "<p>Dit is een testbericht</p>",
"identityProviderLinkSubject": "Koppel {0}",
"identityProviderLinkBody":
'Iemand wil uw "{1}" account koppelen met "{0}" account van gebruiker {2}. Als u dit was, klik dan op de onderstaande link om de accounts te koppelen\n\n{3}\n\nDeze link zal over {5} vervallen.\n\nAls u de accounts niet wilt koppelen, negeer dan dit bericht. Als u accounts koppelt, dan kunt u bij {1} inloggen via {0}.',
"identityProviderLinkBodyHtml":
'<p>Iemand wil uw "{1}" account koppelen met "{0}" account van gebruiker {2}. Als u dit was, klik dan op de onderstaande link om de accounts te koppelen</p><p><a href="{3}">Link om accounts te koppelen</a></p><p>Deze link zal over {5} vervallen.</p><p>Als u de accounts niet wilt koppelen, negeer dan dit bericht. Als u accounts koppelt, dan kunt u bij {1} inloggen via {0}.</p>',
"passwordResetSubject": "Wijzig wachtwoord",
"passwordResetBody":
"Iemand verzocht de aanmeldgegevens van uw {2} account te wijzigen. Als u dit was, klik dan op de onderstaande koppeling om ze te wijzigen.\n\n{0}\n\nDe link en de code zullen binnen {3} vervallen.\n\nAls u uw aanmeldgegevens niet wilt wijzigen, negeer dan dit bericht en er zal niets gewijzigd worden.",
"passwordResetBodyHtml":
'<p>Iemand verzocht de aanmeldgegevens van uw {2} account te wijzigen. Als u dit was, klik dan op de onderstaande koppeling om ze te wijzigen.</p><p><a href="{0}">Wijzig aanmeldgegevens</a></p><p>De link en de code zullen binnen {3} vervallen.</p><p>Als u uw aanmeldgegevens niet wilt wijzigen, negeer dan dit bericht en er zal niets gewijzigd worden.</p>',
"executeActionsSubject": "Wijzig uw account",
"executeActionsBody":
"Uw beheerder heeft u verzocht uw {2} account te wijzigen. Klik op de onderstaande koppeling om dit proces te starten. \n\n{0}\n\nDeze link zal over {4} vervallen. \n\nAls u niet over dit verzoek op de hoogte was, negeer dan dit bericht om uw account ongewijzigd te laten.",
"executeActionsBodyHtml":
'<p>Uw beheerder heeft u verzocht uw {2} account te wijzigen. Klik op de onderstaande koppeling om dit proces te starten.</p><p><a href="{0}">Link naar account wijziging</a></p><p>Deze link zal over {4} vervallen.</p><p>Als u niet over dit verzoek op de hoogte was, negeer dan dit bericht om uw account ongewijzigd te laten.</p>',
"eventLoginErrorSubject": "Inlogfout",
"eventLoginErrorBody":
"Er is een foutieve inlogpoging gedetecteerd op uw account om {0} vanuit {1}. Als u dit niet was, neem dan contact op met de beheerder.",
"eventLoginErrorBodyHtml":
"<p>Er is een foutieve inlogpoging gedetecteerd op uw account om {0} vanuit {1}. Als u dit niet was, neem dan contact op met de beheerder.</p>",
"eventRemoveTotpSubject": "OTP verwijderd",
"eventRemoveTotpBody": "OTP is verwijderd van uw account om {0} vanuit {1}. Als u dit niet was, neem dan contact op met uw beheerder.",
"eventRemoveTotpBodyHtml":
"<p>OTP is verwijderd van uw account om {0} vanuit {1}. Als u dit niet was, neem dan contact op met uw beheerder.</p>",
"eventUpdatePasswordSubject": "Wachtwoord gewijzigd",
"eventUpdatePasswordBody": "Uw wachtwoord is gewijzigd om {0} door {1}. Als u dit niet was, neem dan contact op met uw beheerder.",
"eventUpdatePasswordBodyHtml": "<p>Uw wachtwoord is gewijzigd om {0} door {1}. Als u dit niet was, neem dan contact op met uw beheerder.</p>",
"eventUpdateTotpSubject": "OTP gewijzigd",
"eventUpdateTotpBody": "OTP is gewijzigd voor uw account om {0} door {1}. Als u dit niet was, neem dan contact op met uw beheerder.",
"eventUpdateTotpBodyHtml":
"<p>OTP is gewijzigd voor uw account om {0} door {1}. Als u dit niet was, neem dan contact op met uw beheerder.</p>",
"linkExpirationFormatter.timePeriodUnit.seconds": "seconden",
"linkExpirationFormatter.timePeriodUnit.seconds.1": "seconde",
"linkExpirationFormatter.timePeriodUnit.minutes": "minuten",
"linkExpirationFormatter.timePeriodUnit.minutes.1": "minuut",
"linkExpirationFormatter.timePeriodUnit.hours": "uur",
"linkExpirationFormatter.timePeriodUnit.hours.1": "uur",
"linkExpirationFormatter.timePeriodUnit.days": "dagen",
"linkExpirationFormatter.timePeriodUnit.days.1": "dag",
},
"no": {
"emailVerificationSubject": "Bekreft e-postadresse",
"emailVerificationBody":
"Noen har opprettet en {2} konto med denne e-postadressen. Hvis dette var deg, klikk pÄ lenken nedenfor for Ä bekrefte e-postadressen din\n\n{0}\n\nDenne lenken vil utlÞpe om {1} minutter.\n\nHvis du ikke opprettet denne kontoen, vennligst ignorer denne meldingen.",
"emailVerificationBodyHtml":
'<p>Noen har opprettet en {2} konto med denne e-postadressen. Hvis dette var deg, klikk pÄ lenken nedenfor for Ä bekrefte e-postadressen din</p><p><a href="{0}">{0}</a></p><p>Denne lenken vil utlÞpe om {1} minutter.</p><p>Hvis du ikke opprettet denne kontoen, vennligst ignorer denne meldingen.</p>',
"identityProviderLinkSubject": "Lenke {0}",
"identityProviderLinkBody":
"Noen vil koble din <b>{1}</b> konto med <b>{0}</b> konto til bruker {2}. Hvis dette var deg, klikk pÄ lenken nedenfor for Ä koble kontoene\n\n{3}\n\nDenne lenken vil utlÞpe om {4} minutter\n\nHvis du ikke vil koble kontoene, vennligst ignorer denne meldingen. Hvis du kobler kontoene sammen vil du kunne logge inn til {1} gjennom {0}.",
"identityProviderLinkBodyHtml":
'<p>Noen vil koble din <b>{1}</b> konto med <b>{0}</b> konto til bruker {2}. Hvis dette var deg, klikk pÄ lenken nedenfor for Ä koble kontoene.</p><p><a href="{3}">{3}</a></p><p>Denne lenken vil utlÞpe om {4} minutter.</p><p>Hvis du ikke vil koble kontoene, vennligst ignorer denne meldingen. Hvis du kobler kontoene sammen vil du kunne logge inn til {1} gjennom {0}.</p>',
"passwordResetSubject": "Tilbakestill passord",
"passwordResetBody":
"Noen har bedt om Ä endre innloggingsdetaljene til din konto {2}. Hvis dette var deg, klikk pÄ lenken nedenfor for Ä tilbakestille dem.\n\n{0}\n\nDenne lenken vil utlÞpe om {1} minutter.\n\nHvis du ikke vil tilbakestille din innloggingsdata, vennligst ignorer denne meldingen og ingenting vil bli endret.",
"passwordResetBodyHtml":
'<p>Noen har bedt om Ä endre innloggingsdetaljene til din konto {2}. Hvis dette var deg, klikk pÄ lenken nedenfor for Ä tilbakestille dem.</p><p><a href="{0}">{0}</a></p><p>Denne lenken vil utlÞpe om {1} minutter.</p><p>Hvis du ikke vil tilbakestille din innloggingsdata, vennligst ignorer denne meldingen og ingenting vil bli endret.</p>',
"executeActionsSubject": "Oppdater kontoen din",
"executeActionsBody":
"Administrator har anmodet at du oppdaterer din {2} konto. Klikk pÄ lenken nedenfor for Ä starte denne prosessen\n\n{0}\n\nDenne lenken vil utlÞpe om {1} minutter.\n\nHvis du ikke var klar over at administrator har bedt om dette, vennligst ignorer denne meldingen og ingenting vil bli endret.",
"executeActionsBodyHtml":
'<p>Administrator har anmodet at du oppdaterer din {2} konto. Klikk pÄ linken nedenfor for Ä starte denne prosessen.</p><p><a href="{0}">{0}</a></p><p>Denne lenken vil utlÞpe om {1} minutter.</p><p>Hvis du ikke var klar over at administrator har bedt om dette, ignorer denne meldingen og ingenting vil bli endret. </p>',
"eventLoginErrorSubject": "Innlogging feilet",
"eventLoginErrorBody":
"Et mislykket innloggingsforsÞk ble oppdaget pÄ din konto pÄ {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator.",
"eventLoginErrorBodyHtml":
"<p>Et mislykket innloggingsforsÞk ble oppdaget pÄ din konto pÄ {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator.</p>",
"eventRemoveTotpSubject": "Fjern engangskode",
"eventRemoveTotpBody": "Engangskode ble fjernet fra kontoen din pÄ {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator.",
"eventRemoveTotpBodyHtml":
"<p>Engangskode ble fjernet fra kontoen din pÄ {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator.</p>",
"eventUpdatePasswordSubject": "Oppdater passord",
"eventUpdatePasswordBody": "Ditt passord ble endret i {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator.",
"eventUpdatePasswordBodyHtml": "<p>Ditt passord ble endret i {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator. </p>",
"eventUpdateTotpSubject": "Oppdater engangskode",
"eventUpdateTotpBody": "Engangskode ble oppdatert for kontoen din pÄ {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator.",
"eventUpdateTotpBodyHtml":
"<p>Engangskode ble oppdatert for kontoen din pÄ {0} fra {1}. Hvis dette ikke var deg, vennligst kontakt administrator. </p>",
},
"pl": {
"emailVerificationSubject": "Zweryfikuj email",
"emailVerificationBody":
"Ktoƛ utworzyƂ juĆŒ konto {2} z tym adresem e-mail. Jeƛli to Ty, kliknij poniĆŒszy link, aby zweryfikować swĂłj adres e-mail \n\n{0}\n\nLink ten wygaƛnie w ciągu {3}.\n\nJeƛli nie utworzyƂeƛ tego konta, po prostu zignoruj tę wiadomoƛć.",
"emailVerificationBodyHtml":
'<p>Ktoƛ utworzyƂ juĆŒ konto {2} z tym adresem e-mail. Jeƛli to Ty, kliknij <a href="{0}">ten link</a> aby zweryfikować swĂłj adres e-mail</p><p>Link ten wygaƛnie w ciągu {3}</p><p>Jeƛli nie utworzyƂeƛ tego konta, po prostu zignoruj tę wiadomoƛć.</p>',
"emailTestSubject": "[KEYCLOAK] - wiadomoƛć testowa SMTP",
"emailTestBody": "To jest wiadomoƛć testowa",
"emailTestBodyHtml": "<p>To jest wiadomoƛć testowa</p>",
"identityProviderLinkSubject": "Link {0}",
"identityProviderLinkBody":
'Ktoƛ chce poƂączyć Twoje konto "{1}" z kontem "{0}" uĆŒytkownika {2}. Jeƛli to Ty, kliknij poniĆŒszy link by poƂączyć konta\n\n{3}\n\nTen link wygaƛnie w ciągu {5}.\n\nJeƛli nie chcesz poƂączyć konta to zignoruj tę wiadomoƛć. Jeƛli poƂączysz konta, będziesz mĂłgƂ się zalogować na {1} przez {0}.',
"identityProviderLinkBodyHtml":
'<p>Ktoƛ chce poƂączyć Twoje konto <b>{1}</b> z kontem <b>{0}</b> uĆŒytkownika {2}. Jeƛli to Ty, kliknij <a href="{3}">ten link</a> by poƂączyć konta.</p><p>Ten link wygaƛnie w ciągu {5}.</p><p>Jeƛli nie chcesz poƂączyć konta to zignoruj tę wiadomoƛć. Jeƛli poƂączysz konta, będziesz mĂłgƂ się zalogować na {1} przez {0}.</p>',
"passwordResetSubject": "Zresetuj hasƂo",
"passwordResetBody":
"Ktoƛ wƂaƛnie poprosiƂ o zmianę danych logowania Twojego konta {2}. Jeƛli to Ty, kliknij poniĆŒszy link, aby je zresetować.\n\n{0}\n\nTen link i kod stracą waĆŒnoƛć w ciągu {3}.\n\nJeƛli nie chcesz zresetować swoich danych logowania, po prostu zignoruj tę wiadomoƛć i nic się nie zmieni.",
"passwordResetBodyHtml":
'<p>Ktoƛ wƂaƛnie poprosiƂ o zmianę poƛwiadczeƄ Twojego konta {2}. Jeƛli to Ty, kliknij poniĆŒszy link, aby je zresetować.</p><p><a href="{0}">Link do resetowania poƛwiadczeƄ</a></p><p>Ten link wygaƛnie w ciągu {3}.</p><p>Jeƛli nie chcesz resetować swoich poƛwiadczeƄ, po prostu zignoruj tę wiadomoƛć i nic się nie zmieni.</p>',
"executeActionsSubject": "Zaktualizuj swoje konto",
"executeActionsBody":
"Administrator wƂaƛnie zaĆŒÄ…daƂ aktualizacji konta {2} poprzez wykonanie następujących dziaƂaƄ: {3}. Kliknij poniĆŒszy link, aby rozpocząć ten proces.\n\n{0}\n\nTen link wygaƛnie w ciągu {4}.\n\nJeƛli nie masz pewnoƛci, ĆŒe administrator tego zaĆŒÄ…daƂ, po prostu zignoruj tę wiadomoƛć i nic się nie zmieni.",
"executeActionsBodyHtml":
'<p>Administrator wƂaƛnie zaĆŒÄ…daƂ aktualizacji konta {2} poprzez wykonanie następujących dziaƂaƄ: {3}. Kliknij <a href="{0}">ten link</a>, aby rozpocząć proces.</p><p>Link ten wygaƛnie w ciągu {4}.</p><p>Jeƛli nie masz pewnoƛci, ĆŒe administrator tego zaĆŒÄ…daƂ, po prostu zignoruj tę wiadomoƛć i nic się nie zmieni.</p>',
"eventLoginErrorSubject": "BƂąd logowania",
"eventLoginErrorBody":
"Nieudana próba logowania zostaƂa wykryta na Twoim koncie {0} z {1}. Jeƛli to nie Ty, skontaktuj się z administratorem.",
"eventLoginErrorBodyHtml":
"<p>Nieudana próba logowania zostaƂa wykryta na Twoim koncie {0} z {1}. Jeƛli to nie Ty, skontaktuj się z administratorem.</p>",
"eventRemoveTotpSubject": "UsuƄ hasƂo jednorazowe (OTP)",
"eventRemoveTotpBody":
"HasƂo jednorazowe (OTP) zostaƂo usunięte z Twojego konta w {0} z {1}. Jeƛli to nie Ty, skontaktuj się z administratorem.",
"eventRemoveTotpBodyHtml":
"<p>HasƂo jednorazowe (OTP) zostaƂo usunięte z Twojego konta w {0} z {1}. Jeƛli to nie Ty, skontaktuj się z administratorem.</p>",
"eventUpdatePasswordSubject": "Aktualizuj hasƂo",
"eventUpdatePasswordBody": "Twoje hasƂo zostaƂo zmienione {0} z {1}. Jeƛli to nie Ty, skontaktuj się z administratorem.",
"eventUpdatePasswordBodyHtml": "<p>Twoje hasƂo zostaƂo zmienione {0} z {1}. Jeƛli to nie Ty, skontaktuj się z administratorem.</p>",
"eventUpdateTotpSubject": "Aktualizuj hasƂo jednorazowe (OTP)",
"eventUpdateTotpBody":
"HasƂo jednorazowe (OTP) zostaƂo zaktualizowane na Twoim koncie {0} z {1}. Jeƛli to nie Ty, skontaktuj się z administratorem.",
"eventUpdateTotpBodyHtml":
"<p>HasƂo jednorazowe (OTP) zostaƂo zaktualizowane na Twoim koncie {0} z {1}. Jeƛli to nie Ty, skontaktuj się z administratorem.</p>",
"requiredAction.CONFIGURE_TOTP": "Konfiguracja hasƂa jednorazowego (OTP)",
"requiredAction.terms_and_conditions": "Regulamin",
"requiredAction.UPDATE_PASSWORD": "Aktualizacja hasƂa",
"requiredAction.UPDATE_PROFILE": "Aktualizacja profilu",
"requiredAction.VERIFY_EMAIL": "Weryfikacja adresu e-mail",
"linkExpirationFormatter.timePeriodUnit.seconds": "sekund",
"linkExpirationFormatter.timePeriodUnit.seconds.1": "sekunda",
"linkExpirationFormatter.timePeriodUnit.seconds.2": "sekundy",
"linkExpirationFormatter.timePeriodUnit.seconds.3": "sekundy",
"linkExpirationFormatter.timePeriodUnit.seconds.4": "sekundy",
"linkExpirationFormatter.timePeriodUnit.minutes": "minut",
"linkExpirationFormatter.timePeriodUnit.minutes.1": "minuta",
"linkExpirationFormatter.timePeriodUnit.minutes.2": "minuty",
"linkExpirationFormatter.timePeriodUnit.minutes.3": "minuty",
"linkExpirationFormatter.timePeriodUnit.minutes.4": "minuty",
"linkExpirationFormatter.timePeriodUnit.hours": "godzin",
"linkExpirationFormatter.timePeriodUnit.hours.1": "godzina",
"linkExpirationFormatter.timePeriodUnit.hours.2": "godziny",
"linkExpirationFormatter.timePeriodUnit.hours.3": "godziny",
"linkExpirationFormatter.timePeriodUnit.hours.4": "godziny",
"linkExpirationFormatter.timePeriodUnit.days": "dni",
"linkExpirationFormatter.timePeriodUnit.days.1": "dzieƄ",
"emailVerificationBodyCode": "PotwierdĆș swĂłj adres e-mail wprowadzając następujący kod.\n\n{0}\n\n.",
"emailVerificationBodyCodeHtml": "<p>PotwierdĆș swĂłj adres e-mail, wprowadzając następujący kod.</p><p><b>{0}</b></p>",
},
"pt-BR": {
"emailVerificationSubject": "Verificação de e-mail",
"emailVerificationBody":
"AlguĂ©m criou uma conta {2} com este endereço de e-mail. Se foi vocĂȘ, clique no link abaixo para verificar o seu endereço de email\n\n{0}\n\nEste link irĂĄ expirar dentro de {3}.\n\nSe nĂŁo foi vocĂȘ que criou esta conta, basta ignorar esta mensagem.",
"emailVerificationBodyHtml":
'<p>AlguĂ©m criou uma conta {2} com este endereço de e-mail. Se foi vocĂȘ, clique no link abaixo para verificar o seu endereço de email</p><p><a href="{0}">{0}</a></p><p>Este link irĂĄ expirar dentro de {3}.</p><p>Se nĂŁo foi vocĂȘ que criou esta conta, basta ignorar esta mensagem.</p>',
"emailTestSubject": "[KEYCLOAK] - SMTP mensagem de teste",
"emailTestBody": "Esta Ă© uma mensagem de teste",
"emailTestBodyHtml": "<p>Esta Ă© uma mensagem de teste</p>",
"identityProviderLinkSubject": "Vincular {0}",
"identityProviderLinkBody":
'AlguĂ©m quer vincular sua conta "{1}" com a conta "{0}" do usuĂĄrio {2} . Se foi vocĂȘ, clique no link abaixo para vincular as contas.\n\n{3}\n\nEste link irĂĄ expirar em {5}.\n\nSe vocĂȘ nĂŁo quer vincular a conta, apenas ignore esta mensagem. Se vocĂȘ vincular as contas, vocĂȘ serĂĄ capaz de logar em {1} atrĂĄvĂ©s de {0}.',
"identityProviderLinkBodyHtml":
'<p>AlguĂ©m quer vincular sua conta <b>{1}</b> com a conta <b>{0}</b> do usuĂĄrio {2} . Se foi vocĂȘ, clique no link abaixo para vincular as contas.</p><p><a href="{3}">{3}</a></p><p>Este link irĂĄ expirar em {5}.</p><p>Se vocĂȘ nĂŁo quer vincular a conta, apenas ignore esta mensagem. Se vocĂȘ vincular as contas, vocĂȘ serĂĄ capaz de logar em {1} atrĂĄvĂ©s de {0}.</p>',
"passwordResetSubject": "Redefinição de senha",
"passwordResetBody":
"AlguĂ©m solicitou uma alteração de senha da sua conta {2}. Se foi vocĂȘ, clique no link abaixo para redefini-la.\n\n{0}\n\nEste link e cĂłdigo expiram em {3}.\n\nSe vocĂȘ nĂŁo deseja redefinir sua senha, apenas ignore esta mensagem e nada serĂĄ alterado.",
"passwordResetBodyHtml":
'<p>AlguĂ©m solicitou uma alteração de senha da sua conta {2}. Se foi vocĂȘ, clique no link abaixo para redefini-la.</p><p><a href="{0}">Link para redefinir a senha</a></p><p>Este link irĂĄ expirar em {3}.</p><p>Se vocĂȘ nĂŁo deseja redefinir sua senha, apenas ignore esta mensagem e nada serĂĄ alterado.</p>',
"executeActionsSubject": "Atualização de conta",
"executeActionsBody":
"O administrador solicitou que vocĂȘ atualize sua conta {2} executando a(s) seguinte(s) ação(Ă”es): {3}. Clique no link abaixo para iniciar o processo.\n\n{0}\n\nEste link irĂĄ expirar em {4}.\n\nSe vocĂȘ nĂŁo tem conhecimento de que o administrador solicitou isso, basta ignorar esta mensagem e nada serĂĄ alterado.",
"executeActionsBodyHtml":
'<p>O administrador solicitou que vocĂȘ atualize sua conta {2} executando a(s) seguinte(s) ação(Ă”es): {3}. Clique no link abaixo para iniciar o processo.</p><p><a href="{0}">Link to account update</a></p><p>Este link irĂĄ expirar em {4}.</p><p>Se vocĂȘ nĂŁo tem conhecimento de que o administrador solicitou isso, basta ignorar esta mensagem e nada serĂĄ alterado.</p>',
"eventLoginErrorSubject": "Erro de login",
"eventLoginErrorBody":
"Uma tentativa de login mal sucedida para a sua conta foi detectada em {0} de {1}. Se nĂŁo foi vocĂȘ, por favor, entre em contato com um administrador.",
"eventLoginErrorBodyHtml":
"<p>Uma tentativa de login mal sucedida para a sua conta foi detectada em {0} de {1}. Se nĂŁo foi vocĂȘ, por favor, entre em contato com um administrador.</p>",
"eventRemoveTotpSubject": "Remover OTP",
"eventRemoveTotpBody": "OTP foi removido da sua conta em {0} de {1}. Se nĂŁo foi vocĂȘ, por favor, entre em contato com um administrador.",
"eventRemoveTotpBodyHtml":
"<p>OTP foi removido da sua conta em {0} de {1}. Se nĂŁo foi vocĂȘ, por favor, entre em contato com um administrador.</p>",
"eventUpdatePasswordSubject": "Atualização de senha",
"eventUpdatePasswordBody": "Sua senha foi alterada em {0} de {1}. Se nĂŁo foi vocĂȘ, por favor, entre em contato com um administrador.",
"eventUpdatePasswordBodyHtml":
"<p>Sua senha foi alterada em {0} de {1}. Se nĂŁo foi vocĂȘ, por favor, entre em contato com um administrador.</p>",
"eventUpdateTotpSubject": "Atualização OTP",
"eventUpdateTotpBody":
"OTP foi atualizado para a sua conta em {0} de {1}. Se nĂŁo foi vocĂȘ, por favor, entre em contato com um administrador.",
"eventUpdateTotpBodyHtml":
"<p>OTP foi atualizado para a sua conta em {0} de {1}. Se nĂŁo foi vocĂȘ, por favor, entre em contato com um administrador.</p>",
"requiredAction.CONFIGURE_TOTP": "Configurar OTP",
"requiredAction.terms_and_conditions": "Termos e CondiçÔes",
"requiredAction.UPDATE_PASSWORD": "Atualizar Senha",
"requiredAction.UPDATE_PROFILE": "Atualizar Perfil",
"requiredAction.VERIFY_EMAIL": "Verificar E-mail",
"linkExpirationFormatter.timePeriodUnit.seconds": "segundos",
"linkExpirationFormatter.timePeriodUnit.seconds.1": "segundo",
"linkExpirationFormatter.timePeriodUnit.minutes": "minutos",
"linkExpirationFormatter.timePeriodUnit.minutes.1": "minuto",
"linkExpirationFormatter.timePeriodUnit.hours": "horas",
"linkExpirationFormatter.timePeriodUnit.hours.1": "hora",
"linkExpirationFormatter.timePeriodUnit.days": "dias",
"linkExpirationFormatter.timePeriodUnit.days.1": "dia",
"emailVerificationBodyCode": "Verifique seu endereço de e-mail digitando o seguinte código.\n\n{0}\n\n.",
"emailVerificationBodyCodeHtml": "<p>Verifique seu endereço de e-mail digitando o seguinte código.</p><p><b>{0}</b></p>",
},
"ru": {
"emailVerificationSubject": "ĐŸĐŸĐŽŃ‚ĐČĐ”Ń€Đ¶ĐŽĐ”ĐœĐžĐ” E-mail",
"emailVerificationBody":
"ĐšŃ‚ĐŸ-Ń‚ĐŸ ŃĐŸĐ·ĐŽĐ°Đ» ŃƒŃ‡Đ”Ń‚ĐœŃƒŃŽ Đ·Đ°ĐżĐžŃŃŒ {2} с ŃŃ‚ĐžĐŒ E-mail. ЕслО ŃŃ‚ĐŸ былО Вы, ĐœĐ°Đ¶ĐŒĐžŃ‚Đ” ĐœĐ° ŃĐ»Đ”ĐŽŃƒŃŽŃ‰ŃƒŃŽ ссылĐșу ĐŽĐ»Ń ĐżĐŸĐŽŃ‚ĐČĐ”Ń€Đ¶ĐŽĐ”ĐœĐžŃ ĐČĐ°ŃˆĐ”ĐłĐŸ email\n\n{0}\n\nЭта ссылĐșа ŃƒŃŃ‚Đ°Ń€Đ”Đ”Ń‚ чДрДз {1} ĐŒĐžĐœŃƒŃ‚.\n\nЕслО Вы ĐœĐ” ŃĐŸĐ·ĐŽĐ°ĐČалО ŃƒŃ‡Đ”Ń‚ĐœŃƒŃŽ Đ·Đ°ĐżĐžŃŃŒ, ĐżŃ€ĐŸŃŃ‚ĐŸ ĐżŃ€ĐŸĐžĐłĐœĐŸŃ€ĐžŃ€ŃƒĐčтД ŃŃ‚ĐŸ ĐżĐžŃŃŒĐŒĐŸ.",
"emailVerificationBodyHtml":
'<p>ĐšŃ‚ĐŸ-Ń‚ĐŸ ŃĐŸĐ·ĐŽĐ°Đ» ŃƒŃ‡Đ”Ń‚ĐœŃƒŃŽ Đ·Đ°ĐżĐžŃŃŒ {2} с ŃŃ‚ĐžĐŒ E-mail. ЕслО ŃŃ‚ĐŸ былО Вы, ĐœĐ°Đ¶ĐŒĐžŃ‚Đ” ĐżĐŸ ссылĐșĐ” ĐŽĐ»Ń ĐżĐŸĐŽŃ‚ĐČĐ”Ń€Đ¶ĐŽĐ”ĐœĐžŃ ĐČĐ°ŃˆĐ”ĐłĐŸ E-mail</p><p><a href="{0}">{0}</a></p><p>Эта ссылĐșа ŃƒŃŃ‚Đ°Ń€Đ”Đ”Ń‚ чДрДз {1} ĐŒĐžĐœŃƒŃ‚.</p><p>ЕслО Вы ĐœĐ” ŃĐŸĐ·ĐŽĐ°ĐČалО ŃƒŃ‡Đ”Ń‚ĐœŃƒŃŽ Đ·Đ°ĐżĐžŃŃŒ, ĐżŃ€ĐŸŃŃ‚ĐŸ ĐżŃ€ĐŸĐžĐłĐœĐŸŃ€ĐžŃ€ŃƒĐčтД ŃŃ‚ĐŸ ĐżĐžŃŃŒĐŒĐŸ.</p>',
"identityProviderLinkSubject": "ХсылĐșа {0}",
"identityProviderLinkBody":
'ĐšŃ‚ĐŸ-Ń‚ĐŸ Ń…ĐŸŃ‡Đ”Ń‚ сĐČŃĐ·Đ°Ń‚ŃŒ ĐČашу ŃƒŃ‡Đ”Ń‚ĐœŃƒŃŽ Đ·Đ°ĐżĐžŃŃŒ "{1}" с "{0}" ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč Đ·Đ°ĐżĐžŃŃŒŃŽ ĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Ń‚Đ”Đ»Ń {2} . ЕслО ŃŃ‚ĐŸ былО Вы, ĐœĐ°Đ¶ĐŒĐžŃ‚Đ” ĐżĐŸ ŃĐ»Đ”ĐŽŃƒŃŽŃ‰Đ”Đč ссылĐșĐ”, Ń‡Ń‚ĐŸĐ±Ń‹ сĐČŃĐ·Đ°Ń‚ŃŒ ŃƒŃ‡Đ”Ń‚ĐœŃ‹Đ” запОсО\n\n{3}\n\nЭта ссылĐșа ŃƒŃŃ‚Đ°Ń€Đ”Đ”Ń‚ чДрДз {4} ĐŒĐžĐœŃƒŃ‚.\n\nЕслО ŃŃ‚ĐŸ ĐœĐ” Ń…ĐŸŃ‚ĐžŃ‚Đ” ĐŸĐ±ŃŠĐ”ĐŽĐžĐœŃŃ‚ŃŒ ŃƒŃ‡Đ”Ń‚ĐœŃ‹Đ” запОсО, ĐżŃ€ĐŸŃŃ‚ĐŸ ĐżŃ€ĐŸĐžĐłĐœĐŸŃ€ĐžŃƒĐčтД ŃŃ‚ĐŸ ĐżĐžŃŃŒĐŒĐŸ. ĐŸĐŸŃĐ»Đ” ĐŸĐ±ŃŠĐ”ĐŽĐžĐœĐ”ĐœĐžŃ ŃƒŃ‡Đ”Ń‚ĐœŃ‹Ń… запОсДĐč Вы ĐŒĐŸĐ¶Đ”Ń‚Đ” ĐČĐŸĐčто ĐČ {1} чДрДз {0}.',
"identityProviderLinkBodyHtml":
'<p>ĐšŃ‚ĐŸ-Ń‚ĐŸ Ń…ĐŸŃ‡Đ”Ń‚ сĐČŃĐ·Đ°Ń‚ŃŒ ĐČашу ŃƒŃ‡Đ”Ń‚ĐœŃƒŃŽ Đ·Đ°ĐżĐžŃŃŒ <b>{1}</b> с <b>{0}</b> ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč Đ·Đ°ĐżĐžŃŃŒŃŽ ĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Ń‚Đ”Đ»Ń {2} . ЕслО ŃŃ‚ĐŸ былО Вы, ĐœĐ°Đ¶ĐŒĐžŃ‚Đ” ĐżĐŸ ŃĐ»Đ”ĐŽŃƒŃŽŃ‰Đ”Đč ссылĐșĐ”, Ń‡Ń‚ĐŸĐ±Ń‹ сĐČŃĐ·Đ°Ń‚ŃŒ ŃƒŃ‡Đ”Ń‚ĐœŃ‹Đ” запОсО</p><p><a href="{3}">{3}</a></p><p>Эта ссылĐșа ŃƒŃŃ‚Đ°Ń€Đ”Đ”Ń‚ чДрДз {4} ĐŒĐžĐœŃƒŃ‚.</p><p>ЕслО ŃŃ‚ĐŸ ĐœĐ” Ń…ĐŸŃ‚ĐžŃ‚Đ” ĐŸĐ±ŃŠĐ”ĐŽĐžĐœŃŃ‚ŃŒ ŃƒŃ‡Đ”Ń‚ĐœŃ‹Đ” запОсО, ĐżŃ€ĐŸŃŃ‚ĐŸ ĐżŃ€ĐŸĐžĐłĐœĐŸŃ€ĐžŃƒĐčтД ŃŃ‚ĐŸ ĐżĐžŃŃŒĐŒĐŸ. ĐŸĐŸŃĐ»Đ” ĐŸĐ±ŃŠĐ”ĐŽĐžĐœĐ”ĐœĐžŃ ŃƒŃ‡Đ”Ń‚ĐœŃ‹Ń… запОсДĐč Вы ĐŒĐŸĐ¶Đ”Ń‚Đ” ĐČĐŸĐčто ĐČ {1} чДрДз {0}.</p>',
"passwordResetSubject": "ĐĄĐ±Ń€ĐŸŃ ĐżĐ°Ń€ĐŸĐ»Ń",
"passwordResetBody":
"ĐšŃ‚ĐŸ-Ń‚ĐŸ Ń‚ĐŸĐ»ŃŒĐșĐŸ Ń‡Ń‚ĐŸ Đ·Đ°ĐżŃ€ĐŸŃĐžĐ» ĐžĐ·ĐŒĐ”ĐœĐ”ĐœĐžĐ” ĐżĐ°Ń€ĐŸĐ»Ń ĐŸŃ‚ Đ’Đ°ŃˆĐ”Đč ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč запОсО {2}. ЕслО ŃŃ‚ĐŸ былО Вы, ĐœĐ°Đ¶ĐŒĐžŃ‚Đ” ĐœĐ° ŃĐ»Đ”ĐŽŃƒŃŽŃ‰ŃƒŃŽ ссылĐșу, Ń‡Ń‚ĐŸĐ±Ń‹ ŃĐ±Ń€ĐŸŃĐžŃ‚ŃŒ Đ”ĐłĐŸ.\n\n{0}\n\nЭта ссылĐșа ŃƒŃŃ‚Đ°Ń€Đ”Đ”Ń‚ чДрДз {1} ĐŒĐžĐœŃƒŃ‚.\n\nЕслО Вы ĐœĐ” Ń…ĐŸŃ‚ĐžŃ‚Đ” сбрасыĐČать ĐżĐ°Ń€ĐŸĐ»ŃŒ, ĐżŃ€ĐŸŃŃ‚ĐŸ ĐżŃ€ĐŸĐžĐłĐœĐŸŃ€ĐžŃ€ŃƒĐčтД ŃŃ‚ĐŸ ĐżĐžŃŃŒĐŒĐŸ.",
"passwordResetBodyHtml":
'<p>ĐšŃ‚ĐŸ-Ń‚ĐŸ Ń‚ĐŸĐ»ŃŒĐșĐŸ Ń‡Ń‚ĐŸ Đ·Đ°ĐżŃ€ĐŸŃĐžĐ» ĐžĐ·ĐŒĐ”ĐœĐ”ĐœĐžĐ” ĐżĐ°Ń€ĐŸĐ»Ń ĐŸŃ‚ Đ’Đ°ŃˆĐ”Đč ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč запОсО {2}. ЕслО ŃŃ‚ĐŸ былО Вы, ĐœĐ°Đ¶ĐŒĐžŃ‚Đ” ĐœĐ° ŃĐ»Đ”ĐŽŃƒŃŽŃ‰ŃƒŃŽ ссылĐșу, Ń‡Ń‚ĐŸĐ±Ń‹ ŃĐ±Ń€ĐŸŃĐžŃ‚ŃŒ Đ”ĐłĐŸ.</p><p><a href="{0}">{0}</a></p><p>Эта ссылĐșа ŃƒŃŃ‚Đ°Ń€Đ”Đ”Ń‚ чДрДз {1} ĐŒĐžĐœŃƒŃ‚.</p><p>ЕслО Вы ĐœĐ” Ń…ĐŸŃ‚ĐžŃ‚Đ” сбрасыĐČать ĐżĐ°Ń€ĐŸĐ»ŃŒ, ĐżŃ€ĐŸŃŃ‚ĐŸ ĐżŃ€ĐŸĐžĐłĐœĐŸŃ€ĐžŃ€ŃƒĐčтД ŃŃ‚ĐŸ ĐżĐžŃŃŒĐŒĐŸ Đž ĐœĐžŃ‡Đ”ĐłĐŸ ĐœĐ” ĐžĐ·ĐŒĐ”ĐœĐžŃ‚ŃŃ.</p>',
"executeActionsSubject": "ĐžĐ±ĐœĐŸĐČĐ»Đ”ĐœĐžĐ” Đ’Đ°ŃˆĐ”Đč ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč запОсО",
"executeActionsBody":
"ĐĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€ ĐżŃ€ĐŸŃĐžŃ‚ Вас ĐŸĐ±ĐœĐŸĐČоть ĐŽĐ°ĐœĐœŃ‹Đ” Đ’Đ°ŃˆĐ”Đč ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč запОсО {2}. ĐĐ°Đ¶ĐŒĐžŃ‚Đ” ĐżĐŸ ŃĐ»Đ”ĐŽŃƒŃŽŃ‰Đ”Đč ссылĐșĐ” Ń‡Ń‚ĐŸĐ±Ń‹ ĐœĐ°Ń‡Đ°Ń‚ŃŒ ŃŃ‚ĐŸŃ‚ ĐżŃ€ĐŸŃ†Đ”ŃŃ.\n\n{0}\n\nЭта ссылĐșа ŃƒŃŃ‚Đ°Ń€Đ”Đ”Ń‚ чДрДз {1} ĐŒĐžĐœŃƒŃ‚.\n\nЕслО у ĐČас Đ”ŃŃ‚ŃŒ ĐżĐŸĐŽĐŸĐ·Ń€Đ”ĐœĐžŃ, Ń‡Ń‚ĐŸ Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€ ĐœĐ” ĐŒĐŸĐł ŃĐŽĐ”Đ»Đ°Ń‚ŃŒ таĐșĐŸĐč Đ·Đ°ĐżŃ€ĐŸŃ, ĐżŃ€ĐŸŃŃ‚ĐŸ ĐżŃ€ĐŸĐžĐłĐœĐŸŃ€ĐžŃ€ŃƒĐčтД ŃŃ‚ĐŸ ĐżĐžŃŃŒĐŒĐŸ.",
"executeActionsBodyHtml":
'<p>ĐĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€ ĐżŃ€ĐŸŃĐžŃ‚ Вас ĐŸĐ±ĐœĐŸĐČоть ĐŽĐ°ĐœĐœŃ‹Đ” Đ’Đ°ŃˆĐ”Đč ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč запОсО {2}. ĐĐ°Đ¶ĐŒĐžŃ‚Đ” ĐżĐŸ ŃĐ»Đ”ĐŽŃƒŃŽŃ‰Đ”Đč ссылĐșĐ” Ń‡Ń‚ĐŸĐ±Ń‹ ĐœĐ°Ń‡Đ°Ń‚ŃŒ ŃŃ‚ĐŸŃ‚ ĐżŃ€ĐŸŃ†Đ”ŃŃ.</p><p><a href="{0}">{0}</a></p><p>Эта ссылĐșа ŃƒŃŃ‚Đ°Ń€Đ”Đ”Ń‚ чДрДз {1} ĐŒĐžĐœŃƒŃ‚.</p><p>ЕслО у ĐČас Đ”ŃŃ‚ŃŒ ĐżĐŸĐŽĐŸĐ·Ń€Đ”ĐœĐžŃ, Ń‡Ń‚ĐŸ Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€ ĐœĐ” ĐŒĐŸĐł ŃĐŽĐ”Đ»Đ°Ń‚ŃŒ таĐșĐŸĐč Đ·Đ°ĐżŃ€ĐŸŃ, ĐżŃ€ĐŸŃŃ‚ĐŸ ĐżŃ€ĐŸĐžĐłĐœĐŸŃ€ĐžŃ€ŃƒĐčтД ŃŃ‚ĐŸ ĐżĐžŃŃŒĐŒĐŸ.</p>',
"eventLoginErrorSubject": "ĐžŃˆĐžĐ±Đșа ĐČŃ…ĐŸĐŽĐ°",
"eventLoginErrorBody":
"Была зафОĐșŃĐžŃ€ĐŸĐČĐ°ĐœĐ° ĐœĐ”ŃƒĐŽĐ°Ń‡ĐœĐ°Ń ĐżĐŸĐżŃ‹Ń‚Đșа ĐČŃ…ĐŸĐŽĐ° ĐČ Đ’Đ°ŃˆŃƒ ŃƒŃ‡Đ”Ń‚ĐœŃƒŃŽ Đ·Đ°ĐżĐžŃŃŒ {0} с {1}. ЕслО ŃŃ‚ĐŸ былО ĐœĐ” Вы, ĐżĐŸĐ¶Đ°Đ»ŃƒĐčста, сĐČŃĐ¶ĐžŃ‚Đ”ŃŃŒ с Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€ĐŸĐŒ.",
"eventLoginErrorBodyHtml":
"<p>Была зафОĐșŃĐžŃ€ĐŸĐČĐ°ĐœĐ° ĐœĐ”ŃƒĐŽĐ°Ń‡ĐœĐ°Ń ĐżĐŸĐżŃ‹Ń‚Đșа ĐČŃ…ĐŸĐŽĐ° ĐČ Đ’Đ°ŃˆŃƒ ŃƒŃ‡Đ”Ń‚ĐœŃƒŃŽ Đ·Đ°ĐżĐžŃŃŒ {0} с {1}. ЕслО ŃŃ‚ĐŸ былО ĐœĐ” Вы, ĐżĐŸĐ¶Đ°Đ»ŃƒĐčста, сĐČŃĐ¶ĐžŃ‚Đ”ŃŃŒ с Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€ĐŸĐŒ.</p>",
"eventRemoveTotpSubject": "ĐŁĐŽĐ°Đ»ĐžŃ‚ŃŒ OTP",
"eventRemoveTotpBody": "OTP был ŃƒĐŽĐ°Đ»Đ”Đœ Оз ĐČашДĐč ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč запОсО {0} c {1}. ЕслО ŃŃ‚ĐŸ былО ĐœĐ” Вы, ĐżĐŸĐ¶Đ°Đ»ŃƒĐčста, сĐČŃĐ¶ĐžŃ‚Đ”ŃŃŒ с Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€ĐŸĐŒ.",
"eventRemoveTotpBodyHtml":
"<p>OTP был ŃƒĐŽĐ°Đ»Đ”Đœ Оз ĐČашДĐč ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč запОсО {0} c {1}. ЕслО ŃŃ‚ĐŸ былО ĐœĐ” Вы, ĐżĐŸĐ¶Đ°Đ»ŃƒĐčста, сĐČŃĐ¶ĐžŃ‚Đ”ŃŃŒ с Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€ĐŸĐŒ.</p>",
"eventUpdatePasswordSubject": "ĐžĐ±ĐœĐŸĐČĐ»Đ”ĐœĐžĐ” ĐżĐ°Ń€ĐŸĐ»Ń",
"eventUpdatePasswordBody": "Ваш ĐżĐ°Ń€ĐŸĐ»ŃŒ был ĐžĐ·ĐŒĐ”ĐœĐ”Đœ ĐČ {0} с {1}. ЕслО ŃŃ‚ĐŸ былО ĐœĐ” Вы, ĐżĐŸĐ¶Đ°Đ»ŃƒĐčста, сĐČŃĐ¶ĐžŃ‚Đ”ŃŃŒ с Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€ĐŸĐŒ.",
"eventUpdatePasswordBodyHtml": "<p>Ваш ĐżĐ°Ń€ĐŸĐ»ŃŒ был ĐžĐ·ĐŒĐ”ĐœĐ”Đœ ĐČ {0} с {1}. ЕслО ŃŃ‚ĐŸ былО ĐœĐ” Вы, ĐżĐŸĐ¶Đ°Đ»ŃƒĐčста, сĐČŃĐ¶ĐžŃ‚Đ”ŃŃŒ с Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€ĐŸĐŒ.</p>",
"eventUpdateTotpSubject": "ĐžĐ±ĐœĐŸĐČĐ»Đ”ĐœĐžĐ” OTP",
"eventUpdateTotpBody": "OTP был ĐŸĐ±ĐœĐŸĐČĐ»Đ”Đœ ĐČ ĐČашДĐč ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč запОсО {0} с {1}. ЕслО ŃŃ‚ĐŸ былО ĐœĐ” Вы, ĐżĐŸĐ¶Đ°Đ»ŃƒĐčста, сĐČŃĐ¶ĐžŃ‚Đ”ŃŃŒ с Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€ĐŸĐŒ.",
"eventUpdateTotpBodyHtml":
"<p>OTP был ĐŸĐ±ĐœĐŸĐČĐ»Đ”Đœ ĐČ ĐČашДĐč ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč запОсО {0} с {1}. ЕслО ŃŃ‚ĐŸ былО ĐœĐ” Вы, ĐżĐŸĐ¶Đ°Đ»ŃƒĐčста, сĐČŃĐ¶ĐžŃ‚Đ”ŃŃŒ с Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€ĐŸĐŒ.</p>",
},
"sk": {
"emailVerificationSubject": "Overenie e-mailu",
"emailVerificationBody":
"Niekto vytvoril Ășčet {2} s touto e-mailovou adresou. Ak ste to vy, kliknite na niĆŸĆĄie uvedenĂœ odkaz a overte svoju e-mailovĂș adresu \n\n{0}\n\nTento odkaz uplynie do {1} minĂșt.\n\nAk ste tento Ășčet nevytvorili, ignorujte tĂșto sprĂĄvu.",
"emailVerificationBodyHtml":
'<p>Niekto vytvoril Ășčet {2} s touto e-mailovou adresou. Ak ste to vy, kliknite na niĆŸĆĄie uvedenĂœ odkaz na overenie svojej e-mailovej adresy.</p><p><a href="{0}"> Odkaz na overenie e-mailovej adresy </a></p><p>PlatnosĆ„ odkazu vyprĆĄĂ­ za {1} minĂșt.</p><p> Ak ste tento Ășčet nevytvorili, ignorujte tĂșto sprĂĄvu.</p>',
"emailTestSubject": "[KEYCLOAK] - Testovacia sprĂĄva SMTP",
"emailTestBody": "Toto je skĂșĆĄobnĂĄ sprĂĄva",
"emailTestBodyHtml": "<p>Toto je skĂșĆĄobnĂĄ sprĂĄva</p>",
"identityProviderLinkSubject": "Odkaz {0}",
"identityProviderLinkBody":
'Niekto chce prepojiĆ„ vĂĄĆĄ Ășčet "{1}" s Ășčtom {0}"pouĆŸĂ­vateÄŸa {2}. Ak ste to vy, kliknutĂ­m na odkaz niĆŸĆĄie prepojte Ășčty. \n\n{3}\n\nTento odkaz uplynie do {4} minĂșt.\n\nAk nechcete prepojiĆ„ Ășčet, jednoducho ignorujte tĂșto sprĂĄvu , Ak prepĂĄjate Ășčty, budete sa mĂŽcĆ„ prihlĂĄsiĆ„ do {1} aĆŸ {0}.',
"identityProviderLinkBodyHtml":
'<p>Niekto chce prepojiĆ„ vĂĄĆĄ Ășčet <b>{1}</b> s Ășčtom <b>{0}</b> pouĆŸĂ­vateÄŸa {2}. Ak ste to vy, kliknutĂ­m na odkaz niĆŸĆĄie prepojte Ășčty</p><p><a href="{3}">Odkaz na potvrdenie prepojenia Ășčtu </a></p><p> PlatnosĆ„ tohto odkazu vyprĆĄĂ­ v rĂĄmci {4} minĂșt.</p><p>Ak nechcete prepojiĆ„ Ășčet, ignorujte tĂșto sprĂĄvu. Ak prepojujete Ășčty, budete sa mĂŽcĆ„ prihlĂĄsiĆ„ do {1} aĆŸ {0}.</p>',
"passwordResetSubject": "Obnovenie hesla",
"passwordResetBody":
"Niekto poĆŸiadal, aby ste zmenili svoje poverenia Ășčtu {2}. Ak ste to vy, kliknite na odkaz uvedenĂœ niĆŸĆĄie, aby ste ich vynulovali.\n\n{0}\n\nTento odkaz a kĂłd uplynie do {1} minĂșt.\n\nAk nechcete obnoviĆ„ svoje poverenia , ignorujte tĂșto sprĂĄvu a nič sa nezmenĂ­.",
"passwordResetBodyHtml":
'<p>Niekto poĆŸiadal, aby ste zmenili svoje poverenia Ășčtu {2}. Ak ste to vy, kliknutĂ­m na odkaz niĆŸĆĄie ich resetujte.</p><p><a href="{0}">Odkaz na obnovenie poverenĂ­ </a></p><p>PlatnosĆ„ tohto odkazu vyprĆĄĂ­ v priebehu {1} minĂșt.</p><p>Ak nechcete obnoviĆ„ svoje poverenia, ignorujte tĂșto sprĂĄvu a nič sa nezmenĂ­.</p>',
"executeActionsSubject": "Aktualizujte svoj Ășčet",
"executeActionsBody":
"VĂĄĆĄ administrĂĄtor prĂĄve poĆŸiadal o aktualizĂĄciu vĂĄĆĄho Ășčtu {2} vykonanĂ­m nasledujĂșcich akciĂ­: {3}. KliknutĂ­m na odkaz uvedenĂœ niĆŸĆĄie spustĂ­te tento proces.\n\n{0}\n\nTento odkaz vyprĆĄĂ­ za {1} minĂșty.\n\nAk si nie ste vedomĂœ, ĆŸe vĂĄĆĄ adminstrĂĄtor o toto poĆŸiadal, ignorujte tĂșto sprĂĄvu a nič bude zmenenĂ©.",
"executeActionsBodyHtml":
'<p>VĂĄĆĄ sprĂĄvca prĂĄve poĆŸiadal o aktualizĂĄciu vĂĄĆĄho Ășčtu {2} vykonanĂ­m nasledujĂșcich akciĂ­: {3}. KliknutĂ­m na odkaz uvedenĂœ niĆŸĆĄie spustĂ­te tento proces.</p><p><a href="{0}"> Odkaz na aktualizĂĄciu Ășčtu </a></p><p> PlatnosĆ„ tohto odkazu uplynie do {1} minĂșty.</p><p> Ak si nie ste vedomĂ­, ĆŸe vĂĄĆĄ adminstrĂĄtor o toto poĆŸiadal, ignorujte tĂșto sprĂĄvu a nič sa nezmenĂ­.</p>',
"eventLoginErrorSubject": "Chyba prihlĂĄsenia",
"eventLoginErrorBody":
"Bol zistenĂœ neĂșspeĆĄnĂœ pokus o prihlĂĄsenie do vĂĄĆĄho Ășčtu v {0} z {1}. Ak ste to neboli vy, obrĂĄĆ„te sa na administrĂĄtora.",
"eventLoginErrorBodyHtml":
"<p>Bol zistenĂœ neĂșspeĆĄnĂœ pokus o prihlĂĄsenie vĂĄĆĄho Ășčtu na {0} z {1}. Ak ste to neboli vy, kontaktujte administrĂĄtora.</p>",
"eventRemoveTotpSubject": "OdstråniƄ TOTP",
"eventRemoveTotpBody": "OTP bol odstrĂĄnenĂœ z vĂĄĆĄho Ășčtu dƈa {0} z {1}. Ak ste to neboli vy, obrĂĄĆ„te sa na administrĂĄtora.",
"eventRemoveTotpBodyHtml": "<p>OTP bol odstrĂĄnenĂœ z vĂĄĆĄho Ășčtu dƈa {0} z {1}. Ak ste to neboli vy, kontaktujte administrĂĄtora.</p>",
"eventUpdatePasswordSubject": "AktualizovaƄ heslo",
"eventUpdatePasswordBody": "Vaƥe heslo bolo zmenené na {0} z {1}. Ak ste to neboli vy, obråƄte sa na administråtora.",
"eventUpdatePasswordBodyHtml": "<p>Vaƥe heslo bolo zmenené na {0} z {1}. Ak ste to neboli vy, kontaktujte administråtora.</p>",
"eventUpdateTotpSubject": "AktualizĂĄcia TOTP",
"eventUpdateTotpBody": "TOTP bol aktualizovanĂœ pre vĂĄĆĄ Ășčet na {0} z {1}. Ak ste to neboli vy, obrĂĄĆ„te sa na administrĂĄtora.",
"eventUpdateTotpBodyHtml": "<p>TOTP bol aktualizovanĂœ pre vĂĄĆĄ Ășčet dƈa {0} z {1}. Ak ste to neboli vy, kontaktujte administrĂĄtora.</p>",
"requiredAction.CONFIGURE_TOTP": "KonfigurĂĄcia OTP",
"requiredAction.terms_and_conditions": "Zmluvné podmienky",
"requiredAction.UPDATE_PASSWORD": "AktualizovaƄ heslo",
"requiredAction.UPDATE_PROFILE": "AktualizovaƄ profil",
"requiredAction.VERIFY_EMAIL": "OveriƄ e-mail",
"linkExpirationFormatter.timePeriodUnit.seconds": "sekundy",
"linkExpirationFormatter.timePeriodUnit.seconds.1": "sekunda",
"linkExpirationFormatter.timePeriodUnit.minutes": "minuty",
"linkExpirationFormatter.timePeriodUnit.minutes.1": "minĂșta",
"linkExpirationFormatter.timePeriodUnit.hours": "hodiny",
"linkExpirationFormatter.timePeriodUnit.hours.1": "hodina",
"linkExpirationFormatter.timePeriodUnit.days": "dni",
"linkExpirationFormatter.timePeriodUnit.days.1": "deƈ ",
},
"sv": {
"emailVerificationSubject": "Verifiera e-post",
"emailVerificationBody":
"NÄgon har skapat ett {2} konto med den hÀr e-postadressen. Om det var du, klicka dÄ pÄ lÀnken nedan för att verifiera din e-postadress\n\n{0}\n\nDen hÀr lÀnken kommer att upphöra inom {1} minuter.\n\nOm det inte var du som skapade det hÀr kontot, ignorera i sÄ fall det hÀr meddelandet.",
"emailVerificationBodyHtml":
'<p>NÄgon har skapat ett {2} konto med den hÀr e-postadressen. Om det var du, klicka dÄ pÄ lÀnken nedan för att verifiera din e-postadress</p><p><a href="{0}">{0}</a></p><p>Den hÀr lÀnken kommer att upphöra inom {1} minuter.</p><p>Om det inte var du som skapade det hÀr kontot, ignorera i sÄ fall det hÀr meddelandet.</p>',
"identityProviderLinkSubject": "LĂ€nk {0}",
"identityProviderLinkBody":
'NÄgon vill lÀnka ditt "{1}" konto med "{0}" kontot tillhörande anvÀndaren {2} . Om det var du, klicka dÄ pÄ lÀnken nedan för att lÀnka kontona\n\n{3}\n\nDen hÀr lÀnken kommer att upphöra inom {4} minuter.\n\nOm du inte vill lÀnka kontot, ignorera i sÄ fall det hÀr meddelandet. Om du lÀnkar kontona, sÄ kan du logga in till {1} genom {0}.',
"identityProviderLinkBodyHtml":
'<p>NÄgon vill lÀnka ditt <b>{1}</b> konto med <b>{0}</b> kontot tillhörande anvÀndaren {2} . Om det var du, klicka dÄ pÄ lÀnken nedan för att lÀnka kontona</p><p><a href="{3}">{3}</a></p><p>Den hÀr lÀnken kommer att upphöra inom {4} minuter.</p><p>Om du inte vill lÀnka kontot, ignorera i sÄ fall det hÀr meddelandet. Om du lÀnkar kontona, sÄ kan du logga in till {1} genom {0}.</p>',
"passwordResetSubject": "ÅterstĂ€ll lösenord",
"passwordResetBody":
"NÄgon har precis bett om att Àndra anvÀndaruppgifter för ditt konto {2}. Om det var du, klicka dÄ pÄ lÀnken nedan för att ÄterstÀlla dem.\n\n{0}\n\nDen hÀr lÀnken och koden kommer att upphöra inom {1} minuter.\n\nOm du inte vill ÄterstÀlla dina kontouppgifter, ignorera i sÄ fall det hÀr meddelandet sÄ kommer inget att Àndras.",
"passwordResetBodyHtml":
'<p>NÄgon har precis bett om att Àndra anvÀndaruppgifter för ditt konto {2}. Om det var du, klicka dÄ pÄ lÀnken nedan för att ÄterstÀlla dem.</p><p><a href="{0}">{0}</a></p><p>Den hÀr lÀnken och koden kommer att upphöra inom {1} minuter.</p><p>Om du inte vill ÄterstÀlla dina kontouppgifter, ignorera i sÄ fall det hÀr meddelandet sÄ kommer inget att Àndras.</p>',
"executeActionsSubject": "Uppdatera ditt konto",
"executeActionsBody":
"Din administratör har precis bett om att du skall uppdatera ditt {2} konto. Klicka pÄ lÀnken för att pÄbörja processen.\n\n{0}\n\nDen hÀr lÀnken kommer att upphöra inom {1} minuter.\n\nOm du Àr omedveten om att din administratör har bett om detta, ignorera i sÄ fall det hÀr meddelandet sÄ kommer inget att Àndras.",
"executeActionsBodyHtml":
'<p>Din administratör har precis bett om att du skall uppdatera ditt {2} konto. Klicka pÄ lÀnken för att pÄbörja processen.</p><p><a href="{0}">{0}</a></p><p>Den hÀr lÀnken kommer att upphöra inom {1} minuter.</p><p>Om du Àr omedveten om att din administratör har bett om detta, ignorera i sÄ fall det hÀr meddelandet sÄ kommer inget att Àndras.</p>',
"eventLoginErrorSubject": "Inloggningsfel",
"eventLoginErrorBody":
"Ett misslyckat inloggningsförsök har upptÀckts pÄ ditt konto pÄ {0} frÄn {1}. Om det inte var du, vÀnligen kontakta i sÄ fall en administratör.",
"eventLoginErrorBodyHtml":
"<p>Ett misslyckat inloggningsförsök har upptÀckts pÄ ditt konto den {0} frÄn {1}. Om det inte var du, vÀnligen kontakta i sÄ fall en administratör.</p>",
"eventRemoveTotpSubject": "Ta bort OTP",
"eventRemoveTotpBody": "OTP togs bort frÄn ditt konto den {0} frÄn {1}. Om det inte var du, vÀnligen kontakta i sÄ fall en administratör.",
"eventRemoveTotpBodyHtml":
"<p>OTP togs bort frÄn ditt konto den {0} frÄn {1}. Om det inte var du, vÀnligen kontakta i sÄ fall en administratör.</p>",
"eventUpdatePasswordSubject": "Uppdatera lösenord",
"eventUpdatePasswordBody": "Ditt lösenord Àndrades den {0} frÄn {1}. Om det inte var du, vÀnligen kontakta i sÄ fall en administratör.",
"eventUpdatePasswordBodyHtml":
"<p>Ditt lösenord Àndrades den {0} frÄn {1}. Om det inte var du, vÀnligen kontakta i sÄ fall en administratör.</p>",
"eventUpdateTotpSubject": "Uppdatera OTP",
"eventUpdateTotpBody": "OTP uppdaterades för ditt konto den {0} frÄn {1}. Om det inte var du, vÀnligen kontakta i sÄ fall en administratör.",
"eventUpdateTotpBodyHtml":
"<p>OTP uppdaterades för ditt konto den {0} frÄn {1}. Om det inte var du, vÀnligen kontakta i sÄ fall en administratör.</p>",
},
"tr": {
"emailVerificationSubject": "E-postayı doğrula",
"emailVerificationBody":
"Birisi bu e-posta adresiyle bir {2} hesap olußturdu. Bu sizseniz, e-posta adresinizi doğrulamak için aßağıdaki bağlantıya tıklayın\n\n{0}\n\nBu bağlantı {3} içinde sona erecek.\n\nBu hesabı olußturmadıysanız, sadece bu iletiyi yoksayınız.",
"emailVerificationBodyHtml":
'<p>Birisi bu e-posta adresiyle bir {2} hesap olußturdu. Bu sizseniz, e-posta adresinizi doğrulamak için aßağıdaki bağlantıyı tıklayın.</p><p><a href="{0}">E-posta adresi doğrulama adresi</a></p><p>Bu bağlantının sĂŒresi {3} içerisinde sona erecek.</p><p>Bu hesabı siz olußturmadıysanız, bu mesajı göz ardı edin.</p>',
"emailTestSubject": "[KEYCLOAK] - SMTP test mesajı",
"emailTestBody": "Bu bir test mesajı",
"emailTestBodyHtml": "<p>Bu bir test mesajı</p>",
"identityProviderLinkSubject": "Link {0}",
"identityProviderLinkBody":
'Birisi "{1}" hesabınızı "{0}" kullanıcı hesabı {2} ile bağlamak istiyor. Bu sizseniz, hesapları bağlamak için aßağıdaki bağlantıyı tıklayın:\n\n{3}\n\nBu bağlantı {5} içinde sona erecek.\n\nHesabınızı bağlamak istemiyorsanız bu mesajı göz ardı edin. Hesapları bağlarsanız, {1} ile {0} arasında oturum açabilirsiniz.',
"identityProviderLinkBodyHtml":
'<p>Birisi <b> {1} </ b> hesabınızı {2} kullanıcısı <b> {0} </ b> hesabına bağlamak istiyor. Bu sizseniz, bağlantı vermek için aßağıdaki bağlantıyı tıklayın</p><p><a href="{3}">Hesap bağlantısını onaylamak için bağlantı</a></p><p>Bu bağlantının sĂŒresi {5} içerisinde sona erecek.</p><p>Hesabı bağlamak istemiyorsanız, bu mesajı göz ardı edin. Hesapları bağlarsanız, {1} ile {0} arasında oturum açabilirsiniz.</p>',
"passwordResetSubject": "ƞifreyi sıfırla",
"passwordResetBody":
"Birisi, {2} hesabınızın kimlik bilgilerini değißtirmeyi istedi.Bu sizseniz, sıfırlamak için aßağıdaki bağlantıyı tıklayın.\n\n{0}\n\nBu bağlantı ve kod {3} içinde sona erecek.\n\nFakat bilgilerinizi sıfırlamak istemiyorsanız, Sadece bu mesajı görmezden gelin ve hiçbir ßey değißmeyecek.",
"passwordResetBodyHtml":
'<p>Birisi, {2} hesabınızın kimlik bilgilerini değißtirmeyi istedi. Sizseniz, sıfırlamak için aßağıdaki linke tıklayınız.</p><p><a href="{0}">Kimlik bilgilerini sıfırlamak için bağlantı</a></p><p>Bu bağlantının sĂŒresi {3} içerisinde sona erecek.</p><p>Kimlik bilgilerinizi sıfırlamak istemiyorsanız, bu mesajı göz ardı edin.</p>',
"executeActionsSubject": "Hesabınızı GĂŒncelleyin",
"executeActionsBody":
"Yöneticiniz aßağıdaki ißlemleri gerçekleßtirerek {2} hesabınızı gĂŒncelledi: {3}. Bu ißlemi baßlatmak için aßağıdaki linke tıklayın.\n\n{0}\n\nBu bağlantının sĂŒresi {4} içerisinde sona erecek.\n\nYöneticinizin bunu istediğinden habersizseniz, bu mesajı göz ardı edin ve hiçbir ßey değißmez.",
"executeActionsBodyHtml":
'<p>Yöneticiniz aßağıdaki ißlemleri gerçekleßtirerek {2} hesabınızı gĂŒncelledi: {3}. Bu ißlemi baßlatmak için aßağıdaki linke tıklayın.</p><p><a href="{0}">Hesap gĂŒncelleme bağlantısı</a></p><p>Bu bağlantının sĂŒresi {4} içerisinde sona erecek.</p><p>Yöneticinizin bunu istediğinden habersizseniz, bu mesajı göz ardı edin ve hiçbir ßey değißmez.</p>',
"eventLoginErrorSubject": "Giriß hatası",
"eventLoginErrorBody": "{1} 'den {0} tarihinde baßarısız bir giriß denemesi yapıldı. Bu siz değilseniz, lĂŒtfen yöneticiyle iletißime geçin.",
"eventLoginErrorBodyHtml":
"<p>{1} 'den {0} tarihinde baßarısız bir giriß denemesi yapıldı. Bu siz değilseniz, lĂŒtfen yöneticiyle iletißime geçin.</p>",
"eventRemoveTotpSubject": "OTP'yi kaldır",
"eventRemoveTotpBody": "OTP, {0} tarihinden {1} tarihinde hesabınızdan kaldırıldı. Bu siz değilseniz, lĂŒtfen yöneticiyle iletißime geçin.",
"eventRemoveTotpBodyHtml":
"<p>OTP, {0} tarihinden {1} tarihinde hesabınızdan kaldırıldı. Bu siz değilseniz, lĂŒtfen yöneticiyle iletißime geçin.</p>",
"eventUpdatePasswordSubject": "ƞifreyi gĂŒncelle",
"eventUpdatePasswordBody": "ƞifreniz {0} tarihinde {0} tarihinde değißtirildi. Bu siz değilseniz, lĂŒtfen yöneticiyle iletißime geçin.",
"eventUpdatePasswordBodyHtml":
"<p>ƞifreniz {0} tarihinde {0} tarihinde değißtirildi. Bu siz değilseniz, lĂŒtfen yöneticiyle iletißime geçin.</p>",
"eventUpdateTotpSubject": "OTP'yi GĂŒncelle",
"eventUpdateTotpBody": "OTP, {0} tarihinden {1} tarihinde hesabınız için gĂŒncellendi. Bu siz değilseniz, lĂŒtfen yöneticiyle iletißime geçin.",
"eventUpdateTotpBodyHtml":
"<p>OTP, {0} tarihinden {1} tarihinde hesabınız için gĂŒncellendi. Bu siz değilseniz, lĂŒtfen yöneticiyle iletißime geçin.</p>",
"requiredAction.CONFIGURE_TOTP": "OTP'yi yapılandır",
"requiredAction.terms_and_conditions": "ƞartlar ve KoƟullar",
"requiredAction.UPDATE_PASSWORD": "ƞifre GĂŒncelleme",
"requiredAction.UPDATE_PROFILE": "Profilleri gĂŒncelle",
"requiredAction.VERIFY_EMAIL": "E-mail doğrula",
"linkExpirationFormatter.timePeriodUnit.seconds": "saniye",
"linkExpirationFormatter.timePeriodUnit.seconds.1": "saniye",
"linkExpirationFormatter.timePeriodUnit.minutes": "dakika",
"linkExpirationFormatter.timePeriodUnit.minutes.1": "dakika",
"linkExpirationFormatter.timePeriodUnit.hours": "saat",
"linkExpirationFormatter.timePeriodUnit.hours.1": "saat",
"linkExpirationFormatter.timePeriodUnit.days": "gĂŒn",
"linkExpirationFormatter.timePeriodUnit.days.1": "gĂŒn",
"emailVerificationBodyCode": "LĂŒtfen aßağıdaki kodu girerek e-posta adresinizi doğrulayın.\n\n{0}\n\n.",
"emailVerificationBodyCodeHtml": "<p>LĂŒtfen aßağıdaki kodu girerek e-posta adresinizi doğrulayın.</p><p><b>{0}</b></p>",
},
"zh-CN": {
"emailVerificationSubject": "éȘŒèŻç””ć­é‚źä»¶",
"emailVerificationBody":
"ç”šæˆ·äœżç”šćœ“ć‰ç””ć­é‚źä»¶æłšć†Œ {2} èŽŠæˆ·ă€‚ćŠ‚æ˜ŻæœŹäșșæ“äœœïŒŒèŻ·ç‚čć‡»ä»„äž‹é“ŸæŽ„ćźŒæˆé‚źçź±éȘŒè݁\n\n{0}\n\nèż™äžȘé“ŸæŽ„äŒšćœš {1} ćˆ†é’ŸćŽèż‡æœŸ.\n\nćŠ‚æžœæ‚šæČĄæœ‰æłšć†Œç”šæˆ·ïŒŒèŻ·ćżœç•„èż™æĄæ¶ˆæŻă€‚",
"emailVerificationBodyHtml":
'<p>ç”šæˆ·äœżç”šćœ“ć‰ç””ć­é‚źä»¶æłšć†Œ {2} èŽŠæˆ·ă€‚ćŠ‚æ˜ŻæœŹäșșæ“äœœïŒŒèŻ·ç‚čć‡»ä»„äž‹é“ŸæŽ„ćźŒæˆé‚źçź±éȘŒè݁</p><p><a href="{0}">{0}</a></p><p>èż™äžȘé“ŸæŽ„äŒšćœš {1} ćˆ†é’ŸćŽèż‡æœŸ.</p><p>ćŠ‚æžœæ‚šæČĄæœ‰æłšć†Œç”šæˆ·ïŒŒèŻ·ćżœç•„èż™æĄæ¶ˆæŻă€‚</p>',
"identityProviderLinkSubject": "铟掄 {0}",
"identityProviderLinkBody":
'æœ‰ç”šæˆ·æƒłèŠć°†èŽŠæˆ· "{1}" 䞎甚户{2}的莊户"{0}" ćšé“ŸæŽ„ . ćŠ‚æžœæ˜ŻæœŹäșșæ“äœœïŒŒèŻ·ç‚čć‡»ä»„äž‹é“ŸæŽ„ćźŒæˆé“ŸæŽ„èŻ·æ±‚\n\n{3}\n\nèż™äžȘé“ŸæŽ„äŒšćœš {4} ćˆ†é’ŸćŽèż‡æœŸ.\n\nćŠ‚éžæœŹäșșæ“äœœïŒŒèŻ·ćżœç•„èż™æĄæ¶ˆæŻă€‚ćŠ‚æžœæ‚šé“ŸæŽ„èŽŠæˆ·ïŒŒæ‚šć°†ćŻä»„é€šèż‡{0}ç™»ćœ•èŽŠæˆ· {1}.',
"identityProviderLinkBodyHtml":
'<p>æœ‰ç”šæˆ·æƒłèŠć°†èŽŠæˆ· <b>{1}</b> 䞎甚户{2} 的莊户<b>{0}</b> ćšé“ŸæŽ„ . ćŠ‚æžœæ˜ŻæœŹäșșæ“äœœïŒŒèŻ·ç‚čć‡»ä»„äž‹é“ŸæŽ„ćźŒæˆé“ŸæŽ„èŻ·æ±‚</p><p><a href="{3}">{3}</a></p><p>èż™äžȘé“ŸæŽ„äŒšćœš {4} ćˆ†é’ŸćŽèż‡æœŸă€‚</p><p>ćŠ‚éžæœŹäșșæ“äœœïŒŒèŻ·ćżœç•„èż™æĄæ¶ˆæŻă€‚ćŠ‚æžœæ‚šé“ŸæŽ„èŽŠæˆ·ïŒŒæ‚šć°†ćŻä»„é€šèż‡{0}ç™»ćœ•èŽŠæˆ· {1}.</p>',
"passwordResetSubject": "é‡çœźćŻ†ç ",
"passwordResetBody":
"æœ‰ç”šæˆ·èŠæ±‚äżźæ”č莊户 {2} 的毆码.ćŠ‚æ˜ŻæœŹäșșæ“äœœïŒŒèŻ·ç‚čć‡»äž‹éąé“ŸæŽ„èż›èĄŒé‡çœź.\n\n{0}\n\nèż™äžȘé“ŸæŽ„äŒšćœš {1} ćˆ†é’ŸćŽèż‡æœŸ.\n\nćŠ‚æžœæ‚šäžæƒłé‡çœźæ‚šçš„ćŻ†ç ïŒŒèŻ·ćżœç•„èż™æĄæ¶ˆæŻïŒŒćŻ†ç äžäŒšæ”č揘。",
"passwordResetBodyHtml":
'<p>æœ‰ç”šæˆ·èŠæ±‚äżźæ”č莊户 {2} çš„ćŻ†ç ćŠ‚æ˜ŻæœŹäșșæ“äœœïŒŒèŻ·ç‚čć‡»äž‹éąé“ŸæŽ„èż›èĄŒé‡çœź.</p><p><a href="{0}">{0}</a></p><p>èż™äžȘé“ŸæŽ„äŒšćœš {1} ćˆ†é’ŸćŽèż‡æœŸ</p><p>ćŠ‚æžœæ‚šäžæƒłé‡çœźæ‚šçš„ćŻ†ç ïŒŒèŻ·ćżœç•„èż™æĄæ¶ˆæŻïŒŒćŻ†ç äžäŒšæ”č揘。</p>',
"executeActionsSubject": "曎新悚的莊户",
"executeActionsBody":
"æ‚šçš„çźĄç†ć‘˜èŠæ±‚æ‚šæ›Žæ–°èŽŠæˆ· {2}. ç‚čć‡»ä»„äž‹é“ŸæŽ„ćŒ€ć§‹æ›Žæ–°\n\n{0}\n\nèż™äžȘé“ŸæŽ„äŒšćœš {1} ćˆ†é’ŸćŽć€±æ•ˆ.\n\nćŠ‚æžœæ‚šäžçŸ„é“çźĄç†ć‘˜èŠæ±‚æ›Žæ–°èŽŠæˆ·äżĄæŻïŒŒèŻ·ćżœç•„èż™æĄæ¶ˆæŻă€‚èŽŠæˆ·äżĄæŻäžäŒšäżźæ”č。",
"executeActionsBodyHtml":
'<p>æ‚šçš„çźĄç†ć‘˜èŠæ±‚æ‚šæ›Žæ–°èŽŠæˆ·{2}. ç‚čć‡»ä»„äž‹é“ŸæŽ„ćŒ€ć§‹æ›Žæ–°.</p><p><a href="{0}">{0}</a></p><p>èż™äžȘé“ŸæŽ„äŒšćœš {1} ćˆ†é’ŸćŽć€±æ•ˆ.</p><p>ćŠ‚æžœæ‚šäžçŸ„é“çźĄç†ć‘˜èŠæ±‚æ›Žæ–°èŽŠæˆ·äżĄæŻïŒŒèŻ·ćżœç•„èż™æĄæ¶ˆæŻă€‚èŽŠæˆ·äżĄæŻäžäŒšäżźæ”č。</p>',
"eventLoginErrorSubject": "ç™»ćœ•é”™èŻŻ",
"eventLoginErrorBody": "朹{0} 由 {1}äœżç”šæ‚šçš„èŽŠæˆ·ç™»ćœ•ć€±èŽ„. ćŠ‚æžœèż™äžæ˜Żæ‚šæœŹäșșæ“äœœïŒŒèŻ·è”çł»çźĄç†ć‘˜.",
"eventLoginErrorBodyHtml": "<p>朹{0} 由 {1}äœżç”šæ‚šçš„èŽŠæˆ·ç™»ćœ•ć€±èŽ„. ćŠ‚æžœèż™äžæ˜Żæ‚šæœŹäșșæ“äœœïŒŒèŻ·è”çł»çźĄç†ć‘˜.</p>",
"eventRemoveTotpSubject": "ćˆ é™€ OTP",
"eventRemoveTotpBody": "OTP朹 {0} 由{1} ä»Žæ‚šçš„èŽŠæˆ·äž­ćˆ é™€.ćŠ‚æžœèż™äžæ˜Żæ‚šæœŹäșșæ“äœœïŒŒèŻ·è”çł»çźĄç†ć‘˜",
"eventRemoveTotpBodyHtml": "<p>OTP朹 {0} 由{1} ä»Žæ‚šçš„èŽŠæˆ·äž­ćˆ é™€.ćŠ‚æžœèż™äžæ˜Żæ‚šæœŹäșșæ“äœœïŒŒèŻ·è”çł»çźĄç†ć‘˜ă€‚</p>",
"eventUpdatePasswordSubject": "æ›Žæ–°ćŻ†ç ",
"eventUpdatePasswordBody": "æ‚šçš„ćŻ†ç ćœš{0} 由 {1}曎æ”č. ćŠ‚éžæœŹäșșæ“äœœïŒŒèŻ·è”çł»çźĄç†ć‘˜",
"eventUpdatePasswordBodyHtml": "<p>æ‚šçš„ćŻ†ç ćœš{0} 由 {1}曎æ”č. ćŠ‚éžæœŹäșșæ“äœœïŒŒèŻ·è”çł»çźĄç†ć‘˜</p>",
"eventUpdateTotpSubject": "曎新 OTP",
"eventUpdateTotpBody": "悚莊户的OTP é…çœźćœš{0} 由 {1}曎æ”č. ćŠ‚éžæœŹäșșæ“äœœïŒŒèŻ·è”çł»çźĄç†ć‘˜ă€‚",
"eventUpdateTotpBodyHtml": "<p>悚莊户的OTP é…çœźćœš{0} 由 {1}曎æ”č. ćŠ‚éžæœŹäșșæ“äœœïŒŒèŻ·è”çł»çźĄç†ć‘˜ă€‚</p>",
},
};
/* spell-checker: enable */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,278 +0,0 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
export const kcMessages = {
"ca": {
"invalidPasswordHistoryMessage": "Contrasenya incorrecta: no pot ser igual a cap de les Ășltimes {0} contrasenyes.",
"invalidPasswordMinDigitsMessage": "Contraseña incorrecta: debe contener al menos {0} caracteres numéricos.",
"invalidPasswordMinLengthMessage": "Contrasenya incorrecta: longitud mĂ­nima {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres minĂșscules.",
"invalidPasswordMinSpecialCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} carĂ cters especials.",
"invalidPasswordMinUpperCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres majĂșscules.",
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d'usuari.",
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l'expressiĂł regular.",
},
"de": {
"invalidPasswordMinLengthMessage": "UngĂŒltiges Passwort: muss mindestens {0} Zeichen beinhalten.",
"invalidPasswordMinLowerCaseCharsMessage": "UngĂŒltiges Passwort: muss mindestens {0} Kleinbuchstaben beinhalten.",
"invalidPasswordMinDigitsMessage": "UngĂŒltiges Passwort: muss mindestens {0} Ziffern beinhalten.",
"invalidPasswordMinUpperCaseCharsMessage": "UngĂŒltiges Passwort: muss mindestens {0} Großbuchstaben beinhalten.",
"invalidPasswordMinSpecialCharsMessage": "UngĂŒltiges Passwort: muss mindestens {0} Sonderzeichen beinhalten.",
"invalidPasswordNotUsernameMessage": "UngĂŒltiges Passwort: darf nicht identisch mit dem Benutzernamen sein.",
"invalidPasswordNotEmailMessage": "UngĂŒltiges Passwort: darf nicht identisch mit der E-Mail-Adresse sein.",
"invalidPasswordRegexPatternMessage": "UngĂŒltiges Passwort: stimmt nicht mit Regex-Muster ĂŒberein.",
"invalidPasswordHistoryMessage": "UngĂŒltiges Passwort: darf nicht identisch mit einem der letzten {0} Passwörter sein.",
"invalidPasswordBlacklistedMessage": "UngĂŒltiges Passwort: Passwort ist zu bekannt und auf der schwarzen Liste.",
"invalidPasswordGenericMessage": "UngĂŒltiges Passwort: neues Passwort erfĂŒllt die Passwort-Anforderungen nicht.",
},
"en": {
"invalidPasswordMinLengthMessage": "Invalid password: minimum length {0}.",
"invalidPasswordMaxLengthMessage": "Invalid password: maximum length {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Invalid password: must contain at least {0} lower case characters.",
"invalidPasswordMinDigitsMessage": "Invalid password: must contain at least {0} numerical digits.",
"invalidPasswordMinUpperCaseCharsMessage": "Invalid password: must contain at least {0} upper case characters.",
"invalidPasswordMinSpecialCharsMessage": "Invalid password: must contain at least {0} special characters.",
"invalidPasswordNotUsernameMessage": "Invalid password: must not be equal to the username.",
"invalidPasswordNotEmailMessage": "Invalid password: must not be equal to the email.",
"invalidPasswordRegexPatternMessage": "Invalid password: fails to match regex pattern(s).",
"invalidPasswordHistoryMessage": "Invalid password: must not be equal to any of last {0} passwords.",
"invalidPasswordBlacklistedMessage": "Invalid password: password is blacklisted.",
"invalidPasswordGenericMessage": "Invalid password: new password does not match password policies.",
"ldapErrorInvalidCustomFilter": 'Custom configured LDAP filter does not start with "(" or does not end with ")".',
"ldapErrorConnectionTimeoutNotNumber": "Connection Timeout must be a number",
"ldapErrorReadTimeoutNotNumber": "Read Timeout must be a number",
"ldapErrorMissingClientId": "Client ID needs to be provided in config when Realm Roles Mapping is not used.",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType":
"Not possible to preserve group inheritance and use UID membership type together.",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "Can not set write only when LDAP provider mode is not WRITABLE",
"ldapErrorCantWriteOnlyAndReadOnly": "Can not set write-only and read-only together",
"ldapErrorCantEnableStartTlsAndConnectionPooling": "Can not enable both StartTLS and connection pooling.",
"ldapErrorCantEnableUnsyncedAndImportOff": "Can not disable Importing users when LDAP provider mode is UNSYNCED",
"ldapErrorMissingGroupsPathGroup": "Groups path group does not exist - please create the group on specified path first",
"clientRedirectURIsFragmentError": "Redirect URIs must not contain an URI fragment",
"clientRootURLFragmentError": "Root URL must not contain an URL fragment",
"clientRootURLIllegalSchemeError": "Root URL uses an illegal scheme",
"clientBaseURLIllegalSchemeError": "Base URL uses an illegal scheme",
"backchannelLogoutUrlIllegalSchemeError": "Backchannel logout URL uses an illegal scheme",
"clientRedirectURIsIllegalSchemeError": "A redirect URI uses an illegal scheme",
"clientBaseURLInvalid": "Base URL is not a valid URL",
"clientRootURLInvalid": "Root URL is not a valid URL",
"clientRedirectURIsInvalid": "A redirect URI is not a valid URI",
"backchannelLogoutUrlIsInvalid": "Backchannel logout URL is not a valid URL",
"pairwiseMalformedClientRedirectURI": "Client contained an invalid redirect URI.",
"pairwiseClientRedirectURIsMissingHost": "Client redirect URIs must contain a valid host component.",
"pairwiseClientRedirectURIsMultipleHosts":
"Without a configured Sector Identifier URI, client redirect URIs must not contain multiple host components.",
"pairwiseMalformedSectorIdentifierURI": "Malformed Sector Identifier URI.",
"pairwiseFailedToGetRedirectURIs": "Failed to get redirect URIs from the Sector Identifier URI.",
"pairwiseRedirectURIsMismatch": "Client redirect URIs does not match redirect URIs fetched from the Sector Identifier URI.",
"error-invalid-value": "Invalid value.",
"error-invalid-blank": "Please specify value.",
"error-empty": "Please specify value.",
"error-invalid-length": "Attribute {0} must have a length between {1} and {2}.",
"error-invalid-length-too-short": "Attribute {0} must have minimal length of {1}.",
"error-invalid-length-too-long": "Attribute {0} must have maximal length of {2}.",
"error-invalid-email": "Invalid email address.",
"error-invalid-number": "Invalid number.",
"error-number-out-of-range": "Attribute {0} must be a number between {1} and {2}.",
"error-number-out-of-range-too-small": "Attribute {0} must have minimal value of {1}.",
"error-number-out-of-range-too-big": "Attribute {0} must have maximal value of {2}.",
"error-pattern-no-match": "Invalid value.",
"error-invalid-uri": "Invalid URL.",
"error-invalid-uri-scheme": "Invalid URL scheme.",
"error-invalid-uri-fragment": "Invalid URL fragment.",
"error-user-attribute-required": "Please specify attribute {0}.",
"error-invalid-date": "Attribute {0} is invalid date.",
"error-user-attribute-read-only": "Attribute {0} is read only.",
"error-username-invalid-character": "{0} contains invalid character.",
"error-person-name-invalid-character": "{0} contains invalid character.",
},
"es": {
"invalidPasswordMinLengthMessage": "Contraseña incorrecta: longitud mínima {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Contraseña incorrecta: debe contener al menos {0} letras minĂșsculas.",
"invalidPasswordMinDigitsMessage": "Contraseña incorrecta: debe contener al menos {0} caracteres numéricos.",
"invalidPasswordMinUpperCaseCharsMessage": "Contraseña incorrecta: debe contener al menos {0} letras mayĂșsculas.",
"invalidPasswordMinSpecialCharsMessage": "Contraseña incorrecta: debe contener al menos {0} caracteres especiales.",
"invalidPasswordNotUsernameMessage": "Contraseña incorrecta: no puede ser igual al nombre de usuario.",
"invalidPasswordRegexPatternMessage": "Contraseña incorrecta: no cumple la expresión regular.",
"invalidPasswordHistoryMessage": "Contraseña incorrecta: no puede ser igual a ninguna de las Ășltimas {0} contraseñas.",
},
"fr": {
"invalidPasswordMinLengthMessage": "Mot de passe invalide : longueur minimale requise de {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Mot de passe invalide : doit contenir au moins {0} lettre(s) en minuscule.",
"invalidPasswordMinDigitsMessage": "Mot de passe invalide : doit contenir au moins {0} chiffre(s).",
"invalidPasswordMinUpperCaseCharsMessage": "Mot de passe invalide : doit contenir au moins {0} lettre(s) en majuscule.",
"invalidPasswordMinSpecialCharsMessage": "Mot de passe invalide : doit contenir au moins {0} caractÚre(s) spéciaux.",
"invalidPasswordNotUsernameMessage": "Mot de passe invalide : ne doit pas ĂȘtre identique au nom d'utilisateur.",
"invalidPasswordRegexPatternMessage": "Mot de passe invalide : ne valide pas l'expression rationnelle.",
"invalidPasswordHistoryMessage": "Mot de passe invalide : ne doit pas ĂȘtre Ă©gal aux {0} derniers mot de passe.",
},
"it": {},
"ja": {
"invalidPasswordMinLengthMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: æœ€ć°{0}ăźé•·ă•ăŒćż…èŠă§ă™ă€‚",
"invalidPasswordMinLowerCaseCharsMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: 民ăȘくべも{0}æ–‡ć­—ăźć°æ–‡ć­—ă‚’ć«ă‚€ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"invalidPasswordMinDigitsMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: 民ăȘくべも{0}æ–‡ć­—ăźæ•°ć­—ă‚’ć«ă‚€ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"invalidPasswordMinUpperCaseCharsMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: 民ăȘくべも{0}æ–‡ć­—ăźć€§æ–‡ć­—ă‚’ć«ă‚€ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"invalidPasswordMinSpecialCharsMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: 民ăȘくべも{0}æ–‡ć­—ăźç‰čæźŠæ–‡ć­—ă‚’ć«ă‚€ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"invalidPasswordNotUsernameMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: ăƒŠăƒŒă‚¶ăƒŒćăšćŒă˜ăƒ‘ă‚čăƒŻăƒŒăƒ‰ăŻçŠæ­ąă•ă‚ŒăŠă„ăŸă™ă€‚",
"invalidPasswordRegexPatternMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: æ­ŁèŠèĄšçŸăƒ‘ă‚żăƒŒăƒłăšäž€è‡Žă—ăŸă›ă‚“ă€‚",
"invalidPasswordHistoryMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: æœ€èż‘ăź{0}パă‚čăƒŻăƒŒăƒ‰ăźă„ăšă‚Œă‹ăšćŒă˜ăƒ‘ă‚čăƒŻăƒŒăƒ‰ăŻçŠæ­ąă•ă‚ŒăŠă„ăŸă™ă€‚",
"invalidPasswordBlacklistedMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: パă‚čăƒŻăƒŒăƒ‰ăŒăƒ–ăƒ©ăƒƒă‚ŻăƒȘă‚čăƒˆă«ć«ăŸă‚ŒăŠă„ăŸă™ă€‚",
"invalidPasswordGenericMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: æ–°ă—ă„ăƒ‘ă‚čăƒŻăƒŒăƒ‰ăŻăƒ‘ă‚čăƒŻăƒŒăƒ‰ăƒ»ăƒăƒȘă‚·ăƒŒăšäž€è‡Žă—ăŸă›ă‚“ă€‚",
"ldapErrorInvalidCustomFilter": "LDAPăƒ•ă‚Łăƒ«ă‚żăƒŒăźă‚«ă‚čă‚żăƒ èš­ćźšăŒă€ă€Œ(ă€ă‹ă‚‰é–‹ć§‹ăŸăŸăŻă€Œ)ă€ă§ç”‚äș†ăšăȘăŁăŠă„ăŸă›ă‚“ă€‚",
"ldapErrorConnectionTimeoutNotNumber": "æŽ„ç¶šă‚żă‚€ăƒ ă‚ąă‚ŠăƒˆăŻæ•°ć­—ă§ăȘければăȘă‚ŠăŸă›ă‚“",
"ldapErrorReadTimeoutNotNumber": "èȘ­ăżć–ă‚Šă‚żă‚€ăƒ ă‚ąă‚ŠăƒˆăŻæ•°ć­—ă§ăȘければăȘă‚ŠăŸă›ă‚“",
"ldapErrorMissingClientId": "ăƒŹăƒ«ăƒ ăƒ­ăƒŒăƒ«ăƒ»ăƒžăƒƒăƒ”ăƒłă‚°ă‚’äœżç”šă—ăȘă„ć ŽćˆăŻă€ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆIDăŻèš­ćźšć†…ă§æäŸ›ă•ă‚Œă‚‹ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType":
"ă‚°ăƒ«ăƒŒăƒ—ăźç¶™æ‰żă‚’ç¶­æŒă™ă‚‹ă“ăšăšă€UIDăƒĄăƒłăƒăƒŒă‚·ăƒƒăƒ—ăƒ»ă‚żă‚€ăƒ—ă‚’äœżç”šă™ă‚‹ă“ăšăŻćŒæ™‚ă«ă§ăăŸă›ă‚“ă€‚",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "LDAPăƒ—ăƒ­ăƒă‚€ăƒ€ăƒŒăƒ»ăƒąăƒŒăƒ‰ăŒWRITABLEではăȘい栮搈は、write onlyă‚’èš­ćźšă™ă‚‹ă“ăšăŻă§ăăŸă›ă‚“ă€‚",
"ldapErrorCantWriteOnlyAndReadOnly": "write-onlyずread-onlyă‚’äž€ç·’ă«èš­ćźšă™ă‚‹ă“ăšăŻă§ăăŸă›ă‚“ă€‚",
"ldapErrorCantEnableStartTlsAndConnectionPooling": "StartTLSăšæŽ„ç¶šăƒ—ăƒŒăƒȘングぼ価æ–čă‚’æœ‰ćŠčă«ă§ăăŸă›ă‚“ă€‚",
"clientRedirectURIsFragmentError": "ăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIにURIăƒ•ăƒ©ă‚°ăƒĄăƒłăƒˆă‚’ć«ă‚ă‚‹ă“ăšăŻă§ăăŸă›ă‚“ă€‚",
"clientRootURLFragmentError": "ăƒ«ăƒŒăƒˆURLにURLăƒ•ăƒ©ă‚°ăƒĄăƒłăƒˆă‚’ć«ă‚ă‚‹ă“ăšăŻă§ăăŸă›ă‚“ă€‚",
"pairwiseMalformedClientRedirectURI": "ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆă«ç„ĄćŠčăȘăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIăŒć«ăŸă‚ŒăŠă„ăŸă—ăŸă€‚",
"pairwiseClientRedirectURIsMissingHost": "ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆăźăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIă«ăŻæœ‰ćŠčăȘホă‚čăƒˆăƒ»ă‚łăƒłăƒăƒŒăƒăƒłăƒˆăŒć«ăŸă‚ŒăŠă„ă‚‹ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"pairwiseClientRedirectURIsMultipleHosts":
"èš­ćźšă•ă‚ŒăŸă‚»ăƒŹă‚Żă‚żăƒŒè­˜ćˆ„ć­URIがăȘă„ć ŽćˆăŻă€ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆăźăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIăŻè€‡æ•°ăźăƒ›ă‚čăƒˆăƒ»ă‚łăƒłăƒăƒŒăƒăƒłăƒˆă‚’ć«ă‚€ă“ăšăŻă§ăăŸă›ă‚“ă€‚",
"pairwiseMalformedSectorIdentifierURI": "äžæ­ŁăȘă‚»ăƒŹă‚Żă‚żăƒŒè­˜ćˆ„ć­URIです。",
"pairwiseFailedToGetRedirectURIs": "ă‚»ă‚Żă‚żăƒŒè­˜ćˆ„ć­URIからăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIă‚’ć–ćŸ—ă§ăăŸă›ă‚“ă§ă—ăŸă€‚",
"pairwiseRedirectURIsMismatch": "ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆăźăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIăŻă€ă‚»ă‚Żă‚żăƒŒè­˜ćˆ„ć­URIからフェッチされたăƒȘăƒ€ă‚€ăƒŹă‚ŻăƒˆURIăšäž€è‡Žă—ăŸă›ă‚“ă€‚",
},
"lt": {
"invalidPasswordMinLengthMessage": "Per trumpas slaptaĆŸodis: maĆŸiausias ilgis {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Neteisingas slaptaĆŸodis: privaloma ÄŻvesti {0} maĆŸÄ…ją raidę.",
"invalidPasswordMinDigitsMessage": "Neteisingas slaptaĆŸodis: privaloma ÄŻvesti {0} skaitmenÄŻ.",
"invalidPasswordMinUpperCaseCharsMessage": "Neteisingas slaptaĆŸodis: privaloma ÄŻvesti {0} didĆŸiąją raidę.",
"invalidPasswordMinSpecialCharsMessage": "Neteisingas slaptaĆŸodis: privaloma ÄŻvesti {0} specialĆł simbolÄŻ.",
"invalidPasswordNotUsernameMessage": "Neteisingas slaptaĆŸodis: slaptaĆŸodis negali sutapti su naudotojo vardu.",
"invalidPasswordRegexPatternMessage": "Neteisingas slaptaĆŸodis: slaptaĆŸodis netenkina regex taisyklės(iĆł).",
"invalidPasswordHistoryMessage": "Neteisingas slaptaĆŸodis: slaptaĆŸodis negali sutapti su prieĆĄ tai buvusiais {0} slaptaĆŸodĆŸiais.",
"ldapErrorInvalidCustomFilter": 'Sukonfigƫruotas LDAP filtras neprasideda "(" ir nesibaigia ")" simboliais.',
"ldapErrorMissingClientId": "Privaloma nurodyti kliento ID kai srities roliƳ susiejimas nėra nenaudojamas.",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType": "GrupiĆł paveldėjimo ir UID narystės tipas kartu negali bĆ«ti naudojami.",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "Negalima nustatyti raĆĄymo rÄ—ĆŸimo kuomet LDAP teikėjo rÄ—ĆŸimas ne WRITABLE",
"ldapErrorCantWriteOnlyAndReadOnly": "Negalima nustatyti tik raĆĄyti ir tik skaityti kartu",
"clientRedirectURIsFragmentError": "Nurodykite URI fragmentą, kurio negali bĆ«ti peradresuojamuose URI adresuose",
"clientRootURLFragmentError": "Nurodykite URL fragmentą, kurio negali bĆ«ti ĆĄakniniame URL adrese",
"pairwiseMalformedClientRedirectURI": "Klientas pateikė neteisingą nukreipimo nuorodą.",
"pairwiseClientRedirectURIsMissingHost": "Kliento nukreipimo nuorodos privalo bƫti nurodytos su serverio vardo komponentu.",
"pairwiseClientRedirectURIsMultipleHosts":
"Kuomet nesukonfigĆ«ruotas sektoriaus identifikatoriaus URL, kliento nukreipimo nuorodos privalo talpinti ne daugiau kaip vieną skirtingą serverio vardo komponentą.",
"pairwiseMalformedSectorIdentifierURI": "Neteisinga sektoriaus identifikatoriaus URI.",
"pairwiseFailedToGetRedirectURIs": "Nepavyko gauti nukreipimo nuorodĆł iĆĄ sektoriaus identifikatoriaus URI.",
"pairwiseRedirectURIsMismatch": "Kliento nukreipimo nuoroda neatitinka nukreipimo nuorodĆł iĆĄ sektoriaus identifikatoriaus URI.",
},
"nl": {
"invalidPasswordMinLengthMessage": "Ongeldig wachtwoord: de minimale lengte is {0} karakters.",
"invalidPasswordMinLowerCaseCharsMessage": "Ongeldig wachtwoord: het moet minstens {0} kleine letters bevatten.",
"invalidPasswordMinDigitsMessage": "Ongeldig wachtwoord: het moet minstens {0} getallen bevatten.",
"invalidPasswordMinUpperCaseCharsMessage": "Ongeldig wachtwoord: het moet minstens {0} hoofdletters bevatten.",
"invalidPasswordMinSpecialCharsMessage": "Ongeldig wachtwoord: het moet minstens {0} speciale karakters bevatten.",
"invalidPasswordNotUsernameMessage": "Ongeldig wachtwoord: het mag niet overeenkomen met de gebruikersnaam.",
"invalidPasswordRegexPatternMessage": "Ongeldig wachtwoord: het voldoet niet aan het door de beheerder ingestelde patroon.",
"invalidPasswordHistoryMessage": "Ongeldig wachtwoord: het mag niet overeen komen met een van de laatste {0} wachtwoorden.",
"invalidPasswordGenericMessage": "Ongeldig wachtwoord: het nieuwe wachtwoord voldoet niet aan het wachtwoordbeleid.",
"ldapErrorInvalidCustomFilter": 'LDAP filter met aangepaste configuratie start niet met "(" of eindigt niet met ")".',
"ldapErrorConnectionTimeoutNotNumber": "Verbindingstimeout moet een getal zijn",
"ldapErrorReadTimeoutNotNumber": "Lees-timeout moet een getal zijn",
"ldapErrorMissingClientId": "Client ID moet ingesteld zijn als Realm Roles Mapping niet gebruikt wordt.",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType": "Kan groepsovererving niet behouden bij UID-lidmaatschapstype.",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "Alleen-schrijven niet mogelijk als LDAP provider mode niet WRITABLE is",
"ldapErrorCantWriteOnlyAndReadOnly": "Alleen-schrijven en alleen-lezen mogen niet tegelijk ingesteld zijn",
"clientRedirectURIsFragmentError": "Redirect URIs mogen geen URI fragment bevatten",
"clientRootURLFragmentError": "Root URL mag geen URL fragment bevatten",
"pairwiseMalformedClientRedirectURI": "Client heeft een ongeldige redirect URI.",
"pairwiseClientRedirectURIsMissingHost": "Client redirect URIs moeten een geldige host-component bevatten.",
"pairwiseClientRedirectURIsMultipleHosts":
"Zonder een geconfigureerde Sector Identifier URI mogen client redirect URIs niet meerdere host componenten hebben.",
"pairwiseMalformedSectorIdentifierURI": "Onjuist notatie in Sector Identifier URI.",
"pairwiseFailedToGetRedirectURIs": "Kon geen redirect URIs verkrijgen van de Sector Identifier URI.",
"pairwiseRedirectURIsMismatch": "Client redirect URIs komen niet overeen met redict URIs ontvangen van de Sector Identifier URI.",
},
"no": {
"invalidPasswordMinLengthMessage": "Ugyldig passord: minimum lengde {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Ugyldig passord: mÄ inneholde minst {0} smÄ bokstaver.",
"invalidPasswordMinDigitsMessage": "Ugyldig passord: mÄ inneholde minst {0} sifre.",
"invalidPasswordMinUpperCaseCharsMessage": "Ugyldig passord: mÄ inneholde minst {0} store bokstaver.",
"invalidPasswordMinSpecialCharsMessage": "Ugyldig passord: mÄ inneholde minst {0} spesialtegn.",
"invalidPasswordNotUsernameMessage": "Ugyldig passord: kan ikke vĂŠre likt brukernavn.",
"invalidPasswordRegexPatternMessage": "Ugyldig passord: tilfredsstiller ikke kravene for passord-mĂžnster.",
"invalidPasswordHistoryMessage": "Ugyldig passord: kan ikke vÊre likt noen av de {0} foregÄende passordene.",
"ldapErrorInvalidCustomFilter": 'Tilpasset konfigurasjon av LDAP-filter starter ikke med "(" eller slutter ikke med ")".',
"ldapErrorMissingClientId": "KlientID mÄ vÊre tilgjengelig i config nÄr sikkerhetsdomenerollemapping ikke brukes.",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType": "Ikke mulig Ă„ bevare gruppearv og samtidig bruke UID medlemskapstype.",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "Kan ikke sette write-only nÄr LDAP leverandÞr-modus ikke er WRITABLE",
"ldapErrorCantWriteOnlyAndReadOnly": "Kan ikke sette bÄde write-only og read-only",
},
"pl": {},
"pt-BR": {
"invalidPasswordMinLengthMessage": "Senha invĂĄlida: deve conter ao menos {0} caracteres.",
"invalidPasswordMinLowerCaseCharsMessage": "Senha invĂĄlida: deve conter ao menos {0} caracteres minĂșsculos.",
"invalidPasswordMinDigitsMessage": "Senha invålida: deve conter ao menos {0} digitos numéricos.",
"invalidPasswordMinUpperCaseCharsMessage": "Senha invĂĄlida: deve conter ao menos {0} caracteres maiĂșsculos.",
"invalidPasswordMinSpecialCharsMessage": "Senha invĂĄlida: deve conter ao menos {0} caracteres especiais.",
"invalidPasswordNotUsernameMessage": "Senha invĂĄlida: nĂŁo deve ser igual ao nome de usuĂĄrio.",
"invalidPasswordRegexPatternMessage": "Senha invålida: falha ao passar por padrÔes.",
"invalidPasswordHistoryMessage": "Senha invĂĄlida: nĂŁo deve ser igual Ă s Ășltimas {0} senhas.",
"ldapErrorInvalidCustomFilter": 'Filtro LDAP nĂŁo inicia com "(" ou nĂŁo termina com ")".',
"ldapErrorMissingClientId": "ID do cliente precisa ser definido na configuração quando mapeamentos de Roles do Realm não é utilizado.",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType":
"Não é possível preservar herança de grupos e usar tipo de associação de UID ao mesmo tempo.",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "NĂŁo Ă© possĂ­vel definir modo de somente escrita quando o provedor LDAP nĂŁo suporta escrita",
"ldapErrorCantWriteOnlyAndReadOnly": "NĂŁo Ă© possĂ­vel definir somente escrita e somente leitura ao mesmo tempo",
"clientRedirectURIsFragmentError": "URIs de redirecionamento nĂŁo podem conter fragmentos",
"clientRootURLFragmentError": "URL raiz nĂŁo pode conter fragmentos",
},
"ru": {
"invalidPasswordMinLengthMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐŽĐ»ĐžĐœĐ° ĐżĐ°Ń€ĐŸĐ»Ń ĐŽĐŸĐ»Đ¶ĐœĐ° Đ±Ń‹Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} ŃĐžĐŒĐČĐŸĐ»ĐŸĐČ(а).",
"invalidPasswordMinDigitsMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} цофр(ы).",
"invalidPasswordMinLowerCaseCharsMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} ŃĐžĐŒĐČĐŸĐ»ĐŸĐČ(а) ĐČ ĐœĐžĐ¶ĐœĐ”ĐŒ рДгОстрД.",
"invalidPasswordMinUpperCaseCharsMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} ŃĐžĐŒĐČĐŸĐ»ĐŸĐČ(а) ĐČ ĐČĐ”Ń€Ń…ĐœĐ”ĐŒ рДгОстрД.",
"invalidPasswordMinSpecialCharsMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} ŃĐżĐ”Ń†ŃĐžĐŒĐČĐŸĐ»ĐŸĐČ(а).",
"invalidPasswordNotUsernameMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐœĐ” ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐČпаЮать с ĐžĐŒĐ”ĐœĐ”ĐŒ ĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Ń‚Đ”Đ»Ń.",
"invalidPasswordRegexPatternMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐœĐ” ĐżŃ€ĐŸŃˆĐ”Đ» ĐżŃ€ĐŸĐČДрĐșу ĐżĐŸ Ń€Đ”ĐłŃƒĐ»ŃŃ€ĐœĐŸĐŒŃƒ ĐČŃ‹Ń€Đ°Đ¶Đ”ĐœĐžŃŽ.",
"invalidPasswordHistoryMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐœĐ” ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐČпаЮать с ĐżĐŸŃĐ»Đ”ĐŽĐœĐžĐŒ(Đž) {0} ĐżĐ°Ń€ĐŸĐ»Đ”ĐŒ(ŃĐŒĐž).",
"invalidPasswordGenericMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐœĐŸĐČыĐč ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐœĐ” ŃĐŸĐŸŃ‚ĐČДтстĐČŃƒĐ”Ń‚ праĐČĐžĐ»Đ°ĐŒ ĐżĐ°Ń€ĐŸĐ»Ń.",
"ldapErrorInvalidCustomFilter": 'ĐĄĐșĐŸĐœŃ„ĐžĐłŃƒŃ€ĐžŃ€ĐŸĐČĐ°ĐœĐœŃ‹Đč ĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Ń‚Đ”Đ»Đ”ĐŒ Ń„ĐžĐ»ŃŒŃ‚Ń€ LDAP ĐœĐ” ĐŽĐŸĐ»Đ¶Đ”Đœ ĐœĐ°Ń‡ĐžĐœĐ°Ń‚ŃŒŃŃ с "(" ОлО заĐșĐ°ĐœŃ‡ĐžĐČаться ĐœĐ° ")".',
"ldapErrorMissingClientId": "Client ID ĐŽĐŸĐ»Đ¶Đ”Đœ Đ±Ń‹Ń‚ŃŒ ĐœĐ°ŃŃ‚Ń€ĐŸĐ”Đœ ĐČ ĐșĐŸĐœŃ„ĐžĐłŃƒŃ€Đ°Ń†ĐžĐž, ДслО ĐœĐ” ĐžŃĐżĐŸĐ»ŃŒĐ·ŃƒĐ”Ń‚ŃŃ ŃĐŸĐżĐŸŃŃ‚Đ°ĐČĐ»Đ”ĐœĐžĐ” Ń€ĐŸĐ»Đ”Đč ĐČ realm.",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType": "ĐĐ” ŃƒĐŽĐ°Đ»ĐŸŃŃŒ ŃƒĐœĐ°ŃĐ»Đ”ĐŽĐŸĐČать группу Đž ĐžŃĐżĐŸĐ»ŃŒĐ·ĐŸĐČать Ń‡Đ»Đ”ĐœŃŃ‚ĐČĐŸ UID топа ĐČĐŒĐ”ŃŃ‚Đ”.",
"ldapErrorCantWriteOnlyForReadOnlyLdap": 'ĐĐ”ĐČĐŸĐ·ĐŒĐŸĐ¶ĐœĐŸ ŃƒŃŃ‚Đ°ĐœĐŸĐČоть Ń€Đ”Đ¶ĐžĐŒ "Ń‚ĐŸĐ»ŃŒĐșĐŸ ĐœĐ° Đ·Đ°ĐżĐžŃŃŒ", ĐșĐŸĐłĐŽĐ° LDAP ĐżŃ€ĐŸĐČаĐčЎДр ĐœĐ” ĐČ Ń€Đ”Đ¶ĐžĐŒĐ” WRITABLE',
"ldapErrorCantWriteOnlyAndReadOnly": 'ĐĐ”ĐČĐŸĐ·ĐŒĐŸĐ¶ĐœĐŸ ĐŸĐŽĐœĐŸĐČŃ€Đ”ĐŒĐ”ĐœĐœĐŸ ŃƒŃŃ‚Đ°ĐœĐŸĐČоть Ń€Đ”Đ¶ĐžĐŒŃ‹ "Ń‚ĐŸĐ»ŃŒĐșĐŸ ĐœĐ° Ń‡Ń‚Đ”ĐœĐžĐ”" Đž "Ń‚ĐŸĐ»ŃŒĐșĐŸ ĐœĐ° Đ·Đ°ĐżĐžŃŃŒ"',
"clientRedirectURIsFragmentError": "URI ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžŃ ĐœĐ” ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ Ń„Ń€Đ°ĐłĐŒĐ”ĐœŃ‚ URI",
"clientRootURLFragmentError": "ĐšĐŸŃ€ĐœĐ”ĐČĐŸĐč URL ĐœĐ” ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ Ń„Ń€Đ°ĐłĐŒĐ”ĐœŃ‚ URL ",
"pairwiseMalformedClientRedirectURI": "ĐšĐ»ĐžĐ”ĐœŃ‚ ŃĐŸĐŽĐ”Ń€Đ¶ĐžŃ‚ ĐœĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč URI ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžŃ.",
"pairwiseClientRedirectURIsMissingHost": "URI ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžŃ ĐșĐ»ĐžĐ”ĐœŃ‚Đ° ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚ Ń…ĐŸŃŃ‚Đ°.",
"pairwiseClientRedirectURIsMultipleHosts":
"БДз ĐșĐŸĐœŃ„ĐžĐłŃƒŃ€Đ°Ń†ĐžĐž ĐżĐŸ часто ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Đ° URI, URI ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžŃ ĐșĐ»ĐžĐ”ĐœŃ‚Đ° ĐœĐ” ĐŒĐŸĐ¶Đ”Ń‚ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ”ŃĐșĐŸĐ»ŃŒĐșĐŸ ĐșĐŸĐŒĐżĐŸĐœĐ”ĐœŃ‚ĐŸĐČ Ń…ĐŸŃŃ‚Đ°.",
"pairwiseMalformedSectorIdentifierURI": "ИсĐșĐ°Đ¶Đ”ĐœĐœĐ°Ń часть ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Đ° URI.",
"pairwiseFailedToGetRedirectURIs": "ĐĐ” ŃƒĐŽĐ°Đ»ĐŸŃŃŒ ĐżĐŸĐ»ŃƒŃ‡ĐžŃ‚ŃŒ ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Ń‹ URI ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžŃ Оз часто ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Đ° URI.",
"pairwiseRedirectURIsMismatch": "ĐšĐ»ĐžĐ”ĐœŃ‚ URI пДрДаЎрДсацОО ĐœĐ” ŃĐŸĐŸŃ‚ĐČДтстĐČŃƒĐ”Ń‚ URI пДрДаЎрДсацОО, ĐżĐŸĐ»ŃƒŃ‡Đ”ĐœĐœĐŸĐč Оз часто ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Đ° URI.",
},
"zh-CN": {
"invalidPasswordMinLengthMessage": "æ— æ•ˆçš„ćŻ†ç ïŒšæœ€çŸ­é•żćșŠ {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "æ— æ•ˆçš„ćŻ†ç ïŒšè‡łć°‘ćŒ…ć« {0} ć°ć†™ć­—æŻ",
"invalidPasswordMinDigitsMessage": "æ— æ•ˆçš„ćŻ†ç ïŒšè‡łć°‘ćŒ…ć« {0} äžȘæ•°ć­—",
"invalidPasswordMinUpperCaseCharsMessage": "æ— æ•ˆçš„ćŻ†ç ïŒšæœ€çŸ­é•żćșŠ {0} ć€§ć†™ć­—æŻ",
"invalidPasswordMinSpecialCharsMessage": "æ— æ•ˆçš„ćŻ†ç ïŒšæœ€çŸ­é•żćșŠ {0} ç‰čæźŠć­—çŹŠ",
"invalidPasswordNotUsernameMessage": "æ— æ•ˆçš„ćŻ†ç ïŒš äžćŻä»„äžŽç”šæˆ·ćç›žćŒ",
"invalidPasswordRegexPatternMessage": "æ— æ•ˆçš„ćŻ†ç ïŒš æ— æł•äžŽæ­Łćˆ™èĄšèŸŸćŒćŒč配",
"invalidPasswordHistoryMessage": "æ— æ•ˆçš„ćŻ†ç ïŒšäžèƒœäžŽæœ€ćŽäœżç”šçš„ {0} äžȘ毆码盾搌",
"ldapErrorInvalidCustomFilter": 'ćźšćˆ¶çš„ LDAPèż‡æ»€ć™šäžæ˜Żä»„ "(" ćŒ€ć€Žæˆ–ä»„ ")"ç»“ć°Ÿ.',
"ldapErrorConnectionTimeoutNotNumber": "Connection Timeout ćż…éĄ»æ˜ŻäžȘæ•°ć­—",
"ldapErrorMissingClientId": "ćœ“ćŸŸè§’è‰Čæ˜ ć°„æœȘćŻç”šæ—¶ïŒŒćźąæˆ·ç«Ż ID éœ€èŠæŒ‡ćźšă€‚",
"ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType": "æ— æł•ćœšäœżç”šUIDæˆć‘˜ç±»ćž‹çš„ćŒæ—¶ç»ŽæŠ€ç»„ç»§æ‰żć±žæ€§ă€‚",
"ldapErrorCantWriteOnlyForReadOnlyLdap": "ćœ“LDAP提䟛æ–čäžæ˜ŻćŻć†™æšĄćŒæ—¶ïŒŒæ— æł•èźŸçœźćȘ憙",
"ldapErrorCantWriteOnlyAndReadOnly": "æ— æł•ćŒæ—¶èźŸçœźćȘèŻ»ć’ŒćȘ憙",
"clientRedirectURIsFragmentError": "重漚搑URL䞍ćș”ćŒ…ć«URIç‰‡æź”",
"clientRootURLFragmentError": "æ čURL 䞍ćș”ćŒ…ć« URL ç‰‡æź”",
"pairwiseMalformedClientRedirectURI": "ćźąæˆ·ç«ŻćŒ…ć«äž€äžȘæ— æ•ˆçš„é‡ćźšć‘URL",
"pairwiseClientRedirectURIsMissingHost": "ćźąæˆ·ç«Żé‡ćźšć‘URL需芁有䞀äžȘ有效的䞻æœș",
"pairwiseClientRedirectURIsMultipleHosts":
"Without a configured Sector Identifier URI, client redirect URIs must not contain multiple host components.",
"pairwiseMalformedSectorIdentifierURI": "Malformed Sector Identifier URI.",
"pairwiseFailedToGetRedirectURIs": "æ— æł•ä»ŽæœćŠĄć™šèŽ·ćŸ—é‡ćźšć‘URL",
"pairwiseRedirectURIsMismatch": "ćźąæˆ·ç«Żçš„é‡ćźšć‘URIäžŽæœćŠĄć™šç«ŻèŽ·ć–çš„URIé…çœźäžćŒč配。",
},
};
/* spell-checker: enable */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,137 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "Desa",
"doCancel": "Cancel·la",
"doLogOutAllSessions": "Desconnecta de totes les sessions",
"doRemove": "Elimina",
"doAdd": "Afegeix",
"doSignOut": "Desconnectar",
"editAccountHtmlTitle": "Edita compte",
"federatedIdentitiesHtmlTitle": "Identitats federades",
"accountLogHtmlTitle": "Registre del compte",
"changePasswordHtmlTitle": "Canvia contrasenya",
"sessionsHtmlTitle": "Sessions",
"accountManagementTitle": "GestiĂł de Compte Keycloak",
"authenticatorTitle": "Autenticador",
"applicationsHtmlTitle": "Aplicacions",
"authenticatorCode": "Codi d'un sol Ășs",
"email": "Email",
"firstName": "Nom",
"givenName": "Nom de pila",
"fullName": "Nom complet",
"lastName": "Cognoms",
"familyName": "Cognom",
"password": "Contrasenya",
"passwordConfirm": "Confirma la contrasenya",
"passwordNew": "Nova contrasenya",
"username": "Usuari",
"address": "Adreça",
"street": "Carrer",
"locality": "Ciutat o Municipi",
"region": "Estat, ProvĂ­ncia, o RegiĂł",
"postal_code": "Postal code",
"country": "PaĂ­s",
"emailVerified": "Email verificat",
"gssDelegationCredential": "GSS Delegation Credential",
"role_admin": "Administrador",
"role_realm-admin": "Administrador del domini",
"role_create-realm": "Crear domini",
"role_view-realm": "Veure domini",
"role_view-users": "Veure usuaris",
"role_view-applications": "Veure aplicacions",
"role_view-clients": "Veure clients",
"role_view-events": "Veure events",
"role_view-identity-providers": "Veure proveĂŻdors d'identitat",
"role_manage-realm": "Gestionar domini",
"role_manage-users": "Gestinar usuaris",
"role_manage-applications": "Gestionar aplicacions",
"role_manage-identity-providers": "Gestionar proveĂŻdors d'identitat",
"role_manage-clients": "Gestionar clients",
"role_manage-events": "Gestionar events",
"role_view-profile": "Veure perfil",
"role_manage-account": "Gestionar compte",
"role_read-token": "Llegir token",
"role_offline-access": "Accés sense connexió",
"client_account": "Compte",
"client_security-admin-console": "Consola d'AdministraciĂł de Seguretat",
"client_realm-management": "GestiĂł de domini",
"client_broker": "Broker",
"requiredFields": "Camps obligatoris",
"allFieldsRequired": "Tots els camps obligatoris",
"backToApplication": "&laquo; Torna a l'aplicaciĂł",
"backTo": "Torna a {0}",
"date": "Data",
"event": "Event",
"ip": "IP",
"client": "Client",
"clients": "Clients",
"details": "Detalls",
"started": "Iniciat",
"lastAccess": "Últim accĂ©s",
"expires": "Expira",
"applications": "Aplicacions",
"account": "Compte",
"federatedIdentity": "Identitat federada",
"authenticator": "Autenticador",
"sessions": "Sessions",
"log": "Registre",
"application": "AplicaciĂł",
"availablePermissions": "Permisos disponibles",
"grantedPermissions": "Permisos concedits",
"grantedPersonalInfo": "InformaciĂł personal concedida",
"additionalGrants": "Permisos addicionals",
"action": "AcciĂł",
"inResource": "a",
"fullAccess": "Accés total",
"offlineToken": "Codi d'autoritzaciĂł offline",
"revoke": "Revocar permĂ­s",
"configureAuthenticators": "Autenticadors configurats",
"mobile": "MĂČbil",
"totpStep1":
'Instal·la <a href="https://freeotp.github.io/" target="_blank">FreeOTP</a> o Google Authenticator al teu telĂšfon mĂČbil. Les dues aplicacions estan disponibles a <a href="https://play.google.com">Google Play</a> i en l\'App Store d\'Apple.',
"totpStep2": "Obre l'aplicaciĂł i escaneja el codi o introdueix la clau.",
"totpStep3": "Introdueix el codi Ășnic que et mostra l'aplicaciĂł d'autenticaciĂł i fes clic a Envia per finalitzar la configuraciĂł",
"missingUsernameMessage": "Si us plau indica el teu usuari.",
"missingFirstNameMessage": "Si us plau indica el nom.",
"invalidEmailMessage": "Email no vĂ lid",
"missingLastNameMessage": "Si us plau indica els teus cognoms.",
"missingEmailMessage": "Si us plau indica l'email.",
"missingPasswordMessage": "Si us plau indica la contrasenya.",
"notMatchPasswordMessage": "Les contrasenyes no coincideixen.",
"missingTotpMessage": "Si us plau indica el teu codi d'autenticaciĂł",
"invalidPasswordExistingMessage": "La contrasenya actual no és correcta.",
"invalidPasswordConfirmMessage": "La confirmaciĂł de contrasenya no coincideix.",
"invalidTotpMessage": "El cĂłdigo de autenticaciĂłn no es vĂĄlido.",
"usernameExistsMessage": "L'usuari ja existeix",
"emailExistsMessage": "L'email ja existeix",
"readOnlyUserMessage": "No pots actualitzar el teu usuari perquÚ el teu compte és de només lectura.",
"readOnlyPasswordMessage": "No pots actualitzar la contrasenya perquÚ el teu compte és de només lectura.",
"successTotpMessage": "AplicaciĂł d'autenticaciĂł mĂČbil configurada.",
"successTotpRemovedMessage": "AplicaciĂł d'autenticaciĂł mĂČbil eliminada.",
"successGrantRevokedMessage": "PermĂ­s revocat correctament",
"accountUpdatedMessage": "El teu compte s'ha actualitzat.",
"accountPasswordUpdatedMessage": "La contrasenya s'ha actualitzat.",
"missingIdentityProviderMessage": "ProveĂŻdor d'identitat no indicat.",
"invalidFederatedIdentityActionMessage": "AcciĂł no vĂ lida o no indicada.",
"identityProviderNotFoundMessage": "No s'ha trobat un proveĂŻdor d'identitat.",
"federatedIdentityLinkNotActiveMessage": "Aquesta identitat ja no estĂ  activa",
"federatedIdentityRemovingLastProviderMessage": "No pots eliminar l'Ășltima identitat federada perquĂš no tens fixada una contrasenya.",
"identityProviderRedirectErrorMessage": "Error en la redirecciĂł al proveĂŻdor d'identitat",
"identityProviderRemovedMessage": "ProveĂŻdor d'identitat esborrat correctament.",
"accountDisabledMessage": "El compte estĂ  desactivada, contacteu amb l'administrador.",
"accountTemporarilyDisabledMessage": "El compte està temporalment desactivat, contacta amb l'administrador o intenta-ho de nou més tard.",
"invalidPasswordMinLengthMessage": "Contrasenya incorrecta: longitud mĂ­nima {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres minĂșscules.",
"invalidPasswordMinDigitsMessage": "Contraseña incorrecta: debe contener al menos {0} caracteres numéricos.",
"invalidPasswordMinUpperCaseCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} lletres majĂșscules.",
"invalidPasswordMinSpecialCharsMessage": "Contrasenya incorrecta: ha de contenir almenys {0} carĂ cters especials.",
"invalidPasswordNotUsernameMessage": "Contrasenya incorrecta: no pot ser igual al nom d'usuari.",
"invalidPasswordRegexPatternMessage": "Contrasenya incorrecta: no compleix l'expressiĂł regular.",
"invalidPasswordHistoryMessage": "Contrasenya incorrecta: no pot ser igual a cap de les Ășltimes {0} contrasenyes."
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,156 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "UloĆŸit",
"doCancel": "ZruĆĄit",
"doLogOutAllSessions": "OdhlĂĄsit vĆĄechny relace",
"doRemove": "Odstranit",
"doAdd": "Pƙidat",
"doSignOut": "OdhlĂĄsit se",
"editAccountHtmlTitle": "Upravit Ășčet",
"federatedIdentitiesHtmlTitle": "Propojené identity",
"accountLogHtmlTitle": "Log Ășčtu",
"changePasswordHtmlTitle": "Změnit heslo",
"sessionsHtmlTitle": "Relace",
"accountManagementTitle": "SprĂĄva ĂșčtĆŻ Keycloak",
"authenticatorTitle": "AutentizĂĄtor",
"applicationsHtmlTitle": "Aplikace",
"authenticatorCode": "JednorĂĄzovĂœ kĂłd",
"email": "E-mail",
"firstName": "PrvnĂ­ kƙestnĂ­ jmĂ©no",
"givenName": "KƙestnĂ­ jmĂ©na",
"fullName": "Celé jméno",
"lastName": "Pƙíjmení",
"familyName": "Rodinné jméno",
"password": "Heslo",
"passwordConfirm": "Nové heslo (znovu)",
"passwordNew": "Nové heslo",
"username": "UĆŸivatelskĂ© jmĂ©no",
"address": "Adresa",
"street": "Ulice",
"locality": "Město nebo lokalita",
"region": "Kraj",
"postal_code": "PSČ",
"country": "StĂĄt",
"emailVerified": "E-mail ověƙen",
"gssDelegationCredential": "GSS delegovanĂ© oprĂĄvněnĂ­",
"role_admin": "SprĂĄvce",
"role_realm-admin": "SprĂĄvce realmu",
"role_create-realm": "Vytvoƙit realm",
"role_view-realm": "Zobrazit realm",
"role_view-users": "Zobrazit uĆŸivatele",
"role_view-applications": "Zobrazit aplikace",
"role_view-clients": "Zobrazit klienty",
"role_view-events": "Zobrazit udĂĄlosti",
"role_view-identity-providers": "Zobrazit poskytovatele identity",
"role_manage-realm": "Spravovat realm",
"role_manage-users": "Spravovat uĆŸivatele",
"role_manage-applications": "Spravovat aplikace",
"role_manage-identity-providers": "Spravovat poskytovatele identity",
"role_manage-clients": "Spravovat klienty",
"role_manage-events": "Spravovat udĂĄlosti",
"role_view-profile": "Zobrazit profil",
"role_manage-account": "Spravovat Ășčet",
"role_manage-account-links": "Spravovat odkazy na Ășčet",
"role_read-token": "Číst token",
"role_offline-access": "Pƙístup offline",
"role_uma_authorization": "Získání oprávnění",
"client_account": "Účet",
"client_security-admin-console": "Administrátorská bezpečnostní konzole",
"client_admin-cli": "Administråtorské CLI",
"client_realm-management": "SprĂĄva realmĆŻ",
"client_broker": "Broker",
"requiredFields": "PoĆŸadovanĂĄ pole",
"allFieldsRequired": "VĆĄechna pole vyĆŸadovanĂĄ",
"backToApplication": "&laquo; Zpět na aplikaci",
"backTo": "Zpět na {0}",
"date": "Datum",
"event": "UdĂĄlost",
"ip": "IP",
"client": "Klient",
"clients": "Klienti",
"details": "Podrobnosti",
"started": "ZahĂĄjeno",
"lastAccess": "Poslední pƙístup",
"expires": "VyprĆĄĂ­",
"applications": "Aplikace",
"account": "Účet",
"federatedIdentity": "PropojenĂĄ identita",
"authenticator": "AutentizĂĄtor",
"sessions": "Relace",
"log": "Log",
"application": "Aplikace",
"availablePermissions": "Dostupná oprávnění",
"grantedPermissions": "UdělenĂ© oprĂĄvněnĂ­",
"grantedPersonalInfo": "Poskytnuté osobní informace",
"additionalGrants": "DodatečnĂ© oprĂĄvněnĂ­",
"action": "Akce",
"inResource": "v",
"fullAccess": "ÚplnĂœ pƙístup",
"offlineToken": "Offline Token",
"revoke": "Zruơit oprávnění",
"configureAuthenticators": "Konfigurované autentizåtory",
"mobile": "MobilnĂ­",
"totpStep1": "Nainstalujte jednu z nĂĄsledujĂ­cĂ­ch aplikacĂ­",
"totpStep2": "Otevƙete aplikaci a naskenujte čárovĂœ kĂłd",
"totpStep3": "Zadejte jednorĂĄzovĂœ kĂłd poskytnutĂœ aplikacĂ­ a klepnutĂ­m na tlačítko UloĆŸit dokončete nastavenĂ­.",
"totpManualStep2": "Otevƙete aplikaci a zadejte klíč",
"totpManualStep3": "PouĆŸijte nĂĄsledujĂ­cĂ­ hodnoty konfigurace, pokud aplikace umoĆŸĆˆuje jejich nastavenĂ­",
"totpUnableToScan": "Nelze skenovat?",
"totpScanBarcode": "Skenovat čárovĂœ kĂłd?",
"totp.totp": "ZaloĆŸeno na čase",
"totp.hotp": "ZaloĆŸeno na čítači",
"totpType": "Typ",
"totpAlgorithm": "Algoritmus",
"totpDigits": "Číslice",
"totpInterval": "Interval",
"totpCounter": "Čítač",
"missingUsernameMessage": "Zadejte uĆŸivatelskĂ© jmĂ©no.",
"missingFirstNameMessage": "Zadejte prosĂ­m kƙestnĂ­ jmĂ©no.",
"invalidEmailMessage": "NeplatnĂĄ e-mailovĂĄ adresa.",
"missingLastNameMessage": "Zadejte prosím pƙíjmení.",
"missingEmailMessage": "Zadejte prosĂ­m e-mail.",
"missingPasswordMessage": "Zadejte prosĂ­m heslo.",
"notMatchPasswordMessage": "Hesla se neshodujĂ­.",
"missingTotpMessage": "Zadejte prosĂ­m kĂłd autentizĂĄtoru.",
"invalidPasswordExistingMessage": "Neplatné ståvající heslo.",
"invalidPasswordConfirmMessage": "NovĂĄ hesla se neshodujĂ­.",
"invalidTotpMessage": "NeplatnĂœ kĂłd autentizĂĄtoru.",
"usernameExistsMessage": "UĆŸivatelskĂ© jmĂ©no jiĆŸ existuje.",
"emailExistsMessage": "E-mail jiĆŸ existuje.",
"readOnlyUserMessage": "NemĆŻĆŸete svĆŻj Ășčet aktualizovat, protoĆŸe je pouze pro čtenĂ­.",
"readOnlyUsernameMessage": "NemĆŻĆŸete aktualizovat svĂ© uĆŸivatelskĂ© jmĂ©no, protoĆŸe je pouze pro čtenĂ­.",
"readOnlyPasswordMessage": "NemĆŻĆŸete aktualizovat svĂ© heslo, protoĆŸe vĂĄĆĄ Ășčet je jen pro čtenĂ­.",
"successTotpMessage": "OvěƙenĂ­ pomocĂ­ OTP Ășspěơně konfigurovĂĄno.",
"successTotpRemovedMessage": "OvěƙenĂ­ pomocĂ­ OTP Ășspěơně odstraněno.",
"successGrantRevokedMessage": "OprĂĄvněnĂ­ bylo Ășspěơně zruĆĄeno.",
"accountUpdatedMessage": "VĂĄĆĄ Ășčet byl aktualizovĂĄn.",
"accountPasswordUpdatedMessage": "VaĆĄe heslo bylo aktualizovĂĄno.",
"missingIdentityProviderMessage": "Chybějící poskytovatel identity.",
"invalidFederatedIdentityActionMessage": "Neplatná nebo chybějící akce.",
"identityProviderNotFoundMessage": "Poskytovatel identity nenalezen.",
"federatedIdentityLinkNotActiveMessage": "Tato identita jiĆŸ nenĂ­ aktivnĂ­.",
"federatedIdentityRemovingLastProviderMessage": "NemĆŻĆŸete odstranit poslednĂ­ propojenou identitu, protoĆŸe nemĂĄte heslo.",
"identityProviderRedirectErrorMessage": "Nepodaƙilo se pƙesměrovat na poskytovatele identity.",
"identityProviderRemovedMessage": "Poskytovatel identity byl Ășspěơně odstraněn.",
"identityProviderAlreadyLinkedMessage": "PropojenĂĄ identita vrĂĄcenĂĄ uĆŸivatelem {0} je jiĆŸ propojena s jinĂœm uĆŸivatelem.",
"staleCodeAccountMessage": "Platnost vyprơela. Zkuste to jeơtě jednou.",
"consentDenied": "Souhlas byl zamĂ­tnut.",
"accountDisabledMessage": "Účet je zakázán, kontaktujte správce.",
"accountTemporarilyDisabledMessage": "Účet je dočasně zakázán, kontaktujte správce nebo zkuste to později.",
"invalidPasswordMinLengthMessage": "NeplatnĂ© heslo: musĂ­ obsahovat minimĂĄlně {0} malĂœch znakĆŻ.",
"invalidPasswordMinLowerCaseCharsMessage": "NeplatnĂ© heslo: musĂ­ obsahovat minimĂĄlně {0} malĂ© znaky.",
"invalidPasswordMinDigitsMessage": "NeplatnĂ© heslo: musĂ­ obsahovat nejmĂ©ně {0} číslic.",
"invalidPasswordMinUpperCaseCharsMessage": "NeplatnĂ© heslo: musĂ­ obsahovat nejmĂ©ně {0} velkĂœch pĂ­smenen.",
"invalidPasswordMinSpecialCharsMessage": "NeplatnĂ© heslo: musĂ­ obsahovat nejmĂ©ně {0} speciĂĄlnĂ­ch znakĆŻ.",
"invalidPasswordNotUsernameMessage": "NeplatnĂ© heslo: nesmĂ­ bĂœt totoĆŸnĂ© s uĆŸivatelskĂœm jmĂ©nem.",
"invalidPasswordRegexPatternMessage": "NeplatnĂ© heslo: neshoduje se zadanĂœm regulĂĄrnĂ­m vĂœrazem.",
"invalidPasswordHistoryMessage": "NeplatnĂ© heslo: NesmĂ­ se opakovat ĆŸĂĄdnĂ© z poslednĂ­ch {0} hesel.",
"invalidPasswordBlacklistedMessage": "NeplatnĂ© heslo: heslo je na černĂ© listině.",
"invalidPasswordGenericMessage": "Neplatné heslo: nové heslo neodpovídå pravidlƯm hesla."
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,156 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "Speichern",
"doCancel": "Abbrechen",
"doLogOutAllSessions": "Alle Sitzungen abmelden",
"doRemove": "Entfernen",
"doAdd": "HinzufĂŒgen",
"doSignOut": "Abmelden",
"editAccountHtmlTitle": "Benutzerkonto bearbeiten",
"federatedIdentitiesHtmlTitle": "Föderierte IdentitÀten",
"accountLogHtmlTitle": "Benutzerkonto Log",
"changePasswordHtmlTitle": "Passwort Ändern",
"sessionsHtmlTitle": "Sitzungen",
"accountManagementTitle": "Keycloak Benutzerkontoverwaltung",
"authenticatorTitle": "Mehrfachauthentifizierung",
"applicationsHtmlTitle": "Applikationen",
"authenticatorCode": "One-time Code",
"email": "E-Mail",
"firstName": "Vorname",
"givenName": "Vorname",
"fullName": "Voller Name",
"lastName": "Nachname",
"familyName": "Nachname",
"password": "Passwort",
"passwordConfirm": "Passwort bestÀtigen",
"passwordNew": "Neues Passwort",
"username": "Benutzername",
"address": "Adresse",
"street": "Straße",
"region": "Staat, Provinz, Region",
"postal_code": "PLZ",
"locality": "Stadt oder Ortschaft",
"country": "Land",
"emailVerified": "E-Mail verifiziert",
"gssDelegationCredential": "GSS delegierte Berechtigung",
"role_admin": "Admin",
"role_realm-admin": "Realm Admin",
"role_create-realm": "Realm erstellen",
"role_view-realm": "Realm ansehen",
"role_view-users": "Benutzer ansehen",
"role_view-applications": "Applikationen ansehen",
"role_view-clients": "Clients ansehen",
"role_view-events": "Events ansehen",
"role_view-identity-providers": "Identity Provider ansehen",
"role_manage-realm": "Realm verwalten",
"role_manage-users": "Benutzer verwalten",
"role_manage-applications": "Applikationen verwalten",
"role_manage-identity-providers": "Identity Provider verwalten",
"role_manage-clients": "Clients verwalten",
"role_manage-events": "Events verwalten",
"role_view-profile": "Profile ansehen",
"role_manage-account": "Profile verwalten",
"role_manage-account-links": "Profil-Links verwalten",
"role_read-token": "Token lesen",
"role_offline-access": "Offline-Zugriff",
"role_uma_authorization": "Berechtigungen einholen",
"client_account": "Clientkonto",
"client_security-admin-console": "Security Adminkonsole",
"client_realm-management": "Realm-Management",
"client_broker": "Broker",
"requiredFields": "Erforderliche Felder",
"allFieldsRequired": "Alle Felder sind erforderlich",
"backToApplication": "&laquo; ZurĂŒck zur Applikation",
"backTo": "ZurĂŒck zu {0}",
"date": "Datum",
"event": "Ereignis",
"ip": "IP",
"client": "Client",
"clients": "Clients",
"details": "Details",
"started": "Startdatum",
"lastAccess": "Letzter Zugriff",
"expires": "Ablaufdatum",
"applications": "Applikationen",
"account": "Benutzerkonto",
"federatedIdentity": "Föderierte IdentitÀt",
"authenticator": "Mehrfachauthentifizierung",
"sessions": "Sitzungen",
"log": "Log",
"application": "Applikation",
"availablePermissions": "verfĂŒgbare Berechtigungen",
"grantedPermissions": "gewÀhrte Berechtigungen",
"grantedPersonalInfo": "gewÀhrte persönliche Informationen",
"additionalGrants": "zusÀtzliche Berechtigungen",
"action": "Aktion",
"inResource": "in",
"fullAccess": "Vollzugriff",
"offlineToken": "Offline-Token",
"revoke": "Berechtigung widerrufen",
"configureAuthenticators": "Mehrfachauthentifizierung konfigurieren",
"mobile": "Mobil",
"totpStep1": "Installieren Sie eine der folgenden Applikationen auf Ihrem Smartphone:",
"totpStep2": "Öffnen Sie die Applikation und scannen Sie den Barcode.",
"totpStep3": "Geben Sie den von der Applikation generierten One-time Code ein und klicken Sie auf Speichern.",
"totpManualStep2": "Öffnen Sie die Applikation und geben Sie den folgenden SchlĂŒssel ein.",
"totpManualStep3": "Verwenden Sie die folgenden Konfigurationswerte, falls Sie diese fĂŒr die Applikation anpassen können:",
"totpUnableToScan": "Sie können den Barcode nicht scannen?",
"totpScanBarcode": "Barcode scannen?",
"totp.totp": "zeitbasiert (time-based)",
"totp.hotp": "zÀhlerbasiert (counter-based)",
"totpType": "Typ",
"totpAlgorithm": "Algorithmus",
"totpDigits": "Ziffern",
"totpInterval": "Intervall",
"totpCounter": "ZĂ€hler",
"missingUsernameMessage": "Bitte geben Sie einen Benutzernamen ein.",
"missingFirstNameMessage": "Bitte geben Sie einen Vornamen ein.",
"invalidEmailMessage": "UngĂŒltige E-Mail Adresse.",
"missingLastNameMessage": "Bitte geben Sie einen Nachnamen ein.",
"missingEmailMessage": "Bitte geben Sie eine E-Mail Adresse ein.",
"missingPasswordMessage": "Bitte geben Sie ein Passwort ein.",
"notMatchPasswordMessage": "Die Passwörter sind nicht identisch.",
"missingTotpMessage": "Bitte geben Sie den One-time Code ein.",
"invalidPasswordExistingMessage": "Das aktuelle Passwort ist ungĂŒltig.",
"invalidPasswordConfirmMessage": "Die PasswortbestÀtigung ist nicht identisch.",
"invalidTotpMessage": "UngĂŒltiger One-time Code.",
"usernameExistsMessage": "Der Benutzername existiert bereits.",
"emailExistsMessage": "Die E-Mail-Adresse existiert bereits.",
"readOnlyUserMessage": "Sie können Ihr Benutzerkonto nicht Ă€ndern, da es schreibgeschĂŒtzt ist.",
"readOnlyUsernameMessage": "Sie können Ihren Benutzernamen nicht Ă€ndern, da er schreibgeschĂŒtzt ist.",
"readOnlyPasswordMessage": "Sie können Ihr Passwort nicht Ă€ndern, da es schreibgeschĂŒtzt ist.",
"successTotpMessage": "Mehrfachauthentifizierung erfolgreich konfiguriert.",
"successTotpRemovedMessage": "Mehrfachauthentifizierung erfolgreich entfernt.",
"successGrantRevokedMessage": "Berechtigung erfolgreich widerrufen.",
"accountUpdatedMessage": "Ihr Benutzerkonto wurde aktualisiert.",
"accountPasswordUpdatedMessage": "Ihr Passwort wurde aktualisiert.",
"missingIdentityProviderMessage": "Identity Provider nicht angegeben.",
"invalidFederatedIdentityActionMessage": "UngĂŒltige oder fehlende Aktion.",
"identityProviderNotFoundMessage": "Angegebener Identity Provider nicht gefunden.",
"federatedIdentityLinkNotActiveMessage": "Diese IdentitÀt ist nicht mehr aktiv.",
"federatedIdentityRemovingLastProviderMessage": "Sie können den letzten Eintrag nicht entfernen, da Sie kein Passwort haben.",
"identityProviderRedirectErrorMessage": "Fehler bei der Weiterleitung zum Identity Provider.",
"identityProviderRemovedMessage": "Identity Provider erfolgreich entfernt.",
"identityProviderAlreadyLinkedMessage": "Die föderierte IdentitÀt von {0} ist bereits einem anderen Benutzer zugewiesen.",
"staleCodeAccountMessage": "Diese Seite ist nicht mehr gĂŒltig, bitte versuchen Sie es noch einmal.",
"consentDenied": "EinverstÀndnis verweigert.",
"accountDisabledMessage": "Ihr Benutzerkonto ist gesperrt, bitte kontaktieren Sie den Admin.",
"accountTemporarilyDisabledMessage":
"Ihr Benutzerkonto ist temporÀr gesperrt, bitte kontaktieren Sie den Admin oder versuchen Sie es spÀter noch einmal.",
"invalidPasswordMinLengthMessage": "UngĂŒltiges Passwort: Es muss mindestens {0} Zeichen lang sein.",
"invalidPasswordMinLowerCaseCharsMessage": "UngĂŒltiges Passwort: Es muss mindestens {0} Kleinbuchstaben beinhalten.",
"invalidPasswordMinDigitsMessage": "UngĂŒltiges Passwort: Es muss mindestens {0} Zahl(en) beinhalten.",
"invalidPasswordMinUpperCaseCharsMessage": "UngĂŒltiges Passwort: Es muss mindestens {0} Großbuchstaben beinhalten.",
"invalidPasswordMinSpecialCharsMessage": "UngĂŒltiges Passwort: Es muss mindestens {0} Sonderzeichen beinhalten.",
"invalidPasswordNotUsernameMessage": "UngĂŒltiges Passwort: Es darf nicht gleich sein wie der Benutzername.",
"invalidPasswordRegexPatternMessage": "UngĂŒltiges Passwort: Es entspricht nicht dem Regex-Muster.",
"invalidPasswordHistoryMessage": "UngĂŒltiges Passwort: Es darf nicht einem der letzten {0} Passwörter entsprechen.",
"invalidPasswordBlacklistedMessage": "UngĂŒltiges Passwort: Das Passwort steht auf der Blocklist (schwarzen Liste).",
"invalidPasswordGenericMessge": "UngĂŒltiges Passwort: Das neue Passwort verletzt die Passwort-Richtlinien."
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,325 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "Save",
"doCancel": "Cancel",
"doLogOutAllSessions": "Log out all sessions",
"doRemove": "Remove",
"doAdd": "Add",
"doSignOut": "Sign Out",
"doLogIn": "Log In",
"doLink": "Link",
"editAccountHtmlTitle": "Edit Account",
"personalInfoHtmlTitle": "Personal Info",
"federatedIdentitiesHtmlTitle": "Federated Identities",
"accountLogHtmlTitle": "Account Log",
"changePasswordHtmlTitle": "Change Password",
"deviceActivityHtmlTitle": "Device Activity",
"sessionsHtmlTitle": "Sessions",
"accountManagementTitle": "Keycloak Account Management",
"authenticatorTitle": "Authenticator",
"applicationsHtmlTitle": "Applications",
"linkedAccountsHtmlTitle": "Linked Accounts",
"accountManagementWelcomeMessage": "Welcome to Keycloak Account Management",
"personalInfoIntroMessage": "Manage your basic information",
"accountSecurityTitle": "Account Security",
"accountSecurityIntroMessage": "Control your password and account access",
"applicationsIntroMessage": "Track and manage your app permission to access your account",
"resourceIntroMessage": "Share your resources among team members",
"passwordLastUpdateMessage": "Your password was updated at",
"updatePasswordTitle": "Update Password",
"updatePasswordMessageTitle": "Make sure you choose a strong password",
"updatePasswordMessage":
"A strong password contains a mix of numbers, letters, and symbols. It is hard to guess, does not resemble a real word, and is only used for this account.",
"personalSubTitle": "Your Personal Info",
"personalSubMessage": "Manage this basic information: your first name, last name and email",
"authenticatorCode": "One-time code",
"email": "Email",
"firstName": "First name",
"givenName": "Given name",
"fullName": "Full name",
"lastName": "Last name",
"familyName": "Family name",
"password": "Password",
"currentPassword": "Current Password",
"passwordConfirm": "Confirmation",
"passwordNew": "New Password",
"username": "Username",
"address": "Address",
"street": "Street",
"locality": "City or Locality",
"region": "State, Province, or Region",
"postal_code": "Zip or Postal code",
"country": "Country",
"emailVerified": "Email verified",
"gssDelegationCredential": "GSS Delegation Credential",
"profileScopeConsentText": "User profile",
"emailScopeConsentText": "Email address",
"addressScopeConsentText": "Address",
"phoneScopeConsentText": "Phone number",
"offlineAccessScopeConsentText": "Offline Access",
"samlRoleListScopeConsentText": "My Roles",
"rolesScopeConsentText": "User roles",
"role_admin": "Admin",
"role_realm-admin": "Realm Admin",
"role_create-realm": "Create realm",
"role_view-realm": "View realm",
"role_view-users": "View users",
"role_view-applications": "View applications",
"role_view-clients": "View clients",
"role_view-events": "View events",
"role_view-identity-providers": "View identity providers",
"role_view-consent": "View consents",
"role_manage-realm": "Manage realm",
"role_manage-users": "Manage users",
"role_manage-applications": "Manage applications",
"role_manage-identity-providers": "Manage identity providers",
"role_manage-clients": "Manage clients",
"role_manage-events": "Manage events",
"role_view-profile": "View profile",
"role_manage-account": "Manage account",
"role_manage-account-links": "Manage account links",
"role_manage-consent": "Manage consents",
"role_read-token": "Read token",
"role_offline-access": "Offline access",
"role_uma_authorization": "Obtain permissions",
"client_account": "Account",
"client_account-console": "Account Console",
"client_security-admin-console": "Security Admin Console",
"client_admin-cli": "Admin CLI",
"client_realm-management": "Realm Management",
"client_broker": "Broker",
"requiredFields": "Required fields",
"allFieldsRequired": "All fields required",
"backToApplication": "&laquo; Back to application",
"backTo": "Back to {0}",
"date": "Date",
"event": "Event",
"ip": "IP",
"client": "Client",
"clients": "Clients",
"details": "Details",
"started": "Started",
"lastAccess": "Last Access",
"expires": "Expires",
"applications": "Applications",
"account": "Account",
"federatedIdentity": "Federated Identity",
"authenticator": "Authenticator",
"device-activity": "Device Activity",
"sessions": "Sessions",
"log": "Log",
"application": "Application",
"availableRoles": "Available Roles",
"grantedPermissions": "Granted Permissions",
"grantedPersonalInfo": "Granted Personal Info",
"additionalGrants": "Additional Grants",
"action": "Action",
"inResource": "in",
"fullAccess": "Full Access",
"offlineToken": "Offline Token",
"revoke": "Revoke Grant",
"configureAuthenticators": "Configured Authenticators",
"mobile": "Mobile",
"totpStep1": "Install one of the following applications on your mobile:",
"totpStep2": "Open the application and scan the barcode:",
"totpStep3": "Enter the one-time code provided by the application and click Save to finish the setup.",
"totpStep3DeviceName": "Provide a Device Name to help you manage your OTP devices.",
"totpManualStep2": "Open the application and enter the key:",
"totpManualStep3": "Use the following configuration values if the application allows setting them:",
"totpUnableToScan": "Unable to scan?",
"totpScanBarcode": "Scan barcode?",
"totp.totp": "Time-based",
"totp.hotp": "Counter-based",
"totpType": "Type",
"totpAlgorithm": "Algorithm",
"totpDigits": "Digits",
"totpInterval": "Interval",
"totpCounter": "Counter",
"totpDeviceName": "Device Name",
"missingUsernameMessage": "Please specify username.",
"missingFirstNameMessage": "Please specify first name.",
"invalidEmailMessage": "Invalid email address.",
"missingLastNameMessage": "Please specify last name.",
"missingEmailMessage": "Please specify email.",
"missingPasswordMessage": "Please specify password.",
"notMatchPasswordMessage": "Passwords don't match.",
"invalidUserMessage": "Invalid user",
"missingTotpMessage": "Please specify authenticator code.",
"missingTotpDeviceNameMessage": "Please specify device name.",
"invalidPasswordExistingMessage": "Invalid existing password.",
"invalidPasswordConfirmMessage": "Password confirmation doesn't match.",
"invalidTotpMessage": "Invalid authenticator code.",
"usernameExistsMessage": "Username already exists.",
"emailExistsMessage": "Email already exists.",
"readOnlyUserMessage": "You can't update your account as it is read-only.",
"readOnlyUsernameMessage": "You can't update your username as it is read-only.",
"readOnlyPasswordMessage": "You can't update your password as your account is read-only.",
"successTotpMessage": "Mobile authenticator configured.",
"successTotpRemovedMessage": "Mobile authenticator removed.",
"successGrantRevokedMessage": "Grant revoked successfully.",
"accountUpdatedMessage": "Your account has been updated.",
"accountPasswordUpdatedMessage": "Your password has been updated.",
"missingIdentityProviderMessage": "Identity provider not specified.",
"invalidFederatedIdentityActionMessage": "Invalid or missing action.",
"identityProviderNotFoundMessage": "Specified identity provider not found.",
"federatedIdentityLinkNotActiveMessage": "This identity is not active anymore.",
"federatedIdentityRemovingLastProviderMessage": "You can't remove last federated identity as you don't have a password.",
"identityProviderRedirectErrorMessage": "Failed to redirect to identity provider.",
"identityProviderRemovedMessage": "Identity provider removed successfully.",
"identityProviderAlreadyLinkedMessage": "Federated identity returned by {0} is already linked to another user.",
"staleCodeAccountMessage": "The page expired. Please try one more time.",
"consentDenied": "Consent denied.",
"accountDisabledMessage": "Account is disabled, contact your administrator.",
"accountTemporarilyDisabledMessage": "Account is temporarily disabled, contact your administrator or try again later.",
"invalidPasswordMinLengthMessage": "Invalid password: minimum length {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Invalid password: must contain at least {0} lower case characters.",
"invalidPasswordMinDigitsMessage": "Invalid password: must contain at least {0} numerical digits.",
"invalidPasswordMinUpperCaseCharsMessage": "Invalid password: must contain at least {0} upper case characters.",
"invalidPasswordMinSpecialCharsMessage": "Invalid password: must contain at least {0} special characters.",
"invalidPasswordNotUsernameMessage": "Invalid password: must not be equal to the username.",
"invalidPasswordRegexPatternMessage": "Invalid password: fails to match regex pattern(s).",
"invalidPasswordHistoryMessage": "Invalid password: must not be equal to any of last {0} passwords.",
"invalidPasswordBlacklistedMessage": "Invalid password: password is blacklisted.",
"invalidPasswordGenericMessage": "Invalid password: new password doesn't match password policies.",
"myResources": "My Resources",
"myResourcesSub": "My resources",
"doDeny": "Deny",
"doRevoke": "Revoke",
"doApprove": "Approve",
"doRemoveSharing": "Remove Sharing",
"doRemoveRequest": "Remove Request",
"peopleAccessResource": "People with access to this resource",
"resourceManagedPolicies": "Permissions granting access to this resource",
"resourceNoPermissionsGrantingAccess": "No permissions granting access to this resource",
"anyAction": "Any action",
"description": "Description",
"name": "Name",
"scopes": "Scopes",
"resource": "Resource",
"user": "User",
"peopleSharingThisResource": "People sharing this resource",
"shareWithOthers": "Share with others",
"needMyApproval": "Need my approval",
"requestsWaitingApproval": "Your requests waiting approval",
"icon": "Icon",
"requestor": "Requestor",
"owner": "Owner",
"resourcesSharedWithMe": "Resources shared with me",
"permissionRequestion": "Permission Requestion",
"permission": "Permission",
"shares": "share(s)",
"notBeingShared": "This resource is not being shared.",
"notHaveAnyResource": "You don't have any resources",
"noResourcesSharedWithYou": "There are no resources shared with you",
"havePermissionRequestsWaitingForApproval": "You have {0} permission request(s) waiting for approval.",
"clickHereForDetails": "Click here for details.",
"resourceIsNotBeingShared": "The resource is not being shared",
"locale_ca": "CatalĂ ",
"locale_cs": "Čeơtina",
"locale_de": "Deutsch",
"locale_en": "English",
"locale_es": "Español",
"locale_fr": "Français",
"locale_it": "Italian",
"locale_ja": "æ—„æœŹèȘž",
"locale_nl": "Nederlands",
"locale_no": "Norsk",
"locale_lt": "LietuviĆł",
"locale_pt-BR": "PortuguĂȘs (Brasil)",
"locale_ru": "РуссĐșĐžĐč",
"locale_sk": "Slovenčina",
"locale_sv": "Svenska",
"locale_tr": "Turkish",
"locale_zh-CN": "äž­æ–‡çź€äœ“",
"applicaitonName": "Name",
"applicationType": "Application Type",
"applicationInUse": "In-use app only",
"clearAllFilter": "Clear all filters",
"activeFilters": "Active filters",
"filterByName": "Filter By Name ...",
"allApps": "All applications",
"internalApps": "Internal applications",
"thirdpartyApps": "Third-Party applications",
"appResults": "Results",
"clientNotFoundMessage": "Client not found.",
"authorizedProvider": "Authorized Provider",
"authorizedProviderMessage": "Authorized Providers linked with your account",
"identityProvider": "Identity Provider",
"identityProviderMessage": "To link your account with identity providers you have configured",
"socialLogin": "Social Login",
"userDefined": "User Defined",
"removeAccess": "Remove Access",
"removeAccessMessage": "You will need to grant access again, if you want to use this app account.",
"authenticatorStatusMessage": "Two-factor authentication is currently",
"authenticatorFinishSetUpTitle": "Your Two-Factor Authentication",
"authenticatorFinishSetUpMessage":
"Each time you sign in to your Keycloak account, you will be asked to provide a two-factor authentication code.",
"authenticatorSubTitle": "Set Up Two-Factor Authentication",
"authenticatorSubMessage": "To enhance the security of your account, enable at least one of the available two-factor authentication methods.",
"authenticatorMobileTitle": "Mobile Authenticator",
"authenticatorMobileMessage": "Use mobile Authenticator to get Verification codes as the two-factor authentication.",
"authenticatorMobileFinishSetUpMessage": "The authenticator has been bound to your phone.",
"authenticatorActionSetup": "Set up",
"authenticatorSMSTitle": "SMS Code",
"authenticatorSMSMessage": "Keycloak will send the Verification code to your phone as the two-factor authentication.",
"authenticatorSMSFinishSetUpMessage": "Text messages are sent to",
"authenticatorDefaultStatus": "Default",
"authenticatorChangePhone": "Change Phone Number",
"authenticatorBackupCodesTitle": "Backup Codes",
"authenticatorBackupCodesMessage": "Get your 8-digit backup codes",
"authenticatorBackupCodesFinishSetUpMessage": "12 backup codes were generated at this time. Each one can be used once.",
"authenticatorMobileSetupTitle": "Mobile Authenticator Setup",
"smscodeIntroMessage": "Enter your phone number and a verification code will be sent to your phone.",
"mobileSetupStep1": "Install an authenticator application on your phone. The applications listed here are supported.",
"mobileSetupStep2": "Open the application and scan the barcode:",
"mobileSetupStep3": "Enter the one-time code provided by the application and click Save to finish the setup.",
"scanBarCode": "Want to scan the barcode?",
"enterBarCode": "Enter the one-time code",
"doCopy": "Copy",
"doFinish": "Finish",
"authenticatorSMSCodeSetupTitle": "SMS Code Setup",
"chooseYourCountry": "Choose your country",
"enterYourPhoneNumber": "Enter your phone number",
"sendVerficationCode": "Send Verification Code",
"enterYourVerficationCode": "Enter your verification code",
"authenticatorBackupCodesSetupTitle": "Backup Codes Setup",
"backupcodesIntroMessage":
"If you lose access to your phone, you can still log into your account through backup codes. Keep them somewhere safe and accessible.",
"realmName": "Realm",
"doDownload": "Download",
"doPrint": "Print",
"backupCodesTips-1": "Each backup code can be used once.",
"backupCodesTips-2": "These codes were generated on",
"generateNewBackupCodes": "Generate New Backup Codes",
"backupCodesTips-3": "When you generate new backup codes, the current codes will not work anymore.",
"backtoAuthenticatorPage": "Back to Authenticator Page",
"resources": "Resources",
"sharedwithMe": "Shared with Me",
"share": "Share",
"sharedwith": "Shared with",
"accessPermissions": "Access Permissions",
"permissionRequests": "Permission Requests",
"approve": "Approve",
"approveAll": "Approve all",
"people": "people",
"perPage": "per page",
"currentPage": "Current Page",
"sharetheResource": "Share the resource",
"group": "Group",
"selectPermission": "Select Permission",
"addPeople": "Add people to share your resource with",
"addTeam": "Add team to share your resource with",
"myPermissions": "My Permissions",
"waitingforApproval": "Waiting for approval",
"anyPermission": "Any Permission",
"openshift.scope.user_info": "User information",
"openshift.scope.user_check-access": "User access information",
"openshift.scope.user_full": "Full Access",
"openshift.scope.list-projects": "List projects"
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,137 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "Guardar",
"doCancel": "Cancelar",
"doLogOutAllSessions": "Desconectar de todas las sesiones",
"doRemove": "Eliminar",
"doAdd": "Añadir",
"doSignOut": "Desconectar",
"editAccountHtmlTitle": "Editar cuenta",
"federatedIdentitiesHtmlTitle": "Identidades federadas",
"accountLogHtmlTitle": "Registro de la cuenta",
"changePasswordHtmlTitle": "Cambiar contraseña",
"sessionsHtmlTitle": "Sesiones",
"accountManagementTitle": "GestiĂłn de Cuenta Keycloak",
"authenticatorTitle": "Autenticador",
"applicationsHtmlTitle": "Aplicaciones",
"authenticatorCode": "CĂłdigo de un solo uso",
"email": "Email",
"firstName": "Nombre",
"givenName": "Nombre de pila",
"fullName": "Nombre completo",
"lastName": "Apellidos",
"familyName": "Apellido",
"password": "Contraseña",
"passwordConfirm": "Confirma la contraseña",
"passwordNew": "Nueva contraseña",
"username": "Usuario",
"address": "DirecciĂłn",
"street": "Calle",
"locality": "Ciudad o Municipio",
"region": "Estado, Provincia, o RegiĂłn",
"postal_code": "CĂłdigo Postal",
"country": "PaĂ­s",
"emailVerified": "Email verificado",
"gssDelegationCredential": "GSS Delegation Credential",
"role_admin": "Administrador",
"role_realm-admin": "Administrador del dominio",
"role_create-realm": "Crear dominio",
"role_view-realm": "Ver dominio",
"role_view-users": "Ver usuarios",
"role_view-applications": "Ver aplicaciones",
"role_view-clients": "Ver clientes",
"role_view-events": "Ver eventos",
"role_view-identity-providers": "Ver proveedores de identidad",
"role_manage-realm": "Gestionar dominio",
"role_manage-users": "Gestionar usuarios",
"role_manage-applications": "Gestionar aplicaciones",
"role_manage-identity-providers": "Gestionar proveedores de identidad",
"role_manage-clients": "Gestionar clientes",
"role_manage-events": "Gestionar eventos",
"role_view-profile": "Ver perfil",
"role_manage-account": "Gestionar cuenta",
"role_read-token": "Leer token",
"role_offline-access": "Acceso sin conexiĂłn",
"client_account": "Cuenta",
"client_security-admin-console": "Consola de AdministraciĂłn de Seguridad",
"client_realm-management": "GestiĂłn de dominio",
"client_broker": "Broker",
"requiredFields": "Campos obligatorios",
"allFieldsRequired": "Todos los campos obligatorios",
"backToApplication": "&laquo; Volver a la aplicaciĂłn",
"backTo": "Volver a {0}",
"date": "Fecha",
"event": "Evento",
"ip": "IP",
"client": "Cliente",
"clients": "Clientes",
"details": "Detalles",
"started": "Iniciado",
"lastAccess": "Último acceso",
"expires": "Expira",
"applications": "Aplicaciones",
"account": "Cuenta",
"federatedIdentity": "Identidad federada",
"authenticator": "Autenticador",
"sessions": "Sesiones",
"log": "Regisro",
"application": "AplicaciĂłn",
"availablePermissions": "Permisos disponibles",
"grantedPermissions": "Permisos concedidos",
"grantedPersonalInfo": "InformaciĂłn personal concedida",
"additionalGrants": "Permisos adicionales",
"action": "AcciĂłn",
"inResource": "en",
"fullAccess": "Acceso total",
"offlineToken": "CĂłdigo de autorizaciĂłn offline",
"revoke": "Revocar permiso",
"configureAuthenticators": "Autenticadores configurados",
"mobile": "MĂłvil",
"totpStep1":
'Instala <a href="https://freeotp.github.io/" target="_blank">FreeOTP</a> o Google Authenticator en tu teléfono móvil. Ambas aplicaciones estån disponibles en <a href="https://play.google.com">Google Play</a> y en la App Store de Apple.',
"totpStep2": "Abre la aplicaciĂłn y escanea el cĂłdigo o introduce la clave.",
"totpStep3": "Introduce el cĂłdigo Ășnico que te muestra la aplicaciĂłn de autenticaciĂłn y haz clic en Enviar para finalizar la configuraciĂłn",
"missingUsernameMessage": "Por favor indica tu usuario.",
"missingFirstNameMessage": "Por favor indica el nombre.",
"invalidEmailMessage": "Email no vĂĄlido",
"missingLastNameMessage": "Por favor indica tus apellidos.",
"missingEmailMessage": "Por favor indica el email.",
"missingPasswordMessage": "Por favor indica tu contraseña.",
"notMatchPasswordMessage": "Las contraseñas no coinciden.",
"missingTotpMessage": "Por favor indica tu cĂłdigo de autenticaciĂłn",
"invalidPasswordExistingMessage": "La contraseña actual no es correcta.",
"invalidPasswordConfirmMessage": "La confirmación de contraseña no coincide.",
"invalidTotpMessage": "El cĂłdigo de autenticaciĂłn no es vĂĄlido.",
"usernameExistsMessage": "El usuario ya existe",
"emailExistsMessage": "El email ya existe",
"readOnlyUserMessage": "No puedes actualizar tu usuario porque tu cuenta es de solo lectura.",
"readOnlyPasswordMessage": "No puedes actualizar tu contraseña porque tu cuenta es de solo lectura.",
"successTotpMessage": "AplicaciĂłn de autenticaciĂłn mĂłvil configurada.",
"successTotpRemovedMessage": "AplicaciĂłn de autenticaciĂłn mĂłvil eliminada.",
"successGrantRevokedMessage": "Permiso revocado correctamente",
"accountUpdatedMessage": "Tu cuenta se ha actualizado.",
"accountPasswordUpdatedMessage": "Tu contraseña se ha actualizado.",
"missingIdentityProviderMessage": "Proveedor de identidad no indicado.",
"invalidFederatedIdentityActionMessage": "AcciĂłn no vĂĄlida o no indicada.",
"identityProviderNotFoundMessage": "No se encontrĂł un proveedor de identidad.",
"federatedIdentityLinkNotActiveMessage": "Esta identidad ya no estĂĄ activa",
"federatedIdentityRemovingLastProviderMessage": "No puedes eliminar la Ășltima identidad federada porque no tienes fijada una contraseña.",
"identityProviderRedirectErrorMessage": "Error en la redirecciĂłn al proveedor de identidad",
"identityProviderRemovedMessage": "Proveedor de identidad borrado correctamente.",
"accountDisabledMessage": "La cuenta estĂĄ desactivada, contacta con el administrador.",
"accountTemporarilyDisabledMessage": "La cuenta estå temporalmente desactivada, contacta con el administrador o inténtalo de nuevo mås tarde.",
"invalidPasswordMinLengthMessage": "Contraseña incorrecta: longitud mínima {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Contraseña incorrecta: debe contener al menos {0} letras minĂșsculas.",
"invalidPasswordMinDigitsMessage": "Contraseña incorrecta: debe contener al menos {0} caracteres numéricos.",
"invalidPasswordMinUpperCaseCharsMessage": "Contraseña incorrecta: debe contener al menos {0} letras mayĂșsculas.",
"invalidPasswordMinSpecialCharsMessage": "Contraseña incorrecta: debe contener al menos {0} caracteres especiales.",
"invalidPasswordNotUsernameMessage": "Contraseña incorrecta: no puede ser igual al nombre de usuario.",
"invalidPasswordRegexPatternMessage": "Contraseña incorrecta: no cumple la expresión regular.",
"invalidPasswordHistoryMessage": "Contraseña incorrecta: no puede ser igual a ninguna de las Ășltimas {0} contraseñas."
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,150 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "Sauvegarder",
"doCancel": "Annuler",
"doLogOutAllSessions": "Déconnexion de toutes les sessions",
"doRemove": "Supprimer",
"doAdd": "Ajouter",
"doSignOut": "Déconnexion",
"editAccountHtmlTitle": "Édition du compte",
"federatedIdentitiesHtmlTitle": "Identités fédérées",
"accountLogHtmlTitle": "AccĂšs au compte",
"changePasswordHtmlTitle": "Changer de mot de passe",
"sessionsHtmlTitle": "Sessions",
"accountManagementTitle": "Gestion du compte Keycloak",
"authenticatorTitle": "Authentification",
"applicationsHtmlTitle": "Applications",
"authenticatorCode": "Mot de passe unique",
"email": "Courriel",
"firstName": "Prénom",
"givenName": "Prénom",
"fullName": "Nom complet",
"lastName": "Nom",
"familyName": "Nom de famille",
"password": "Mot de passe",
"passwordConfirm": "Confirmation",
"passwordNew": "Nouveau mot de passe",
"username": "Compte",
"address": "Adresse",
"street": "Rue",
"locality": "Ville ou Localité",
"region": "État, Province ou RĂ©gion",
"postal_code": "Code Postal",
"country": "Pays",
"emailVerified": "Courriel vérifié",
"gssDelegationCredential": "Accréditation de délégation GSS",
"role_admin": "Administrateur",
"role_realm-admin": "Administrateur du domaine",
"role_create-realm": "Créer un domaine",
"role_view-realm": "Voir un domaine",
"role_view-users": "Voir les utilisateurs",
"role_view-applications": "Voir les applications",
"role_view-clients": "Voir les clients",
"role_view-events": "Voir les événements",
"role_view-identity-providers": "Voir les fournisseurs d'identités",
"role_manage-realm": "Gérer le domaine",
"role_manage-users": "Gérer les utilisateurs",
"role_manage-applications": "Gérer les applications",
"role_manage-identity-providers": "Gérer les fournisseurs d'identités",
"role_manage-clients": "Gérer les clients",
"role_manage-events": "Gérer les événements",
"role_view-profile": "Voir le profil",
"role_manage-account": "Gérer le compte",
"role_read-token": "Lire le jeton d'authentification",
"role_offline-access": "AccĂšs hors-ligne",
"client_account": "Compte",
"client_security-admin-console": "Console d'administration de la sécurité",
"client_admin-cli": "Admin CLI",
"client_realm-management": "Gestion du domaine",
"client_broker": "Broker",
"requiredFields": "Champs obligatoires",
"allFieldsRequired": "Tous les champs sont obligatoires",
"backToApplication": "&laquo; Revenir Ă  l'application",
"backTo": "Revenir Ă  {0}",
"date": "Date",
"event": "Evénement",
"ip": "IP",
"client": "Client",
"clients": "Clients",
"details": "Détails",
"started": "Début",
"lastAccess": "Dernier accĂšs",
"expires": "Expiration",
"applications": "Applications",
"account": "Compte",
"federatedIdentity": "Identité fédérée",
"authenticator": "Authentification",
"sessions": "Sessions",
"log": "Connexion",
"application": "Application",
"availablePermissions": "Permissions disponibles",
"grantedPermissions": "Permissions accordées",
"grantedPersonalInfo": "Informations personnelles accordées",
"additionalGrants": "Droits additionnels",
"action": "Action",
"inResource": "dans",
"fullAccess": "AccĂšs complet",
"offlineToken": "Jeton d'authentification hors-ligne",
"revoke": "Révoquer un droit",
"configureAuthenticators": "Authentifications configurées.",
"mobile": "Téléphone mobile",
"totpStep1": "Installez une des applications suivantes sur votre mobile",
"totpStep2": "Ouvrez l'application et scannez le code-barres ou entrez la clef.",
"totpStep3": "Entrez le code Ă  usage unique fourni par l'application et cliquez sur Sauvegarder pour terminer.",
"totpManualStep2": "Ouvrez l'application et entrez la clef",
"totpManualStep3": "Utilisez les valeurs de configuration suivante si l'application les autorise",
"totpUnableToScan": "Impossible de scanner ?",
"totpScanBarcode": "Scanner le code-barres ?",
"totp.totp": "Basé sur le temps",
"totp.hotp": "Basé sur un compteur",
"totpType": "Type",
"totpAlgorithm": "Algorithme",
"totpDigits": "Chiffres",
"totpInterval": "Intervalle",
"totpCounter": "Compteur",
"missingUsernameMessage": "Veuillez entrer votre nom d'utilisateur.",
"missingFirstNameMessage": "Veuillez entrer votre prénom.",
"invalidEmailMessage": "Courriel invalide.",
"missingLastNameMessage": "Veuillez entrer votre nom.",
"missingEmailMessage": "Veuillez entrer votre courriel.",
"missingPasswordMessage": "Veuillez entrer votre mot de passe.",
"notMatchPasswordMessage": "Les mots de passe ne sont pas identiques",
"missingTotpMessage": "Veuillez entrer le code d'authentification.",
"invalidPasswordExistingMessage": "Mot de passe existant invalide.",
"invalidPasswordConfirmMessage": "Le mot de passe de confirmation ne correspond pas.",
"invalidTotpMessage": "Le code d'authentification est invalide.",
"usernameExistsMessage": "Le nom d'utilisateur existe déjà.",
"emailExistsMessage": "Le courriel existe déjà.",
"readOnlyUserMessage": "Vous ne pouvez pas mettre Ă  jour votre compte car il est en lecture seule.",
"readOnlyPasswordMessage": "Vous ne pouvez pas mettre Ă  jour votre mot de passe car votre compte est en lecture seule.",
"successTotpMessage": "L'authentification via téléphone mobile est configurée.",
"successTotpRemovedMessage": "L'authentification via téléphone mobile est supprimée.",
"successGrantRevokedMessage": "Droit révoqué avec succÚs.",
"accountUpdatedMessage": "Votre compte a été mis à jour.",
"accountPasswordUpdatedMessage": "Votre mot de passe a été mis à jour.",
"missingIdentityProviderMessage": "Le fournisseur d'identité n'est pas spécifié.",
"invalidFederatedIdentityActionMessage": "Action manquante ou invalide.",
"identityProviderNotFoundMessage": "Le fournisseur d'identité spécifié n'est pas trouvé.",
"federatedIdentityLinkNotActiveMessage": "Cette identité n'est plus active dorénavant.",
"federatedIdentityRemovingLastProviderMessage":
"Vous ne pouvez pas supprimer votre derniÚre fédération d'identité sans avoir de mot de passe spécifié.",
"identityProviderRedirectErrorMessage": "Erreur de redirection vers le fournisseur d'identité.",
"identityProviderRemovedMessage": "Le fournisseur d'identité a été supprimé correctement.",
"identityProviderAlreadyLinkedMessage": "Le fournisseur d'identité retourné par {0} est déjà lié à un autre utilisateur.",
"accountDisabledMessage": "Ce compte est désactivé, veuillez contacter votre administrateur.",
"accountTemporarilyDisabledMessage": "Ce compte est temporairement désactivé, veuillez contacter votre administrateur ou réessayez plus tard.",
"invalidPasswordMinLengthMessage": "Mot de passe invalide: longueur minimale {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Mot de passe invalide: doit contenir au moins {0} lettre(s) en minuscule.",
"invalidPasswordMinDigitsMessage": "Mot de passe invalide: doit contenir au moins {0} chiffre(s).",
"invalidPasswordMinUpperCaseCharsMessage": "Mot de passe invalide: doit contenir au moins {0} lettre(s) en majuscule.",
"invalidPasswordMinSpecialCharsMessage": "Mot de passe invalide: doit contenir au moins {0} caractÚre(s) spéciaux.",
"invalidPasswordNotUsernameMessage": "Mot de passe invalide: ne doit pas ĂȘtre identique au nom d'utilisateur.",
"invalidPasswordRegexPatternMessage": "Mot de passe invalide: ne valide pas l'expression rationnelle.",
"invalidPasswordHistoryMessage": "Mot de passe invalide: ne doit pas ĂȘtre Ă©gal aux {0} derniers mots de passe."
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,310 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "Salva",
"doCancel": "Annulla",
"doLogOutAllSessions": "Effettua il logout da tutte le sessioni",
"doRemove": "Elimina",
"doAdd": "Aggiungi",
"doSignOut": "Esci",
"doLogIn": "Log In",
"doLink": "Link",
"editAccountHtmlTitle": "Modifica Account",
"personalInfoHtmlTitle": "Informazioni personali",
"federatedIdentitiesHtmlTitle": "IdentitĂ  federate",
"accountLogHtmlTitle": "Log dell'account",
"changePasswordHtmlTitle": "Cambia password",
"deviceActivityHtmlTitle": "AttivitĂ  dei dispositivi",
"sessionsHtmlTitle": "Sessioni",
"accountManagementTitle": "Gestione degli account di Keycloak",
"authenticatorTitle": "Autenticatore",
"applicationsHtmlTitle": "Applicazioni",
"linkedAccountsHtmlTitle": "Account collegati",
"accountManagementWelcomeMessage": "Benvenuto nella gestione degli account di Keycloak",
"personalInfoIntroMessage": "Gestisci le tue informazioni di base",
"accountSecurityTitle": "Sicurezza dell'account",
"accountSecurityIntroMessage": "Controlla la tua password e gli accessi dell'account",
"applicationsIntroMessage": "Traccia e gestisci i permessi delle applicazioni nell'accesso al tuo account",
"resourceIntroMessage": "Condividi le tue risorse tra i membri del team",
"passwordLastUpdateMessage": "La tua password Ăš stata aggiornata il",
"updatePasswordTitle": "Aggiornamento password",
"updatePasswordMessageTitle": "Assicurati di scegliere una password robusta",
"updatePasswordMessage":
"Una password robusta contiene un misto di numeri, lettere, e simboli. È difficile da indovinare, non assomiglia a una parola reale, ed Ú utilizzata solo per questo account.",
"personalSubTitle": "Le tue informazioni personali",
"personalSubMessage": "Gestisce queste informazioni di base: il tuo nome, cognome, e indirizzo email",
"authenticatorCode": "Codice monouso",
"email": "Email",
"firstName": "Nome",
"givenName": "Nome",
"fullName": "Nome completo",
"lastName": "Cognome",
"familyName": "Cognome",
"password": "Password",
"currentPassword": "Password attuale",
"passwordConfirm": "Conferma password",
"passwordNew": "Nuova password",
"username": "Username",
"address": "Indirizzo",
"street": "Via",
"locality": "CittĂ  o localitĂ ",
"region": "Stato, Provincia, o Regione",
"postal_code": "CAP",
"country": "Paese",
"emailVerified": "Email verificata",
"gssDelegationCredential": "Credenziali delega GSS",
"profileScopeConsentText": "Profilo utente",
"emailScopeConsentText": "Indirizzo email",
"addressScopeConsentText": "Indirizzo",
"phoneScopeConsentText": "Numero di telefono",
"offlineAccessScopeConsentText": "Accesso offline",
"samlRoleListScopeConsentText": "I miei ruoli",
"rolesScopeConsentText": "Ruoli utente",
"role_admin": "Admin",
"role_realm-admin": "Realm admin",
"role_create-realm": "Crea realm",
"role_view-realm": "Visualizza realm",
"role_view-users": "Visualizza utenti",
"role_view-applications": "Visualizza applicazioni",
"role_view-clients": "Visualizza client",
"role_view-events": "Visualizza eventi",
"role_view-identity-providers": "Visualizza identity provider",
"role_view-consent": "Visualizza consensi",
"role_manage-realm": "Gestisci realm",
"role_manage-users": "Gestisci utenti",
"role_manage-applications": "Gestisci applicazioni",
"role_manage-identity-providers": "Gestisci identity provider",
"role_manage-clients": "Gestisci client",
"role_manage-events": "Gestisci eventi",
"role_view-profile": "Visualizza profilo",
"role_manage-account": "Gestisci account",
"role_manage-account-links": "Gestisci i link dell'account",
"role_manage-consent": "Gestisci consensi",
"role_read-token": "Leggi token",
"role_offline-access": "Accesso offline",
"role_uma_authorization": "Ottieni permessi",
"client_account": "Account",
"client_account-console": "Console account",
"client_security-admin-console": "Console di amministrazione di sicurezza",
"client_admin-cli": "Admin CLI",
"client_realm-management": "Gestione realm",
"client_broker": "Broker",
"requiredFields": "Campi obbligatori",
"allFieldsRequired": "Tutti campi obbligatori",
"backToApplication": "&laquo; Torna all'applicazione",
"backTo": "Torna a {0}",
"date": "Data",
"event": "Evento",
"ip": "IP",
"client": "Client",
"clients": "Client",
"details": "Dettagli",
"started": "Iniziato",
"lastAccess": "Ultimo accesso",
"expires": "Scade",
"applications": "Applicazioni",
"account": "Account",
"federatedIdentity": "IdentitĂ  federate",
"authenticator": "Autenticatore",
"device-activity": "AttivitĂ  dei dispositivi",
"sessions": "Sessioni",
"log": "Log",
"application": "Applicazione",
"availablePermissions": "Autorizzazioni disponibili",
"grantedPermissions": "Autorizzazioni concesse",
"grantedPersonalInfo": "Informazioni personali concesse",
"additionalGrants": "Ulteriori concessioni",
"action": "Azione",
"inResource": "in",
"fullAccess": "Accesso completo",
"offlineToken": "Token offline",
"revoke": "Revoca concessione",
"configureAuthenticators": "Autenticatori configurati",
"mobile": "Dispositivo mobile",
"totpStep1": "Installa una delle seguenti applicazioni sul tuo dispositivo mobile",
"totpStep2": "Apri l'applicazione e scansiona il codice QR",
"totpStep3": "Scrivi il codice monouso fornito dall'applicazione e clicca Salva per completare il setup.",
"totpStep3DeviceName": "Fornisci il nome del dispositivo per aiutarti a gestire i dispositivi di autenticazione.",
"totpManualStep2": "Apri l'applicazione e scrivi la chiave",
"totpManualStep3": "Usa le seguenti impostazioni se l'applicazione lo consente",
"totpUnableToScan": "Non riesci a scansionare il codice QR?",
"totpScanBarcode": "Vuoi scansionare il codice QR?",
"totp.totp": "Basato sull'ora",
"totp.hotp": "Basato sul contatore",
"totpType": "Tipo",
"totpAlgorithm": "Algoritmo",
"totpDigits": "Cifre",
"totpInterval": "Intervallo",
"totpCounter": "Contatore",
"totpDeviceName": "Nome dispositivo",
"missingUsernameMessage": "Inserisci lo username.",
"missingFirstNameMessage": "Inserisci il nome.",
"invalidEmailMessage": "Indirizzo email non valido.",
"missingLastNameMessage": "Inserisci il cognome.",
"missingEmailMessage": "Inserisci l'indirizzo email.",
"missingPasswordMessage": "Inserisci la password.",
"notMatchPasswordMessage": "Le password non coincidono.",
"invalidUserMessage": "Utente non valido",
"missingTotpMessage": "Inserisci il codice di autenticazione.",
"missingTotpDeviceNameMessage": "Inserisci il nome del dispositivo di autenticazione.",
"invalidPasswordExistingMessage": "Password esistente non valida.",
"invalidPasswordConfirmMessage": "La password di conferma non coincide.",
"invalidTotpMessage": "Codice di autenticazione non valido.",
"usernameExistsMessage": "Username giĂ  esistente.",
"emailExistsMessage": "Email giĂ  esistente.",
"readOnlyUserMessage": "Non puoi aggiornare il tuo account poiché Ú in modalità sola lettura.",
"readOnlyUsernameMessage": "Non puoi aggiornare il tuo nome utente poiché Ú in modalità sola lettura.",
"readOnlyPasswordMessage": "Non puoi aggiornare il tuo account poiché Ú in modalità sola lettura.",
"successTotpMessage": "Autenticatore mobile configurato.",
"successTotpRemovedMessage": "Autenticatore mobile eliminato.",
"successGrantRevokedMessage": "Concessione revocata con successo.",
"accountUpdatedMessage": "Il tuo account Ăš stato aggiornato.",
"accountPasswordUpdatedMessage": "La tua password Ăš stata aggiornata.",
"missingIdentityProviderMessage": "Identity provider non specificato.",
"invalidFederatedIdentityActionMessage": "Azione non valida o mancante.",
"identityProviderNotFoundMessage": "L'identity provider specificato non Ăš stato trovato.",
"federatedIdentityLinkNotActiveMessage": "Questo identity non Ăš piĂč attivo.",
"federatedIdentityRemovingLastProviderMessage": "Non puoi rimuovere l'ultima identitĂ  federata poichĂ© non hai piĂč la password.",
"identityProviderRedirectErrorMessage": "Il reindirizzamento all'identity provider Ăš fallito.",
"identityProviderRemovedMessage": "Identity provider eliminato correttamente.",
"identityProviderAlreadyLinkedMessage": "L'identitĂ  federata restituita da {0} Ăš giĂ  collegata ad un altro utente.",
"staleCodeAccountMessage": "La pagina Ăš scaduta. Prova di nuovo.",
"consentDenied": "Consenso negato.",
"accountDisabledMessage": "Account disabilitato, contatta l'amministratore.",
"accountTemporarilyDisabledMessage": "L'account Ăš temporaneamente disabilitato, contatta l'amministratore o riprova piĂč tardi.",
"invalidPasswordMinLengthMessage": "Password non valida: lunghezza minima {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Password non valida: deve contenere almeno {0} caratteri minuscoli.",
"invalidPasswordMinDigitsMessage": "Password non valida: deve contenere almeno {0} numeri.",
"invalidPasswordMinUpperCaseCharsMessage": "Password non valida: deve contenere almeno {0} caratteri maiuscoli.",
"invalidPasswordMinSpecialCharsMessage": "Password non valida: deve contenere almeno {0} caratteri speciali.",
"invalidPasswordNotUsernameMessage": "Password non valida: non deve essere uguale allo username.",
"invalidPasswordRegexPatternMessage": "Password non valida: fallito il match con una o piĂč espressioni regolari.",
"invalidPasswordHistoryMessage": "Password non valida: non deve essere uguale a una delle ultime {0} password.",
"invalidPasswordBlacklistedMessage": "Password non valida: la password non Ăš consentita.",
"invalidPasswordGenericMessage": "Password non valida: la nuova password non rispetta le indicazioni previste.",
"myResources": "Le mie risorse",
"myResourcesSub": "Le mie risorse",
"doDeny": "Nega",
"doRevoke": "Revoca",
"doApprove": "Approva",
"doRemoveSharing": "Rimuovi condivisione",
"doRemoveRequest": "Rimuovi richiesta",
"peopleAccessResource": "Persone che hanno accesso a questa risorsa",
"resourceManagedPolicies": "Permessi che danno accesso a questa risorsa",
"resourceNoPermissionsGrantingAccess": "Nessun permesso dĂ  accesso a questa risorsa",
"anyAction": "Qualsiasi azione",
"description": "Descrizione",
"name": "Nome",
"scopes": "Ambito",
"resource": "Risorsa",
"user": "Utente",
"peopleSharingThisResource": "Persone che condividono questa risorsa",
"shareWithOthers": "Condividi con altri",
"needMyApproval": "Richiede la mia approvazione",
"requestsWaitingApproval": "La tua richiesta Ăš in attesa di approvazione",
"icon": "Icona",
"requestor": "Richiedente",
"owner": "Proprietario",
"resourcesSharedWithMe": "Risorse condivise con me",
"permissionRequestion": "Richiesta di permesso",
"permission": "Permesso",
"shares": "condivisioni",
"notBeingShared": "Questa risorsa non Ăš in condivisione.",
"notHaveAnyResource": "Non hai nessuna risorsa",
"noResourcesSharedWithYou": "Non ci sono risorse condivise con te",
"havePermissionRequestsWaitingForApproval": "Hai {0} richiesta(e) di permesso in attesa di approvazione.",
"clickHereForDetails": "Clicca qui per i dettagli.",
"resourceIsNotBeingShared": "La risorsa non Ăš in condivisione",
"locale_it": "Italiano",
"applicaitonName": "Nome",
"applicationType": "Tipo applicazione",
"applicationInUse": "In-use app only",
"clearAllFilter": "Azzera tutti i filtri",
"activeFilters": "Filtri attivi",
"filterByName": "Filtra per nome ...",
"allApps": "Tutte le applicazioni",
"internalApps": "Applicazioni interne",
"thirdpartyApps": "Applicazioni di terze parti",
"appResults": "Risultati",
"clientNotFoundMessage": "Client non trovato.",
"authorizedProvider": "Provider autorizzato",
"authorizedProviderMessage": "Provider autorizzati collegati al tuo account",
"identityProvider": "Identity provider",
"identityProviderMessage": "Collegare il tuo account con gli identity provider che hai configurato",
"socialLogin": "Social Login",
"userDefined": "Definito dall'utente",
"removeAccess": "Rimuovi accesso",
"removeAccessMessage": "Devi concedere di nuovo l'accesso, se vuoi utilizzare l'account di questa applicazione.",
"authenticatorStatusMessage": "L'autenticazione a due fattori Ăš attualmente",
"authenticatorFinishSetUpTitle": "La tua autenticazione a due fattori",
"authenticatorFinishSetUpMessage":
"Ogni volta che effettui l'accesso al tuo account Keycloak, ti verrĂ  richiesto di fornire il tuo codice di autenticazione a due fattori.",
"authenticatorSubTitle": "Imposta l'autenticazione a due fattori",
"authenticatorSubMessage":
"Per incrementare la sicurezza del tuo account, attiva almeno uno dei metodi disponibili per l'autenticazione a due fattori.",
"authenticatorMobileTitle": "Autenticatore mobile",
"authenticatorMobileMessage": "Utilizza l'autenticatore mobile per ottenere i codici di verifica per l'autenticazione a due fattori.",
"authenticatorMobileFinishSetUpMessage": "L'autenticatore Ăš stato collegato al tuo telefono.",
"authenticatorActionSetup": "Set up",
"authenticatorSMSTitle": "Codice SMS",
"authenticatorSMSMessage": "Keycloak invierĂ  il codice di verifica al tuo telefono per l'autenticazione a due fattori.",
"authenticatorSMSFinishSetUpMessage": "I messaggi di testo vengono inviati a",
"authenticatorDefaultStatus": "Default",
"authenticatorChangePhone": "Cambia numero di telefono",
"authenticatorBackupCodesTitle": "Codici di backup",
"authenticatorBackupCodesMessage": "Ottieni i tuoi codici di backup a otto cifre",
"authenticatorBackupCodesFinishSetUpMessage": "Sono stati generati dodici codici di backup. Ognuno puĂČ essere usato una sola volta.",
"authenticatorMobileSetupTitle": "Setup autenticatore mobile",
"smscodeIntroMessage": "Inserisci il tuo numero di telefono e ti verrĂ  inviato un codice di verifica.",
"mobileSetupStep1": "Installa un'applicazione di autenticazione sul tuo telefono. Sono supportate le applicazioni qui elencate.",
"mobileSetupStep2": "Apri l'applicazione e scansiona il codice QR:",
"mobileSetupStep3": "Inserisci il codice monouso fornito dall'applicazione e clicca Salva per completare il setup.",
"scanBarCode": "Vuoi scansionare il codice QR?",
"enterBarCode": "Inserisci il codice monouso",
"doCopy": "Copia",
"doFinish": "Termina",
"authenticatorSMSCodeSetupTitle": "Setup codice SMS",
"chooseYourCountry": "Scegli la tua nazione",
"enterYourPhoneNumber": "Inserisci il tuo numero di telefono",
"sendVerficationCode": "Invia il codice di verifica",
"enterYourVerficationCode": "Inserisci il codice di verifica",
"authenticatorBackupCodesSetupTitle": "Setup backup codici",
"backupcodesIntroMessage":
"Se non disponi piĂč del tuo telefono, puoi comunque accedere al tuo account attraverso i codici di backup. Conservali in un posto sicuro e accessibile.",
"realmName": "Realm",
"doDownload": "Download",
"doPrint": "Stampa",
"backupCodesTips-1": "Ogni codice di backup puĂČ essere usato una sola volta.",
"backupCodesTips-2": "Questi codici sono stati generati il",
"generateNewBackupCodes": "Genera dei nuovi codici di backup",
"backupCodesTips-3": "Quando generi dei nuovi codici di backup, quelli attuali non funzioneranno piĂč.",
"backtoAuthenticatorPage": "Torna alla pagina dell'autenticatore",
"resources": "Risorse",
"sharedwithMe": "Condiviso con me",
"share": "Condiviso",
"sharedwith": "Condiviso con",
"accessPermissions": "Permessi di accesso",
"permissionRequests": "Richieste di permesso",
"approve": "Approva",
"approveAll": "Approva tutti",
"people": "persone",
"perPage": "per pagina",
"currentPage": "Pagina corrente",
"sharetheResource": "Condividi la risorsa",
"group": "Gruppo",
"selectPermission": "Seleziona permessi",
"addPeople": "Aggiungi persone con le quali condividere la tua risorsa",
"addTeam": "Aggiungi gruppi con i quali condividere la tua risorsa",
"myPermissions": "Miei permessi",
"waitingforApproval": "Attesa dell'approvazione",
"anyPermission": "Qualsiasi permesso",
"openshift.scope.user_info": "Informazioni utente",
"openshift.scope.user_check-access": "Informazioni per l'accesso dell'utente",
"openshift.scope.user_full": "Accesso completo",
"openshift.scope.list-projects": "Elenca progetti"
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,324 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "保歘",
"doCancel": "ă‚­ăƒŁăƒłă‚»ăƒ«",
"doLogOutAllSessions": "ć…šă‚»ăƒƒă‚·ăƒ§ăƒłă‹ă‚‰ăƒ­ă‚°ă‚ąă‚Šăƒˆ",
"doRemove": "扊陀",
"doAdd": "èżœćŠ ",
"doSignOut": "ă‚”ă‚€ăƒłă‚ąă‚Šăƒˆ",
"doLogIn": "ăƒ­ă‚°ă‚€ăƒł",
"doLink": "ăƒȘンク",
"editAccountHtmlTitle": "ă‚ąă‚«ă‚Šăƒłăƒˆăźç·šé›†",
"personalInfoHtmlTitle": "怋äșșæƒ…ć ±",
"federatedIdentitiesHtmlTitle": "連æșæžˆăżă‚ąă‚€ăƒ‡ăƒłăƒ†ă‚Łăƒ†ă‚ŁăƒŒ",
"accountLogHtmlTitle": "ă‚ąă‚«ă‚Šăƒłăƒˆăƒ­ă‚°",
"changePasswordHtmlTitle": "パă‚čăƒŻăƒŒăƒ‰ć€‰æ›Ž",
"deviceActivityHtmlTitle": "ăƒ‡ăƒă‚€ă‚čăƒ»ă‚ąă‚Żăƒ†ă‚Łăƒ“ăƒ†ă‚ŁăƒŒ",
"sessionsHtmlTitle": "ă‚»ăƒƒă‚·ăƒ§ăƒł",
"accountManagementTitle": "Keycloakă‚ąă‚«ă‚ŠăƒłăƒˆçźĄç†",
"authenticatorTitle": "ă‚ȘăƒŒă‚»ăƒłăƒ†ă‚Łă‚±ăƒŒă‚żăƒŒ",
"applicationsHtmlTitle": "ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒł",
"linkedAccountsHtmlTitle": "ăƒȘăƒłă‚Żă•ă‚ŒăŸă‚ąă‚«ă‚Šăƒłăƒˆ",
"accountManagementWelcomeMessage": "Keycloakă‚ąă‚«ă‚ŠăƒłăƒˆçźĄç†ăžă‚ˆă†ă“ă",
"personalInfoIntroMessage": "ćŸșæœŹæƒ…ć ±ă‚’çźĄç†ă™ă‚‹",
"accountSecurityTitle": "ă‚ąă‚«ă‚Šăƒłăƒˆăƒ»ă‚»ă‚­ăƒ„ăƒȘăƒ†ă‚ŁăƒŒ",
"accountSecurityIntroMessage": "パă‚čăƒŻăƒŒăƒ‰ăšă‚ąă‚«ă‚Šăƒłăƒˆăƒ»ă‚ąă‚Żă‚»ă‚čă‚’ćˆ¶ćŸĄă™ă‚‹",
"applicationsIntroMessage": "ă‚ąă‚«ă‚Šăƒłăƒˆăžă‚ąă‚Żă‚»ă‚čă™ă‚‹ăŸă‚ă«ă‚ąăƒ—ăƒȘăźăƒ‘ăƒŒăƒŸăƒƒă‚·ăƒ§ăƒłă‚’èżœè·Ąă—ăŠçźĄç†ă™ă‚‹",
"resourceIntroMessage": "ăƒăƒŒăƒ ăƒĄăƒłăƒăƒŒé–“ă§ăƒȘă‚œăƒŒă‚čă‚’ć…±æœ‰ă™ă‚‹",
"passwordLastUpdateMessage": "パă‚čăƒŻăƒŒăƒ‰ăŻæ›Žæ–°ă•ă‚ŒăŸă—ăŸ",
"updatePasswordTitle": "パă‚čăƒŻăƒŒăƒ‰ăźæ›Žæ–°",
"updatePasswordMessageTitle": "ćŒ·ćŠ›ăȘパă‚čăƒŻăƒŒăƒ‰ă‚’éžæŠžă—ăŠăă ă•ă„",
"updatePasswordMessage":
"ćŒ·ćŠ›ăȘパă‚čăƒŻăƒŒăƒ‰ăŻă€æ•°ć­—ă€æ–‡ć­—ă€èš˜ć·ă‚’ć«ăżăŸă™ă€‚æŽšæžŹăŒé›Łă—ăă€ćźŸćœšă™ă‚‹èš€è‘‰ă«äŒŒăŠăŠă‚‰ăšă€ă“ăźă‚ąă‚«ă‚Šăƒłăƒˆă ă‘ă§äœżç”šă•ă‚ŒăŠă„ăŸă™ă€‚",
"personalSubTitle": "怋äșșæƒ…ć ±",
"personalSubMessage": "こぼćŸșæœŹæƒ…ć ±ă‚’çźĄç†ă—ăŠăă ă•ă„ïŒšćă€ć§“ă€ăƒĄăƒŒăƒ«",
"authenticatorCode": "ăƒŻăƒłă‚żă‚€ăƒ ă‚łăƒŒăƒ‰",
"email": "EăƒĄăƒŒăƒ«",
"firstName": "損",
"givenName": "損",
"fullName": "æ°ć",
"lastName": "槓",
"familyName": "槓",
"password": "パă‚čăƒŻăƒŒăƒ‰",
"currentPassword": "çŸćœšăźăƒ‘ă‚čăƒŻăƒŒăƒ‰",
"passwordConfirm": "æ–°ă—ă„ăƒ‘ă‚čăƒŻăƒŒăƒ‰ïŒˆçąșèȘïŒ‰",
"passwordNew": "æ–°ă—ă„ăƒ‘ă‚čăƒŻăƒŒăƒ‰",
"username": "ăƒŠăƒŒă‚¶ăƒŒć",
"address": "䜏所",
"street": "ç•Ș㜰",
"locality": "澂ćŒșç”ș村",
"region": "郜道ćșœçœŒ",
"postal_code": "éƒ”äŸżç•Șć·",
"country": "ć›œ",
"emailVerified": "çąșèȘæžˆăżEăƒĄăƒŒăƒ«",
"gssDelegationCredential": "GSS槔è­Čă‚ŻăƒŹăƒ‡ăƒłă‚·ăƒŁăƒ«",
"profileScopeConsentText": "ăƒŠăƒŒă‚¶ăƒŒăƒ»ăƒ—ăƒ­ăƒ•ă‚Ąă‚€ăƒ«",
"emailScopeConsentText": "ăƒĄăƒŒăƒ«ă‚ąăƒ‰ăƒŹă‚č",
"addressScopeConsentText": "ケドレă‚č",
"phoneScopeConsentText": "電話ç•Șć·",
"offlineAccessScopeConsentText": "ă‚Șăƒ•ăƒ©ă‚€ăƒłăƒ»ă‚ąă‚Żă‚»ă‚č",
"samlRoleListScopeConsentText": "ăƒ­ăƒŒăƒ«",
"rolesScopeConsentText": "ăƒŠăƒŒă‚¶ăƒŒăƒ­ăƒŒăƒ«",
"role_admin": "çźĄç†è€…",
"role_realm-admin": "ăƒŹăƒ«ăƒ çźĄç†è€…",
"role_create-realm": "ăƒŹăƒ«ăƒ ăźäœœæˆ",
"role_view-realm": "ăƒŹăƒ«ăƒ ăźć‚ç…§",
"role_view-users": "ăƒŠăƒŒă‚¶ăƒŒăźć‚ç…§",
"role_view-applications": "ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłăźć‚ç…§",
"role_view-clients": "ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆăźć‚ç…§",
"role_view-events": "ă‚€ăƒ™ăƒłăƒˆăźć‚ç…§",
"role_view-identity-providers": "ă‚ąă‚€ăƒ‡ăƒłăƒ†ă‚Łăƒ†ă‚ŁăƒŒăƒ»ăƒ—ăƒ­ăƒă‚€ăƒ€ăƒŒăźć‚ç…§",
"role_view-consent": "ćŒæ„ăźć‚ç…§",
"role_manage-realm": "ăƒŹăƒ«ăƒ ăźçźĄç†",
"role_manage-users": "ăƒŠăƒŒă‚¶ăƒŒăźçźĄç†",
"role_manage-applications": "ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłăźçźĄç†",
"role_manage-identity-providers": "ă‚ąă‚€ăƒ‡ăƒłăƒ†ă‚Łăƒ†ă‚ŁăƒŒăƒ»ăƒ—ăƒ­ăƒă‚€ăƒ€ăƒŒăźçźĄç†",
"role_manage-clients": "ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆăźçźĄç†",
"role_manage-events": "ă‚€ăƒ™ăƒłăƒˆăźçźĄç†",
"role_view-profile": "ăƒ—ăƒ­ăƒ•ă‚Ąă‚€ăƒ«ăźć‚ç…§",
"role_manage-account": "ă‚ąă‚«ă‚ŠăƒłăƒˆăźçźĄç†",
"role_manage-account-links": "ă‚ąă‚«ă‚ŠăƒłăƒˆăƒȘンクぼ缡理",
"role_manage-consent": "ćŒæ„ăźçźĄç†",
"role_read-token": "ăƒˆăƒŒă‚Żăƒłăźć‚ç…§",
"role_offline-access": "ă‚Șăƒ•ăƒ©ă‚€ăƒłăƒ»ă‚ąă‚Żă‚»ă‚č",
"role_uma_authorization": "ăƒ‘ăƒŒăƒŸăƒƒă‚·ăƒ§ăƒłăźć–ćŸ—",
"client_account": "ă‚ąă‚«ă‚Šăƒłăƒˆ",
"client_account-console": "ă‚ąă‚«ă‚Šăƒłăƒˆăƒ»ă‚łăƒłă‚œăƒŒăƒ«",
"client_security-admin-console": "ă‚»ă‚­ăƒ„ăƒȘăƒ†ă‚ŁăƒŒçźĄç†ă‚łăƒłă‚œăƒŒăƒ«",
"client_admin-cli": "缡理CLI",
"client_realm-management": "ăƒŹăƒ«ăƒ çźĄç†",
"client_broker": "ăƒ–ăƒ­ăƒŒă‚«ăƒŒ",
"requiredFields": "濅須",
"allFieldsRequired": "ć…šăŠăźć…„ćŠ›é …ç›źăŒćż…é ˆ",
"backToApplication": "&laquo; ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłă«æˆ»ă‚‹",
"backTo": "{0}ă«æˆ»ă‚‹",
"date": "旄付",
"event": "ă‚€ăƒ™ăƒłăƒˆ",
"ip": "IP",
"client": "ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆ",
"clients": "ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆ",
"details": "è©łçŽ°",
"started": "開構",
"lastAccess": "æœ€ç”‚ă‚ąă‚Żă‚»ă‚č",
"expires": "有ćŠč期限",
"applications": "ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒł",
"account": "ă‚ąă‚«ă‚Šăƒłăƒˆ",
"federatedIdentity": "連æșæžˆăżă‚ąă‚€ăƒ‡ăƒłăƒ†ă‚Łăƒ†ă‚ŁăƒŒ",
"authenticator": "ă‚ȘăƒŒă‚»ăƒłăƒ†ă‚Łă‚±ăƒŒă‚żăƒŒ",
"device-activity": "ăƒ‡ăƒă‚€ă‚čăƒ»ă‚ąă‚Żăƒ†ă‚Łăƒ“ăƒ†ă‚ŁăƒŒ",
"sessions": "ă‚»ăƒƒă‚·ăƒ§ăƒł",
"log": "ログ",
"application": "ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒł",
"availableRoles": "ćˆ©ç”šćŻèƒœăȘăƒ­ăƒŒăƒ«",
"grantedPermissions": "èš±ćŻă•ă‚ŒăŸăƒ‘ăƒŒăƒŸăƒƒă‚·ăƒ§ăƒł",
"grantedPersonalInfo": "èš±ćŻă•ă‚ŒăŸć€‹äșșæƒ…ć ±",
"additionalGrants": "èżœćŠ ăźèš±ćŻ",
"action": "ă‚ąă‚Żă‚·ăƒ§ăƒł",
"inResource": "in",
"fullAccess": "ăƒ•ăƒ«ă‚ąă‚Żă‚»ă‚č",
"offlineToken": "ă‚Șăƒ•ăƒ©ă‚€ăƒłăƒ»ăƒˆăƒŒă‚Żăƒł",
"revoke": "èš±ćŻăźć–ă‚Šæ¶ˆă—",
"configureAuthenticators": "èš­ćźšæžˆăżăźă‚ȘăƒŒă‚»ăƒłăƒ†ă‚Łă‚±ăƒŒă‚żăƒŒ",
"mobile": "ăƒąăƒă‚€ăƒ«",
"totpStep1": "ăƒąăƒă‚€ăƒ«ă«ä»„äž‹ăźă‚ąăƒ—ăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłăźă„ăšă‚Œă‹ă‚’ă‚€ăƒłă‚čăƒˆăƒŒăƒ«ă—ăŠăă ă•ă„ă€‚",
"totpStep2": "ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłă‚’é–‹ăă€ăƒăƒŒă‚łăƒŒăƒ‰ă‚’ă‚čキャンしどください。",
"totpStep3": "ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłă§æäŸ›ă•ă‚ŒăŸăƒŻăƒłă‚żă‚€ăƒ ă‚łăƒŒăƒ‰ă‚’ć…„ćŠ›ă—ăŠäżć­˜ă‚’ă‚ŻăƒȘăƒƒă‚Żă—ă€ă‚»ăƒƒăƒˆă‚ąăƒƒăƒ—ă‚’ćźŒäș†ă—ăŠăă ă•ă„ă€‚",
"totpStep3DeviceName": "OTPăƒ‡ăƒă‚€ă‚čた知理にćœčç«‹ă€ă‚ˆă†ăȘăƒ‡ăƒă‚€ă‚čćă‚’æŒ‡ćźšă—ăŠăă ă•ă„ă€‚",
"totpManualStep2": "ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłă‚’é–‹ăă€ă‚­ăƒŒă‚’ć…„ćŠ›ă—ăŠăă ă•ă„ă€‚",
"totpManualStep3": "ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłăŒèš­ćźšă§ăă‚‹ć ŽćˆăŻă€æŹĄăźèš­ćźšć€€ă‚’äœżç”šă—ăŠăă ă•ă„ă€‚",
"totpUnableToScan": "ă‚čă‚­ăƒŁăƒłă§ăăŸă›ă‚“ă‹ïŒŸ",
"totpScanBarcode": "ăƒăƒŒă‚łăƒŒăƒ‰ă‚’ă‚čă‚­ăƒŁăƒłă—ăŸă™ă‹ïŒŸ",
"totp.totp": "æ™‚é–“ăƒ™ăƒŒă‚č",
"totp.hotp": "ă‚«ă‚Šăƒłă‚żăƒŒăƒ™ăƒŒă‚č",
"totpType": "ă‚żă‚€ăƒ—",
"totpAlgorithm": "ă‚ąăƒ«ă‚ŽăƒȘă‚șム",
"totpDigits": "æ•°ć­—",
"totpInterval": "間隔",
"totpCounter": "ă‚«ă‚Šăƒłă‚żăƒŒ",
"totpDeviceName": "ăƒ‡ăƒă‚€ă‚č損",
"missingUsernameMessage": "ăƒŠăƒŒă‚¶ăƒŒćă‚’ć…„ćŠ›ă—ăŠăă ă•ă„ă€‚",
"missingFirstNameMessage": "ćă‚’ć…„ćŠ›ă—ăŠăă ă•ă„ă€‚",
"invalidEmailMessage": "無ćŠčăȘăƒĄăƒŒăƒ«ă‚ąăƒ‰ăƒŹă‚čです。",
"missingLastNameMessage": "ć§“ă‚’ć…„ćŠ›ă—ăŠăă ă•ă„ă€‚",
"missingEmailMessage": "EăƒĄăƒŒăƒ«ă‚’ć…„ćŠ›ă—ăŠăă ă•ă„ă€‚",
"missingPasswordMessage": "パă‚čăƒŻăƒŒăƒ‰ă‚’ć…„ćŠ›ă—ăŠăă ă•ă„ă€‚",
"notMatchPasswordMessage": "パă‚čăƒŻăƒŒăƒ‰ăŒäž€è‡Žă—ăŠă„ăŸă›ă‚“ă€‚",
"invalidUserMessage": "無ćŠčăȘăƒŠăƒŒă‚¶ăƒŒă§ă™ă€‚",
"missingTotpMessage": "ă‚ȘăƒŒă‚»ăƒłăƒ†ă‚Łă‚±ăƒŒă‚żăƒŒăƒ»ă‚łăƒŒăƒ‰ă‚’ć…„ćŠ›ă—ăŠăă ă•ă„ă€‚",
"missingTotpDeviceNameMessage": "ăƒ‡ăƒă‚€ă‚čćă‚’æŒ‡ćźšă—ăŠăă ă•ă„ă€‚",
"invalidPasswordExistingMessage": "æ—ąć­˜ăźăƒ‘ă‚čăƒŻăƒŒăƒ‰ăŒäžæ­Łă§ă™ă€‚",
"invalidPasswordConfirmMessage": "æ–°ă—ă„ăƒ‘ă‚čăƒŻăƒŒăƒ‰ïŒˆçąșèȘïŒ‰ăšäž€è‡Žă—ăŠă„ăŸă›ă‚“ă€‚",
"invalidTotpMessage": "無ćŠčăȘă‚ȘăƒŒă‚»ăƒłăƒ†ă‚Łă‚±ăƒŒă‚żăƒŒăƒ»ă‚łăƒŒăƒ‰ă§ă™ă€‚",
"usernameExistsMessage": "æ—ąă«ć­˜ćœšă™ă‚‹ăƒŠăƒŒă‚¶ăƒŒćă§ă™ă€‚",
"emailExistsMessage": "æ—ąă«ć­˜ćœšă™ă‚‹EăƒĄăƒŒăƒ«ă§ă™ă€‚",
"readOnlyUserMessage": "èȘ­ăżć–ă‚Šć°‚ç”šăźăŸă‚ă€ă‚ąă‚«ă‚Šăƒłăƒˆă‚’æ›Žæ–°ă™ă‚‹ă“ăšăŻă§ăăŸă›ă‚“ă€‚",
"readOnlyUsernameMessage": "èȘ­ăżć–ă‚Šć°‚ç”šăźăŸă‚ă€ăƒŠăƒŒă‚¶ăƒŒćă‚’æ›Žæ–°ă™ă‚‹ă“ăšăŻă§ăăŸă›ă‚“ă€‚",
"readOnlyPasswordMessage": "èȘ­ăżć–ă‚Šć°‚ç”šăźăŸă‚ă€ăƒ‘ă‚čăƒŻăƒŒăƒ‰ă‚’æ›Žæ–°ă™ă‚‹ă“ăšăŻă§ăăŸă›ă‚“ă€‚",
"successTotpMessage": "ăƒąăƒă‚€ăƒ«ăƒ»ă‚ȘăƒŒă‚»ăƒłăƒ†ă‚Łă‚±ăƒŒă‚żăƒŒăŒèš­ćźšă•ă‚ŒăŸă—ăŸă€‚",
"successTotpRemovedMessage": "ăƒąăƒă‚€ăƒ«ăƒ»ă‚ȘăƒŒă‚»ăƒłăƒ†ă‚Łă‚±ăƒŒă‚żăƒŒăŒć‰Šé™€ă•ă‚ŒăŸă—ăŸă€‚",
"successGrantRevokedMessage": "èš±ćŻăŒæ­Łćžžă«ć–ă‚Šæ¶ˆă—ă•ă‚ŒăŸă—ăŸă€‚",
"accountUpdatedMessage": "ă‚ąă‚«ă‚ŠăƒłăƒˆăŒæ›Žæ–°ă•ă‚ŒăŸă—ăŸă€‚",
"accountPasswordUpdatedMessage": "パă‚čăƒŻăƒŒăƒ‰ăŒæ›Žæ–°ă•ă‚ŒăŸă—ăŸă€‚",
"missingIdentityProviderMessage": "ă‚ąă‚€ăƒ‡ăƒłăƒ†ă‚Łăƒ†ă‚ŁăƒŒăƒ»ăƒ—ăƒ­ăƒă‚€ăƒ€ăƒŒăŒæŒ‡ćźšă•ă‚ŒăŠă„ăŸă›ă‚“ă€‚",
"invalidFederatedIdentityActionMessage": "無ćŠčăŸăŸăŻć­˜ćœšă—ăȘă„ă‚ąă‚Żă‚·ăƒ§ăƒłă§ă™ă€‚",
"identityProviderNotFoundMessage": "æŒ‡ćźšă•ă‚ŒăŸă‚ąă‚€ăƒ‡ăƒłăƒ†ă‚Łăƒ†ă‚ŁăƒŒăƒ»ăƒ—ăƒ­ăƒă‚€ăƒ€ăƒŒăŒèŠ‹ă€ă‹ă‚ŠăŸă›ă‚“ă€‚",
"federatedIdentityLinkNotActiveMessage": "ă“ăźă‚ąă‚€ăƒ‡ăƒłăƒ†ă‚Łăƒ†ă‚ŁăƒŒăŻæœ‰ćŠčă§ăŻă‚ă‚ŠăŸă›ă‚“ă€‚",
"federatedIdentityRemovingLastProviderMessage": "パă‚čăƒŻăƒŒăƒ‰ăŒăȘă„ăŸă‚ă€æœ€ćŸŒăźé€Łæșæžˆăżă‚ąă‚€ăƒ‡ăƒłăƒ†ă‚Łăƒ†ă‚ŁăƒŒăŒć‰Šé™€ă§ăăŸă›ă‚“ă€‚",
"identityProviderRedirectErrorMessage": "ă‚ąă‚€ăƒ‡ăƒłăƒ†ă‚Łăƒ†ă‚ŁăƒŒăƒ»ăƒ—ăƒ­ăƒă‚€ăƒ€ăƒŒăžăźăƒȘăƒ€ă‚€ăƒŹă‚Żăƒˆă«ć€±æ•—ă—ăŸă—ăŸă€‚",
"identityProviderRemovedMessage": "ă‚ąă‚€ăƒ‡ăƒłăƒ†ă‚Łăƒ†ă‚ŁăƒŒăƒ»ăƒ—ăƒ­ăƒă‚€ăƒ€ăƒŒăŒæ­Łćžžă«ć‰Šé™€ă•ă‚ŒăŸă—ăŸă€‚",
"identityProviderAlreadyLinkedMessage": "{0}ă‹ă‚‰èż”ă•ă‚ŒăŸé€Łæșæžˆăżă‚ąă‚€ăƒ‡ăƒłăƒ†ă‚Łăƒ†ă‚ŁăƒŒăŻæ—ąă«ä»–ăźăƒŠăƒŒă‚¶ăƒŒă«é–ąé€Łä»˜ă‘ă•ă‚ŒăŠă„ăŸă™ă€‚",
"staleCodeAccountMessage": "有ćŠčæœŸé™ćˆ‡ă‚Œă§ă™ă€‚ć†ćșŠăŠè©Šă—ăă ă•ă„ă€‚",
"consentDenied": "ćŒæ„ăŒæ‹’ćŠă•ă‚ŒăŸă—ăŸă€‚",
"accountDisabledMessage": "ă‚ąă‚«ă‚ŠăƒłăƒˆăŒç„ĄćŠčă§ă™ă€‚çźĄç†è€…ă«é€Łç”Ąă—ăŠăă ă•ă„ă€‚",
"accountTemporarilyDisabledMessage": "ă‚ąă‚«ă‚ŠăƒłăƒˆăŒäž€æ™‚çš„ă«ç„ĄćŠčă§ă™ă€‚çźĄç†è€…ă«é€Łç”Ąă™ă‚‹ă‹ă€ă—ă°ă‚‰ăæ™‚é–“ă‚’ăŠă„ăŠă‹ă‚‰ć†ćșŠăŠè©Šă—ăă ă•ă„ă€‚",
"invalidPasswordMinLengthMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: æœ€ć°{0}ăźé•·ă•ăŒćż…èŠă§ă™ă€‚",
"invalidPasswordMinLowerCaseCharsMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: 民ăȘくべも{0}æ–‡ć­—ăźć°æ–‡ć­—ă‚’ć«ă‚€ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"invalidPasswordMinDigitsMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: 民ăȘくべも{0}æ–‡ć­—ăźæ•°ć­—ă‚’ć«ă‚€ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"invalidPasswordMinUpperCaseCharsMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰:民ăȘくべも{0}æ–‡ć­—ăźć€§æ–‡ć­—ă‚’ć«ă‚€ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"invalidPasswordMinSpecialCharsMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: 民ăȘくべも{0}æ–‡ć­—ăźç‰čæźŠæ–‡ć­—ă‚’ć«ă‚€ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"invalidPasswordNotUsernameMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: ăƒŠăƒŒă‚¶ăƒŒćăšćŒă˜ăƒ‘ă‚čăƒŻăƒŒăƒ‰ăŻçŠæ­ąă•ă‚ŒăŠă„ăŸă™ă€‚",
"invalidPasswordRegexPatternMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: æ­ŁèŠèĄšçŸăƒ‘ă‚żăƒŒăƒłăšäž€è‡Žă—ăŸă›ă‚“ă€‚",
"invalidPasswordHistoryMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: æœ€èż‘ăź{0}パă‚čăƒŻăƒŒăƒ‰ăźă„ăšă‚Œă‹ăšćŒă˜ăƒ‘ă‚čăƒŻăƒŒăƒ‰ăŻçŠæ­ąă•ă‚ŒăŠă„ăŸă™ă€‚",
"invalidPasswordBlacklistedMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: パă‚čăƒŻăƒŒăƒ‰ăŒăƒ–ăƒ©ăƒƒă‚ŻăƒȘă‚čăƒˆă«ć«ăŸă‚ŒăŠă„ăŸă™ă€‚",
"invalidPasswordGenericMessage": "無ćŠčăȘパă‚čăƒŻăƒŒăƒ‰: æ–°ă—ă„ăƒ‘ă‚čăƒŻăƒŒăƒ‰ăŻăƒ‘ă‚čăƒŻăƒŒăƒ‰ăƒ»ăƒăƒȘă‚·ăƒŒăšäž€è‡Žă—ăŸă›ă‚“ă€‚",
"myResources": "ăƒžă‚€ăƒȘă‚œăƒŒă‚č",
"myResourcesSub": "ăƒžă‚€ăƒȘă‚œăƒŒă‚č",
"doDeny": "æ‹’ćŠ",
"doRevoke": "ć–ă‚Šæ¶ˆă—",
"doApprove": "æ‰żèȘ",
"doRemoveSharing": "ć…±æœ‰ăźć‰Šé™€",
"doRemoveRequest": "èŠæ±‚ăźć‰Šé™€",
"peopleAccessResource": "こぼăƒȘă‚œăƒŒă‚čにスクセă‚čできるäșș",
"resourceManagedPolicies": "こぼăƒȘă‚œăƒŒă‚čぞたスクセă‚čă‚’èš±ćŻă™ă‚‹ăƒ‘ăƒŒăƒŸăƒƒă‚·ăƒ§ăƒł",
"resourceNoPermissionsGrantingAccess": "こぼăƒȘă‚œăƒŒă‚čぞたスクセă‚čă‚’èš±ćŻă™ă‚‹æš©é™ăŻă‚ă‚ŠăŸă›ă‚“",
"anyAction": "ä»»æ„ăźă‚ąă‚Żă‚·ăƒ§ăƒł",
"description": "èȘŹæ˜Ž",
"name": "損才",
"scopes": "ă‚čă‚łăƒŒăƒ—",
"resource": "ăƒȘă‚œăƒŒă‚č",
"user": "ăƒŠăƒŒă‚¶ăƒŒ",
"peopleSharingThisResource": "こぼăƒȘă‚œăƒŒă‚čă‚’ć…±æœ‰ă—ăŠă„ă‚‹äșș",
"shareWithOthers": "他äșșăšć…±æœ‰",
"needMyApproval": "æ‰żèȘăŒćż…èЁ",
"requestsWaitingApproval": "æ‰żèȘćŸ…ăĄăźèŠæ±‚",
"icon": "ă‚ąă‚€ă‚łăƒł",
"requestor": "芁求者",
"owner": "ă‚ȘăƒŒăƒŠăƒŒ",
"resourcesSharedWithMe": "ć…±æœ‰ă—ăŠă„ă‚‹ăƒȘă‚œăƒŒă‚č",
"permissionRequestion": "ăƒ‘ăƒŒăƒŸăƒƒă‚·ăƒ§ăƒłăźèŠæ±‚",
"permission": "ăƒ‘ăƒŒăƒŸăƒƒă‚·ăƒ§ăƒł",
"shares": "ć…±æœ‰ïŒˆè€‡æ•°ïŒ‰",
"notBeingShared": "こぼăƒȘă‚œăƒŒă‚čăŻć…±æœ‰ă•ă‚ŒăŠă„ăŸă›ă‚“ă€‚",
"notHaveAnyResource": "ăƒȘă‚œăƒŒă‚čăŒă‚ă‚ŠăŸă›ă‚“ă€‚",
"noResourcesSharedWithYou": "ć…±æœ‰ă—ăŠă„ă‚‹ăƒȘă‚œăƒŒă‚čăŻă‚ă‚ŠăŸă›ă‚“",
"havePermissionRequestsWaitingForApproval": "æ‰żèȘă‚’ćŸ…ăŁăŠă„ă‚‹{0}ć€‹ăźăƒ‘ăƒŒăƒŸăƒƒă‚·ăƒ§ăƒłăźèŠæ±‚ăŒă‚ă‚ŠăŸă™ă€‚",
"clickHereForDetails": "è©łçŽ°ăŻă“ăĄă‚‰ă‚’ă‚ŻăƒȘックしどください。",
"resourceIsNotBeingShared": "ăƒȘă‚œăƒŒă‚čăŻć…±æœ‰ă•ă‚ŒăŠă„ăŸă›ă‚“ă€‚",
"locale_ca": "CatalĂ ",
"locale_de": "Deutsch",
"locale_en": "English",
"locale_es": "Español",
"locale_fr": "Français",
"locale_it": "Italian",
"locale_ja": "æ—„æœŹèȘž",
"locale_nl": "Nederlands",
"locale_no": "Norsk",
"locale_lt": "LietuviĆł",
"locale_pt-BR": "PortuguĂȘs (Brasil)",
"locale_ru": "РуссĐșĐžĐč",
"locale_sk": "Slovenčina",
"locale_sv": "Svenska",
"locale_tr": "Turkish",
"locale_zh-CN": "äž­æ–‡çź€äœ“",
"applicaitonName": "損才",
"applicationType": "ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłăƒ»ă‚żă‚€ăƒ—",
"applicationInUse": "äœżç”šäž­ăźă‚ąăƒ—ăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłăźăż",
"clearAllFilter": "すăčăŠăźăƒ•ă‚Łăƒ«ă‚żăƒŒă‚’ă‚ŻăƒȘケ",
"activeFilters": "ケクティブăȘăƒ•ă‚Łăƒ«ă‚żăƒŒ",
"filterByName": "ćć‰ă§ăƒ•ă‚Łăƒ«ă‚żăƒȘング...",
"allApps": "すăčどぼケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒł",
"internalApps": "憅郹ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒł",
"thirdpartyApps": "ă‚”ăƒŒăƒ‰ăƒ‘ăƒŒăƒ†ă‚ŁăƒŒăźă‚ąăƒ—ăƒȘă‚±ăƒŒă‚·ăƒ§ăƒł",
"appResults": "甐果",
"clientNotFoundMessage": "ă‚Żăƒ©ă‚€ă‚ąăƒłăƒˆăŒèŠ‹ă€ă‹ă‚ŠăŸă›ă‚“ă€‚",
"authorizedProvider": "èȘćŻæžˆăżăƒ—ăƒ­ăƒă‚€ăƒ€ăƒŒ",
"authorizedProviderMessage": "ă‚ąă‚«ă‚Šăƒłăƒˆă«ăƒȘンクされたèȘćŻæžˆăżăƒ—ăƒ­ăƒă‚€ăƒ€ăƒŒ",
"identityProvider": "ă‚ąă‚€ăƒ‡ăƒłăƒ†ă‚Łăƒ†ă‚ŁăƒŒăƒ»ăƒ—ăƒ­ăƒă‚€ăƒ€ăƒŒ",
"identityProviderMessage": "ă‚ąă‚«ă‚Šăƒłăƒˆăšèš­ćźšă—ăŸă‚ąă‚€ăƒ‡ăƒłăƒ†ă‚Łăƒ†ă‚ŁăƒŒăƒ»ăƒ—ăƒ­ăƒă‚€ăƒ€ăƒŒă‚’ăƒȘăƒłă‚Żă™ă‚‹ă«ăŻ",
"socialLogin": "ă‚œăƒŒă‚·ăƒŁăƒ«ăƒ»ăƒ­ă‚°ă‚€ăƒł",
"userDefined": "ăƒŠăƒŒă‚¶ăƒŒćźšçŸ©",
"removeAccess": "スクセă‚čæš©ăźć‰Šé™€",
"removeAccessMessage": "こぼケプăƒȘăƒ»ă‚ąă‚«ă‚Šăƒłăƒˆă‚’äœżç”šă™ă‚‹ć ŽćˆăŻă€ă‚ąă‚Żă‚»ă‚čæš©ă‚’ć†ćșŠä»˜äžŽă™ă‚‹ćż…èŠăŒă‚ă‚ŠăŸă™ă€‚",
"authenticatorStatusMessage": "2芁玠èȘèšŒăŻçŸćœš",
"authenticatorFinishSetUpTitle": "あăȘたぼ2芁玠èȘèšŒ",
"authenticatorFinishSetUpMessage": "Keycloakă‚ąă‚«ă‚Šăƒłăƒˆă«ă‚”ă‚€ăƒłă‚€ăƒłă™ă‚‹ăŸăłă«ă€2芁玠èȘèšŒă‚łăƒŒăƒ‰ă‚’ć…„ćŠ›ă™ă‚‹ă‚ˆă†ă«æ±‚ă‚ă‚‰ă‚ŒăŸă™ă€‚",
"authenticatorSubTitle": "2芁玠èȘèšŒă‚’èš­ćźšă™ă‚‹",
"authenticatorSubMessage": "ă‚ąă‚«ă‚Šăƒłăƒˆăźă‚»ă‚­ăƒ„ăƒȘăƒ†ă‚ŁăƒŒă‚’ćŒ·ćŒ–ă™ă‚‹ă«ăŻă€ćˆ©ç”šćŻèƒœăȘ2芁玠èȘèšŒăźæ–čćŒăźă†ăĄć°‘ăȘくべも1ă€ă‚’æœ‰ćŠčă«ă—ăŸă™ă€‚",
"authenticatorMobileTitle": "ăƒąăƒă‚€ăƒ«ăƒ»ă‚ȘăƒŒă‚»ăƒłăƒ†ă‚Łă‚±ăƒŒă‚żăƒŒ",
"authenticatorMobileMessage": "ăƒąăƒă‚€ăƒ«ăƒ»ă‚ȘăƒŒă‚»ăƒłăƒ†ă‚Łă‚±ăƒŒă‚żăƒŒă‚’äœżç”šă—ăŠă€2芁玠èȘèšŒăšă—おçąșèȘă‚łăƒŒăƒ‰ă‚’ć–ćŸ—ă—ăŸă™ă€‚",
"authenticatorMobileFinishSetUpMessage": "ă‚ȘăƒŒă‚»ăƒłăƒ†ă‚Łă‚±ăƒŒă‚żăƒŒăŻă‚ăȘたぼæșćžŻé›»è©±ă«ăƒă‚€ăƒłăƒ‰ă•ă‚ŒăŠă„ăŸă™ă€‚",
"authenticatorActionSetup": "ă‚»ăƒƒăƒˆă‚ąăƒƒăƒ—",
"authenticatorSMSTitle": "SMSă‚łăƒŒăƒ‰",
"authenticatorSMSMessage": "Keycloakは、2芁玠èȘèšŒăšă—おçąșèȘă‚łăƒŒăƒ‰ă‚’æșćžŻé›»è©±ă«é€äżĄă—ăŸă™ă€‚",
"authenticatorSMSFinishSetUpMessage": "テキă‚čăƒˆăƒ»ăƒĄăƒƒă‚»ăƒŒă‚žăŒæŹĄăźé›»è©±ç•Șć·ćź›ă«é€äżĄă•ă‚ŒăŸă™ïŒš",
"authenticatorDefaultStatus": "ăƒ‡ăƒ•ă‚©ăƒ«ăƒˆ",
"authenticatorChangePhone": "電話ç•Șć·ăźć€‰æ›Ž",
"authenticatorBackupCodesTitle": "ăƒăƒƒă‚Żă‚ąăƒƒăƒ—ăƒ»ă‚łăƒŒăƒ‰",
"authenticatorBackupCodesMessage": "8æĄăźăƒăƒƒă‚Żă‚ąăƒƒăƒ—ăƒ»ă‚łăƒŒăƒ‰ăźć…„æ‰‹",
"authenticatorBackupCodesFinishSetUpMessage": "ă“ăźæ™‚ç‚čで12ć€‹ăźăƒăƒƒă‚Żă‚ąăƒƒăƒ—ăƒ»ă‚łăƒŒăƒ‰ăŒç”Ÿæˆă•ă‚ŒăŸă—ăŸă€‚ăă‚Œăžă‚Œäž€ćșŠă ă‘äœżç”šă§ăăŸă™ă€‚",
"authenticatorMobileSetupTitle": "ăƒąăƒă‚€ăƒ«ăƒ»ă‚ȘăƒŒă‚»ăƒłăƒ†ă‚Łă‚±ăƒŒă‚żăƒŒăźă‚»ăƒƒăƒˆă‚ąăƒƒăƒ—",
"smscodeIntroMessage": "電話ç•Șć·ă‚’ć…„ćŠ›ă™ă‚‹ăšă€çąșèȘă‚łăƒŒăƒ‰ăŒă‚ăȘăŸăźé›»è©±ă«é€äżĄă•ă‚ŒăŸă™ă€‚",
"mobileSetupStep1":
"æșćžŻé›»è©±ă«ă‚ȘăƒŒă‚»ăƒłăƒ†ă‚Łă‚±ăƒŒă‚żăƒŒăƒ»ă‚ąăƒ—ăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłă‚’ă‚€ăƒłă‚čăƒˆăƒŒăƒ«ă—ăŸă™ă€‚ă“ă“ă«ăƒȘă‚čトされどいるケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłăŒă‚”ăƒăƒŒăƒˆă•ă‚ŒăŠă„ăŸă™ă€‚",
"mobileSetupStep2": "ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłă‚’é–‹ăă€ăƒăƒŒă‚łăƒŒăƒ‰ă‚’ă‚čキャンしどください。",
"mobileSetupStep3": "ケプăƒȘă‚±ăƒŒă‚·ăƒ§ăƒłă‹ă‚‰æäŸ›ă•ă‚ŒăŸăƒŻăƒłă‚żă‚€ăƒ ă‚łăƒŒăƒ‰ă‚’ć…„ćŠ›ă—ă€äżć­˜ă‚’ă‚ŻăƒȘăƒƒă‚Żă—ăŠă‚»ăƒƒăƒˆă‚ąăƒƒăƒ—ă‚’ç”‚äș†ă—ăŸă™ă€‚",
"scanBarCode": "ăƒăƒŒă‚łăƒŒăƒ‰ă‚’ă‚čă‚­ăƒŁăƒłă—ăŸă™ă‹ïŒŸ",
"enterBarCode": "ăƒŻăƒłă‚żă‚€ăƒ ă‚łăƒŒăƒ‰ă‚’ć…„ćŠ›ă—ăŠăă ă•ă„",
"doCopy": "ă‚łăƒ”ăƒŒ",
"doFinish": "甂äș†",
"authenticatorSMSCodeSetupTitle": "SMSă‚łăƒŒăƒ‰ăźă‚»ăƒƒăƒˆă‚ąăƒƒăƒ—",
"chooseYourCountry": "ć›œă‚’éžă‚“ă§ăă ă•ă„",
"enterYourPhoneNumber": "電話ç•Șć·ă‚’ć…„ćŠ›ă—ăŠăă ă•ă„",
"sendVerficationCode": "çąșèȘă‚łăƒŒăƒ‰ăźé€äżĄ",
"enterYourVerficationCode": "çąșèȘă‚łăƒŒăƒ‰ă‚’ć…„抛しどください",
"authenticatorBackupCodesSetupTitle": "ăƒăƒƒă‚Żă‚ąăƒƒăƒ—ăƒ»ă‚łăƒŒăƒ‰ăźă‚»ăƒƒăƒˆă‚ąăƒƒăƒ—",
"backupcodesIntroMessage":
"æșćžŻé›»è©±ă«ă‚ąă‚Żă‚»ă‚čできăȘă„ć Žćˆă§ă‚‚ă€ăƒăƒƒă‚Żă‚ąăƒƒăƒ—ăƒ»ă‚łăƒŒăƒ‰ă‚’äœżç”šă—ăŠă‚ąă‚«ă‚Šăƒłăƒˆă«ăƒ­ă‚°ă‚€ăƒłă§ăăŸă™ă€‚ă©ă“ă‹ćź‰ć…šă§ă‚ąă‚Żă‚»ă‚čćŻèƒœăȘć Žæ‰€ă«äżçźĄă—ăŠăă ă•ă„ă€‚",
"realmName": "ハルム",
"doDownload": "ăƒ€ă‚Šăƒłăƒ­ăƒŒăƒ‰",
"doPrint": "ć°ćˆ·",
"backupCodesTips-1": "ć„ăƒăƒƒă‚Żă‚ąăƒƒăƒ—ăƒ»ă‚łăƒŒăƒ‰ăŻ1ć›žäœżç”šă§ăăŸă™ă€‚",
"backupCodesTips-2": "ă“ă‚Œă‚‰ăźă‚łăƒŒăƒ‰ăŻă“ăźæ—„ă«ç”Ÿæˆă•ă‚ŒăŸă—ăŸïŒš",
"generateNewBackupCodes": "æ–°ă—ă„ăƒăƒƒă‚Żă‚ąăƒƒăƒ—ăƒ»ă‚łăƒŒăƒ‰ă‚’ç”Ÿæˆă™ă‚‹",
"backupCodesTips-3": "æ–°ă—ă„ăƒăƒƒă‚Żă‚ąăƒƒăƒ—ăƒ»ă‚łăƒŒăƒ‰ă‚’ç”Ÿæˆă™ă‚‹ăšă€çŸćœšăźă‚łăƒŒăƒ‰ăŻæ©Ÿèƒœă—ăȘくăȘă‚ŠăŸă™ă€‚",
"backtoAuthenticatorPage": "ă‚ȘăƒŒă‚»ăƒłăƒ†ă‚Łă‚±ăƒŒă‚żăƒŒăƒ»ăƒšăƒŒă‚žă«æˆ»ă‚‹",
"resources": "ăƒȘă‚œăƒŒă‚č",
"sharedwithMe": "ç§ăšć…±æœ‰",
"share": "ć…±æœ‰",
"sharedwith": "ć…±æœ‰",
"accessPermissions": "スクセă‚čăƒ»ăƒ‘ăƒŒăƒŸăƒƒă‚·ăƒ§ăƒł",
"permissionRequests": "ăƒ‘ăƒŒăƒŸăƒƒă‚·ăƒ§ăƒłăźèŠæ±‚",
"approve": "æ‰żèȘ",
"approveAll": "すăčăŠæ‰żèȘ",
"people": "äșș",
"perPage": "1ăƒšăƒŒă‚žă‚ăŸă‚Š",
"currentPage": "çŸćœšăźăƒšăƒŒă‚ž",
"sharetheResource": "ăƒȘă‚œăƒŒă‚čăźć…±æœ‰",
"group": "ă‚°ăƒ«ăƒŒăƒ—",
"selectPermission": "ăƒ‘ăƒŒăƒŸăƒƒă‚·ăƒ§ăƒłă‚’éžæŠž",
"addPeople": "あăȘたぼăƒȘă‚œăƒŒă‚čă‚’ć…±æœ‰ă™ă‚‹äșșă‚’èżœćŠ ",
"addTeam": "あăȘたぼăƒȘă‚œăƒŒă‚čă‚’ć…±æœ‰ă™ă‚‹ăƒăƒŒăƒ ă‚’èżœćŠ ",
"myPermissions": "ç§ăźăƒ‘ăƒŒăƒŸăƒƒă‚·ăƒ§ăƒł",
"waitingforApproval": "æ‰żèȘćŸ…づ",
"anyPermission": "ä»»æ„ăźăƒ‘ăƒŒăƒŸăƒƒă‚·ăƒ§ăƒł",
"openshift.scope.user_info": "ăƒŠăƒŒă‚¶ăƒŒæƒ…ć ±",
"openshift.scope.user_check-access": "ăƒŠăƒŒă‚¶ăƒŒă‚ąă‚Żă‚»ă‚čæƒ…ć ±",
"openshift.scope.user_full": "ăƒ•ăƒ«ă‚ąă‚Żă‚»ă‚č",
"openshift.scope.list-projects": "ăƒ—ăƒ­ă‚žă‚§ă‚Żăƒˆăźäž€èŠ§èĄšç€ș"
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,143 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "Saugoti",
"doCancel": "AtĆĄaukti",
"doLogOutAllSessions": "Atjungti visas sesijas",
"doRemove": "Ć alinti",
"doAdd": "Pridėti",
"doSignOut": "Atsijungti",
"editAccountHtmlTitle": "Redaguoti paskyrą",
"federatedIdentitiesHtmlTitle": "Susietos paskyros",
"accountLogHtmlTitle": "Paskyros ĆŸurnalas",
"changePasswordHtmlTitle": "Keisti slaptaĆŸodÄŻ",
"sessionsHtmlTitle": "Prisijungimo sesijos",
"accountManagementTitle": "Keycloak NaudotojĆł Administravimas",
"authenticatorTitle": "Autentifikatorius",
"applicationsHtmlTitle": "Programos",
"authenticatorCode": "Vienkartinis kodas",
"email": "El. paĆĄtas",
"firstName": "Vardas",
"givenName": "Pavardė",
"fullName": "Pilnas vardas",
"lastName": "Pavardė",
"familyName": "Pavardė",
"password": "SlaptaĆŸodis",
"passwordConfirm": "Pakartotas slaptaĆŸodis",
"passwordNew": "Naujas slaptaĆŸodis",
"username": "Naudotojo vardas",
"address": "Adresas",
"street": "Gatvė",
"locality": "Miestas arba vietovė",
"region": "Rajonas",
"postal_code": "PaĆĄto kodas",
"country": "Ć alis",
"emailVerified": "El. paĆĄto adresas patvirtintas",
"gssDelegationCredential": "GSS prisijungimo duomenĆł delegavimas",
"role_admin": "Administratorius",
"role_realm-admin": "Srities administravimas",
"role_create-realm": "Kurti sritÄŻ",
"role_view-realm": "PerĆŸiĆ«rėti sritÄŻ",
"role_view-users": "PerĆŸiĆ«rėti naudotojus",
"role_view-applications": "PerĆŸiĆ«rėti programas",
"role_view-clients": "PerĆŸiĆ«rėti klientines programas",
"role_view-events": "PerĆŸiĆ«rėti ÄŻvykiĆł ĆŸurnalą",
"role_view-identity-providers": "PerĆŸiĆ«rėti tapatybės teikėjus",
"role_manage-realm": "Valdyti sritis",
"role_manage-users": "Valdyti naudotojus",
"role_manage-applications": "Valdyti programas",
"role_manage-identity-providers": "Valdyti tapatybės teikėjus",
"role_manage-clients": "Valdyti programas",
"role_manage-events": "Valdyti ÄŻvykius",
"role_view-profile": "PerĆŸiĆ«rėti paskyrą",
"role_manage-account": "Valdyti paskyrą",
"role_read-token": "Skaityti prieigos rakơą",
"role_offline-access": "Darbas neprisijungus",
"role_uma_authorization": "Äźgauti UMA autorizavimo teises",
"client_account": "Paskyra",
"client_security-admin-console": "Saugumo administravimo konsolė",
"client_admin-cli": "Administravimo CLI",
"client_realm-management": "Srities valdymas",
"client_broker": "Tarpininkas",
"requiredFields": "Privalomi laukai",
"allFieldsRequired": "Visi laukai yra privalomi",
"backToApplication": "&laquo; GrÄŻĆŸti ÄŻ programą",
"backTo": "Atgal ÄŻ {0}",
"date": "Data",
"event": "Äźvykis",
"ip": "IP",
"client": "Klientas",
"clients": "Klientai",
"details": "Detaliau",
"started": "Sukƫrimo laikas",
"lastAccess": "Vėliausia prieiga",
"expires": "Galioja iki",
"applications": "Programos",
"account": "Paskyra",
"federatedIdentity": "Susieta tapatybė",
"authenticator": "Autentifikatorius",
"sessions": "Sesijos",
"log": "Äźvykiai",
"application": "Programa",
"availablePermissions": "Galimos teisės",
"grantedPermissions": "ļgalintos teisės",
"grantedPersonalInfo": "ļgalinta asmeninė informacija",
"additionalGrants": "Papildomi ÄŻgaliojimai",
"action": "Veiksmas",
"inResource": "yra",
"fullAccess": "Pilna prieiga",
"offlineToken": "ReĆŸimo neprisijungus raktas (token)",
"revoke": "Atơaukti įgaliojimą",
"configureAuthenticators": "Sukonfigƫruotas autentifikatorius",
"mobile": "Mobilus",
"totpStep1":
'ļdiekite <a href="https://freeotp.github.io/" target="_blank">FreeOTP</a> arba Google Authenticator savo įrenginyje. Programėlės prieinamos <a href="https://play.google.com">Google Play</a> ir Apple App Store.',
"totpStep2": "Atidarykite programėlę ir nuskenuokite barkodą arba įveskite kodą.",
"totpStep3": "ļveskite programėlėje sugeneruotą vieną kartą galiojantį kodą ir paspauskite Saugoti norėdami prisijungti.",
"missingUsernameMessage": "Praơome įvesti naudotojo vardą.",
"missingFirstNameMessage": "Praơome įvesti vardą.",
"invalidEmailMessage": "Neteisingas el. paĆĄto adresas.",
"missingLastNameMessage": "Praơome įvesti pavardę.",
"missingEmailMessage": "Praơome įvesti el. paơto adresą.",
"missingPasswordMessage": "PraĆĄome ÄŻvesti slaptaĆŸodÄŻ.",
"notMatchPasswordMessage": "SlaptaĆŸodĆŸiai nesutampa.",
"missingTotpMessage": "Praơome įvesti autentifikacijos kodą.",
"invalidPasswordExistingMessage": "Neteisingas dabartinis slaptaĆŸodis.",
"invalidPasswordConfirmMessage": "Pakartotas slaptaĆŸodis nesutampa.",
"invalidTotpMessage": "Neteisingas autentifikacijos kodas.",
"usernameExistsMessage": "Toks naudotojas jau egzistuoja.",
"emailExistsMessage": "El. paĆĄto adresas jau egzistuoja.",
"readOnlyUserMessage": "Tik skaitymui sukonfigĆ«ruotos paskyros duomenĆł atnaujinti neleidĆŸiama.",
"readOnlyPasswordMessage": "Tik skaitymui sukonfigĆ«ruotos paskyros slaptaĆŸodĆŸio atnaujinti neleidĆŸiama.",
"successTotpMessage": "Mobilus autentifikatorius sukonfigƫruotas.",
"successTotpRemovedMessage": "Mobilus autentifikatorius paĆĄalintas.",
"successGrantRevokedMessage": "ļgalinimas paơalintas sėkmingai.",
"accountUpdatedMessage": "JĆ«sĆł paskyros duomenys sėkmingai atnaujinti.",
"accountPasswordUpdatedMessage": "JĆ«sĆł paskyros slaptaĆŸodis pakeistas.",
"missingIdentityProviderMessage": "Nenurodytas tapatybės teikėjas.",
"invalidFederatedIdentityActionMessage": "Neteisingas arba neĆŸinomas veiksmas.",
"identityProviderNotFoundMessage": "Nurodytas tapatybės teikėjas nerastas.",
"federatedIdentityLinkNotActiveMessage": "Nurodyta susieta tapatybė neaktyvi.",
"federatedIdentityRemovingLastProviderMessage":
"JĆ«s negalite paĆĄalinti paskutinio tapatybės teikėjo sąsajos, nes JĆ«s neturite nusistatę paskyros slaptaĆŸodĆŸio.",
"identityProviderRedirectErrorMessage": "Klaida nukreipiant į tapatybės teikėjo puslapį.",
"identityProviderRemovedMessage": "Tapatybės teikėjas sėkmingai paơalintas.",
"identityProviderAlreadyLinkedMessage": "Susieta tapatybė iơ {0} jau susieta su kita paskyra.",
"staleCodeAccountMessage": "Puslapio galiojimas baigėsi. Bandykite dar kartą.",
"consentDenied": "Prieiga draudĆŸiama.",
"accountDisabledMessage": "Paskyros galiojimas sustabdytas, kreipkitės į administratoriƳ.",
"accountTemporarilyDisabledMessage": "Paskyros galiojimas laikinai sustabdytas. Kreipkitės į administratoriƳ arba pabandykite vėliau.",
"invalidPasswordMinLengthMessage": "Per trumpas slaptaĆŸodis: maĆŸiausias ilgis {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Neteisingas slaptaĆŸodis: privaloma ÄŻvesti {0} maĆŸÄ…ją raidę.",
"invalidPasswordMinDigitsMessage": "Neteisingas slaptaĆŸodis: privaloma ÄŻvesti {0} skaitmenÄŻ.",
"invalidPasswordMinUpperCaseCharsMessage": "Neteisingas slaptaĆŸodis: privaloma ÄŻvesti {0} didĆŸiąją raidę.",
"invalidPasswordMinSpecialCharsMessage": "Neteisingas slaptaĆŸodis: privaloma ÄŻvesti {0} specialĆł simbolÄŻ.",
"invalidPasswordNotUsernameMessage": "Neteisingas slaptaĆŸodis: slaptaĆŸodis negali sutapti su naudotojo vardu.",
"invalidPasswordRegexPatternMessage": "Neteisingas slaptaĆŸodis: slaptaĆŸodis netenkina regex taisyklės(iĆł).",
"invalidPasswordHistoryMessage": "Neteisingas slaptaĆŸodis: slaptaĆŸodis negali sutapti su prieĆĄ tai buvusiais {0} slaptaĆŸodĆŸiais."
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,143 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "Opslaan",
"doCancel": "Annuleer",
"doLogOutAllSessions": "Alle sessies uitloggen",
"doRemove": "Verwijder",
"doAdd": "Voeg toe",
"doSignOut": "Afmelden",
"editAccountHtmlTitle": "Bewerk account",
"federatedIdentitiesHtmlTitle": "Federated Identities",
"accountLogHtmlTitle": "Account log",
"changePasswordHtmlTitle": "Verander wachtwoord",
"sessionsHtmlTitle": "Sessies",
"accountManagementTitle": "Keycloak Accountbeheer",
"authenticatorTitle": "Authenticator",
"applicationsHtmlTitle": "Toepassingen",
"authenticatorCode": "Eenmalige code",
"email": "E-mailadres",
"firstName": "Voornaam",
"givenName": "Voornaam",
"fullName": "Volledige naam",
"lastName": "Achternaam",
"familyName": "Achternaam",
"password": "Wachtwoord",
"passwordConfirm": "Bevestiging",
"passwordNew": "Nieuw Wachtwoord",
"username": "Gebruikersnaam",
"address": "Adres",
"street": "Straat",
"locality": "Stad of plaats",
"region": "Staat, provincie of regio",
"postal_code": "Postcode",
"country": "Land",
"emailVerified": "E-mailadres geverifieerd",
"gssDelegationCredential": "GSS gedelegeerde aanmeldgegevens",
"role_admin": "Beheer",
"role_realm-admin": "Realmbeheer",
"role_create-realm": "Creëer realm",
"role_view-realm": "Bekijk realm",
"role_view-users": "Bekijk gebruikers",
"role_view-applications": "Bekijk toepassingen",
"role_view-clients": "Bekijk clients",
"role_view-events": "Bekijk gebeurtenissen",
"role_view-identity-providers": "Bekijk identity providers",
"role_manage-realm": "Beheer realm",
"role_manage-users": "Beheer gebruikers",
"role_manage-applications": "Beheer toepassingen",
"role_manage-identity-providers": "Beheer identity providers",
"role_manage-clients": "Beheer clients",
"role_manage-events": "Beheer gebeurtenissen",
"role_view-profile": "Bekijk profiel",
"role_manage-account": "Beheer account",
"role_manage-account-links": "Beheer accountkoppelingen",
"role_read-token": "Lees token",
"role_offline-access": "Offline toegang",
"role_uma_authorization": "Verkrijg UMA rechten",
"client_account": "Account",
"client_security-admin-console": "Console Veligheidsbeheer",
"client_admin-cli": "Beheer CLI",
"client_realm-management": "Realmbeheer",
"client_broker": "Broker",
"requiredFields": "Verplichte velden",
"allFieldsRequired": "Alle velden verplicht",
"backToApplication": "&laquo; Terug naar toepassing",
"backTo": "Terug naar {0}",
"date": "Datum",
"event": "Gebeurtenis",
"ip": "IP",
"client": "Client",
"clients": "Clients",
"details": "Details",
"started": "Gestart",
"lastAccess": "Laatste toegang",
"expires": "Vervalt",
"applications": "Toepassingen",
"account": "Account",
"federatedIdentity": "Federated Identity",
"authenticator": "Authenticator",
"sessions": "Sessies",
"log": "Log",
"application": "Toepassing",
"availablePermissions": "Beschikbare rechten",
"grantedPermissions": "Gegunde rechten",
"grantedPersonalInfo": "Gegunde Persoonsgegevens",
"additionalGrants": "Verdere vergunningen",
"action": "Actie",
"inResource": "in",
"fullAccess": "Volledige toegang",
"offlineToken": "Offline Token",
"revoke": "Vergunning intrekken",
"configureAuthenticators": "Ingestelde authenticators",
"mobile": "Mobiel nummer",
"totpStep1": "Installeer een van de onderstaande applicaties op uw mobiele apparaat:",
"totpStep2": "Open de toepassing en scan de QR-code of voer de sleutel in.",
"totpStep3": "Voer de door de toepassing gegeven eenmalige code in en klik op Opslaan om de configuratie af te ronden.",
"missingUsernameMessage": "Gebruikersnaam ontbreekt.",
"missingFirstNameMessage": "Voornaam onbreekt.",
"invalidEmailMessage": "Ongeldig e-mailadres.",
"missingLastNameMessage": "Achternaam ontbreekt.",
"missingEmailMessage": "E-mailadres ontbreekt.",
"missingPasswordMessage": "Wachtwoord ontbreekt.",
"notMatchPasswordMessage": "Wachtwoorden komen niet overeen.",
"missingTotpMessage": "Authenticatiecode ontbreekt.",
"invalidPasswordExistingMessage": "Ongeldig bestaand wachtwoord.",
"invalidPasswordConfirmMessage": "Wachtwoordbevestiging komt niet overeen.",
"invalidTotpMessage": "Ongeldige authenticatiecode.",
"emailExistsMessage": "E-mailadres bestaat reeds.",
"readOnlyUserMessage": "U kunt uw account niet bijwerken aangezien het account alleen-lezen is.",
"readOnlyPasswordMessage": "U kunt uw wachtwoord niet wijzigen omdat uw account alleen-lezen is.",
"successTotpMessage": "Mobiele authenticator geconfigureerd.",
"successTotpRemovedMessage": "Mobiele authenticator verwijderd.",
"successGrantRevokedMessage": "Vergunning succesvol ingetrokken",
"accountUpdatedMessage": "Uw account is gewijzigd.",
"accountPasswordUpdatedMessage": "Uw wachtwoord is gewijzigd.",
"missingIdentityProviderMessage": "Geen identity provider aangegeven.",
"invalidFederatedIdentityActionMessage": "Ongeldige of ontbrekende actie op federated identity.",
"identityProviderNotFoundMessage": "Gespecificeerde identity provider niet gevonden.",
"federatedIdentityLinkNotActiveMessage": "Deze federated identity is niet langer geldig.",
"federatedIdentityRemovingLastProviderMessage":
"U kunt de laatste federated identity provider niet verwijderen aangezien u dan niet langer zou kunnen inloggen.",
"identityProviderRedirectErrorMessage": "Kon niet herverwijzen naar identity provider.",
"identityProviderRemovedMessage": "Identity provider met succes verwijderd.",
"identityProviderAlreadyLinkedMessage": "Door {0} teruggegeven federated identity is al gekoppeld aan een andere gebruiker.",
"staleCodeAccountMessage": "De pagina is verlopen. Probeer het nogmaals.",
"consentDenied": "Toestemming geweigerd",
"accountDisabledMessage": "Account is gedeactiveerd. Contacteer de beheerder.",
"accountTemporarilyDisabledMessage": "Account is tijdelijk deactiveerd, neem contact op met de beheerder of probeer het later opnieuw.",
"invalidPasswordMinLengthMessage": "Ongeldig wachtwoord: de minimale lengte is {0} karakters.",
"invalidPasswordMinLowerCaseCharsMessage": "Ongeldig wachtwoord: het moet minstens {0} kleine letters bevatten.",
"invalidPasswordMinDigitsMessage": "Ongeldig wachtwoord: het moet minstens {0} getallen bevatten.",
"invalidPasswordMinUpperCaseCharsMessage": "Ongeldig wachtwoord: het moet minstens {0} hoofdletters bevatten.",
"invalidPasswordMinSpecialCharsMessage": "Ongeldig wachtwoord: het moet minstens {0} speciale karakters bevatten.",
"invalidPasswordNotUsernameMessage": "Ongeldig wachtwoord: het mag niet overeenkomen met de gebruikersnaam.",
"invalidPasswordRegexPatternMessage": "Ongeldig wachtwoord: het voldoet niet aan het door de beheerder ingestelde patroon.",
"invalidPasswordHistoryMessage": "Ongeldig wachtwoord: het mag niet overeen komen met een van de laatste {0} wachtwoorden.",
"invalidPasswordGenericMessage": "Ongeldig wachtwoord: het nieuwe wachtwoord voldoet niet aan het wachtwoordbeleid."
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,153 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "Lagre",
"doCancel": "Avbryt",
"doLogOutAllSessions": "Logg ut av alle sesjoner",
"doRemove": "Fjern",
"doAdd": "Legg til",
"doSignOut": "Logg ut",
"editAccountHtmlTitle": "Rediger konto",
"federatedIdentitiesHtmlTitle": "Federerte identiteter",
"accountLogHtmlTitle": "Kontologg",
"changePasswordHtmlTitle": "Endre passord",
"sessionsHtmlTitle": "Sesjoner",
"accountManagementTitle": "Keycloak kontoadministrasjon",
"authenticatorTitle": "Autentikator",
"applicationsHtmlTitle": "Applikasjoner",
"authenticatorCode": "Engangskode",
"email": "E-post",
"firstName": "Fornavn",
"givenName": "Fornavn",
"fullName": "Fullt navn",
"lastName": "Etternavn",
"familyName": "Etternavn",
"password": "Passord",
"passwordConfirm": "Bekreftelse",
"passwordNew": "Nytt passord",
"username": "Brukernavn",
"address": "Adresse",
"street": "Gate-/veinavn + husnummer",
"locality": "By",
"region": "Fylke",
"postal_code": "Postnummer",
"country": "Land",
"emailVerified": "E-post bekreftet",
"gssDelegationCredential": "GSS legitimasjonsdelegering",
"role_admin": "Administrator",
"role_realm-admin": "Administrator for sikkerhetsdomene",
"role_create-realm": "Opprette sikkerhetsdomene",
"role_view-realm": "Se sikkerhetsdomene",
"role_view-users": "Se brukere",
"role_view-applications": "Se applikasjoner",
"role_view-clients": "Se klienter",
"role_view-events": "Se hendelser",
"role_view-identity-providers": "Se identitetsleverandĂžrer",
"role_manage-realm": "Administrere sikkerhetsdomene",
"role_manage-users": "Administrere brukere",
"role_manage-applications": "Administrere applikasjoner",
"role_manage-identity-providers": "Administrere identitetsleverandĂžrer",
"role_manage-clients": "Administrere klienter",
"role_manage-events": "Administrere hendelser",
"role_view-profile": "Se profil",
"role_manage-account": "Administrere konto",
"role_read-token": "Lese token",
"role_offline-access": "Frakoblet tilgang",
"role_uma_authorization": "Skaffe tillatelser",
"client_account": "Konto",
"client_security-admin-console": "Sikkerhetsadministrasjonskonsoll",
"client_admin-cli": "Kommandolinje-grensesnitt for administrator",
"client_realm-management": "Sikkerhetsdomene-administrasjon",
"client_broker": "Broker",
"requiredFields": "Obligatoriske felt",
"allFieldsRequired": "Alle felt mÄ fylles ut",
"backToApplication": "&laquo; Tilbake til applikasjonen",
"backTo": "Tilbake til {0}",
"date": "Dato",
"event": "Hendelse",
"ip": "IP",
"client": "Klient",
"clients": "Klienter",
"details": "Detaljer",
"started": "Startet",
"lastAccess": "Sist benyttet",
"expires": "UtlĂžper",
"applications": "Applikasjoner",
"account": "Konto",
"federatedIdentity": "Federert identitet",
"authenticator": "Autentikator",
"sessions": "Sesjoner",
"log": "Logg",
"application": "Applikasjon",
"availablePermissions": "Tilgjengelige rettigheter",
"grantedPermissions": "Innvilgede rettigheter",
"grantedPersonalInfo": "Innvilget personlig informasjon",
"additionalGrants": "Ekstra rettigheter",
"action": "Handling",
"inResource": "i",
"fullAccess": "Full tilgang",
"offlineToken": "Offline token",
"revoke": "Opphev rettighet",
"configureAuthenticators": "Konfigurerte autentikatorer",
"mobile": "Mobiltelefon",
"totpStep1": "Installer ett av fÞlgende programmer pÄ mobilen din.",
"totpStep2": "Åpne applikasjonen og skann strekkoden eller skriv inn koden.",
"totpStep3": "Skriv inn engangskoden gitt av applikasjonen og klikk Lagre for Ă„ fullfĂžre.",
"missingUsernameMessage": "Vennligst oppgi brukernavn.",
"missingFirstNameMessage": "Vennligst oppgi fornavn.",
"invalidEmailMessage": "Ugyldig e-postadresse.",
"missingLastNameMessage": "Vennligst oppgi etternavn.",
"missingEmailMessage": "Vennligst oppgi e-postadresse.",
"missingPasswordMessage": "Vennligst oppgi passord.",
"notMatchPasswordMessage": "Passordene er ikke like.",
"missingTotpMessage": "Vennligst oppgi engangskode.",
"invalidPasswordExistingMessage": "Ugyldig eksisterende passord.",
"invalidPasswordConfirmMessage": "Passordene er ikke like.",
"invalidTotpMessage": "Ugyldig engangskode.",
"usernameExistsMessage": "Brukernavnet finnes allerede.",
"emailExistsMessage": "E-postadressen finnes allerede.",
"readOnlyUserMessage": "Du kan ikke oppdatere kontoen din ettersom den er skrivebeskyttet.",
"readOnlyPasswordMessage": "Du kan ikke oppdatere passordet ditt ettersom kontoen din er skrivebeskyttet.",
"successTotpMessage": "Autentikator for mobiltelefon er konfigurert.",
"successTotpRemovedMessage": "Autentikator for mobiltelefon er fjernet.",
"successGrantRevokedMessage": "Vellykket oppheving av rettighet.",
"accountUpdatedMessage": "Kontoen din har blitt oppdatert.",
"accountPasswordUpdatedMessage": "Ditt passord har blitt oppdatert.",
"missingIdentityProviderMessage": "IdentitetsleverandĂžr er ikke spesifisert.",
"invalidFederatedIdentityActionMessage": "Ugyldig eller manglende handling.",
"identityProviderNotFoundMessage": "Spesifisert identitetsleverandĂžr ikke funnet.",
"federatedIdentityLinkNotActiveMessage": "Denne identiteten er ikke lenger aktiv.",
"federatedIdentityRemovingLastProviderMessage": "Du kan ikke fjerne siste federerte identitet ettersom du ikke har et passord.",
"identityProviderRedirectErrorMessage": "Redirect til identitetsleverandĂžr feilet.",
"identityProviderRemovedMessage": "Fjerning av identitetsleverandĂžr var vellykket.",
"identityProviderAlreadyLinkedMessage": "Federert identitet returnert av {0} er allerede koblet til en annen bruker.",
"staleCodeAccountMessage": "Siden har utlĂžpt. Vennligst prĂžv en gang til.",
"consentDenied": "Samtykke avslÄtt.",
"accountDisabledMessage": "Konto er deaktivert, kontakt administrator.",
"accountTemporarilyDisabledMessage": "Konto er midlertidig deaktivert, kontakt administrator eller prĂžv igjen senere.",
"invalidPasswordMinLengthMessage": "Ugyldig passord: minimum lengde {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Ugyldig passord: mÄ inneholde minimum {0} smÄ bokstaver.",
"invalidPasswordMinDigitsMessage": "Ugyldig passord: mÄ inneholde minimum {0} sifre.",
"invalidPasswordMinUpperCaseCharsMessage": "Ugyldig passord: mÄ inneholde minimum {0} store bokstaver.",
"invalidPasswordMinSpecialCharsMessage": "Ugyldig passord: mÄ inneholde minimum {0} spesialtegn.",
"invalidPasswordNotUsernameMessage": "Ugyldig passord: kan ikke vĂŠre likt brukernavn.",
"invalidPasswordRegexPatternMessage": "Ugyldig passord: tilfredsstiller ikke kravene for passord-mĂžnster.",
"invalidPasswordHistoryMessage": "Ugyldig passord: kan ikke vÊre likt noen av de {0} foregÄende passordene.",
"locale_ca": "CatalĂ ",
"locale_de": "Deutsch",
"locale_en": "English",
"locale_es": "Español",
"locale_fr": "Français",
"locale_it": "Italian",
"locale_ja": "æ—„æœŹèȘž",
"locale_no": "Norsk",
"locale_nl": "Nederlands",
"locale_pt-BR": "PortuguĂȘs (Brasil)",
"locale_ru": "РуссĐșĐžĐč",
"locale_zh-CN": "äž­æ–‡çź€äœ“"
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,8 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,140 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "Salvar",
"doCancel": "Cancelar",
"doLogOutAllSessions": "Sair de todas as sessÔes",
"doRemove": "Remover",
"doAdd": "Adicionar",
"doSignOut": "Sair",
"editAccountHtmlTitle": "Editar Conta",
"federatedIdentitiesHtmlTitle": "Identidades Federadas",
"accountLogHtmlTitle": "Log da conta",
"changePasswordHtmlTitle": "Alterar senha",
"sessionsHtmlTitle": "SessÔes",
"accountManagementTitle": "Gerenciamento de Conta",
"authenticatorTitle": "Autenticator",
"applicationsHtmlTitle": "Aplicativos",
"authenticatorCode": "CĂłdigo autenticador",
"email": "E-mail",
"firstName": "Primeiro nome",
"givenName": "Primeiro nome",
"fullName": "Nome completo",
"lastName": "Sobrenome",
"familyName": "Sobrenome",
"password": "Senha",
"passwordConfirm": "Confirmação",
"passwordNew": "Nova senha",
"username": "Nome de usĂșario",
"address": "Endereço",
"street": "Logradouro",
"locality": "Cidade ou Localidade",
"region": "Estado",
"postal_code": "CEP",
"country": "PaĂ­s",
"emailVerified": "E-mail verificado",
"gssDelegationCredential": "GSS Delegação de Credencial",
"role_admin": "Admin",
"role_realm-admin": "Realm Admin",
"role_create-realm": "Cria realm",
"role_view-realm": "Visualiza realm",
"role_view-users": "Visualiza usuĂĄrios",
"role_view-applications": "Visualiza aplicaçÔes",
"role_view-clients": "Visualiza clientes",
"role_view-events": "Visualiza eventos",
"role_view-identity-providers": "Visualiza provedores de identidade",
"role_manage-realm": "Gerencia realm",
"role_manage-users": "Gerencia usuĂĄrios",
"role_manage-applications": "Gerencia aplicaçÔes",
"role_manage-identity-providers": "Gerencia provedores de identidade",
"role_manage-clients": "Gerencia clientes",
"role_manage-events": "Gerencia eventos",
"role_view-profile": "Visualiza perfil",
"role_manage-account": "Gerencia conta",
"role_read-token": "LĂȘ token",
"role_offline-access": "Acesso Offline",
"role_uma_authorization": "Obter permissÔes",
"client_account": "Conta",
"client_security-admin-console": "Console de Administração de Segurança",
"client_admin-cli": "Admin CLI",
"client_realm-management": "Gerenciamento de Realm",
"client_broker": "Broker",
"requiredFields": "Campos obrigatĂłrios",
"allFieldsRequired": "Todos os campos sĂŁo obrigatĂłrios",
"backToApplication": "&laquo; Voltar para aplicação",
"backTo": "Voltar para {0}",
"date": "Data",
"event": "Evento",
"ip": "IP",
"client": "Cliente",
"clients": "Clientes",
"details": "Detalhes",
"started": "Iniciado",
"lastAccess": "Último acesso",
"expires": "Expira",
"applications": "Aplicativos",
"account": "Conta",
"federatedIdentity": "Identidade Federada",
"authenticator": "Autenticador",
"sessions": "SessÔes",
"log": "Log",
"application": "Aplicativo",
"availablePermissions": "PermissÔes Disponíveis",
"grantedPermissions": "PermissÔes Concedidas",
"grantedPersonalInfo": "InformaçÔes Pessoais Concedidas",
"additionalGrants": "ConcessÔes Adicionais",
"action": "Ação",
"inResource": "em",
"fullAccess": "Acesso Completo",
"offlineToken": "Offline Token",
"revoke": "Revogar ConcessÔes",
"configureAuthenticators": "Autenticadores Configurados",
"mobile": "Mobile",
"totpStep1":
'Instalar <a href="https://freeotp.github.io/" target="_blank">FreeOTP</a> ou Google Authenticator em seu dispositivo. Ambas aplicaçÔes estão disponíveis no <a href="https://play.google.com">Google Play</a> e na Apple App Store.',
"totpStep2": "Abra o aplicativo e escaneie o cĂłdigo de barras ou entre com o cĂłdigo.",
"totpStep3": "Digite o código fornecido pelo aplicativo e clique em Salvar para concluir a configuração.",
"missingUsernameMessage": "Por favor, especifique o nome de usuĂĄrio.",
"missingFirstNameMessage": "Por favor, informe o primeiro nome.",
"invalidEmailMessage": "E-mail invĂĄlido.",
"missingLastNameMessage": "Por favor, informe o sobrenome.",
"missingEmailMessage": "Por favor, informe o e-mail.",
"missingPasswordMessage": "Por favor, informe a senha.",
"notMatchPasswordMessage": "As senhas nĂŁo coincidem.",
"missingTotpMessage": "Por favor, informe o cĂłdigo autenticador.",
"invalidPasswordExistingMessage": "Senha atual invĂĄlida.",
"invalidPasswordConfirmMessage": "A senha de confirmação não coincide.",
"invalidTotpMessage": "CĂłdigo autenticador invĂĄlido.",
"usernameExistsMessage": "Este nome de usuĂĄrio jĂĄ existe.",
"emailExistsMessage": "Este e-mail jĂĄ existe.",
"readOnlyUserMessage": "VocĂȘ nĂŁo pode atualizar sua conta, uma vez que Ă© apenas de leitura",
"readOnlyPasswordMessage": "VocĂȘ nĂŁo pode atualizar sua senha, sua conta Ă© somente leitura",
"successTotpMessage": "Autenticador mobile configurado.",
"successTotpRemovedMessage": "Autenticador mobile removido.",
"successGrantRevokedMessage": "ConcessÔes revogadas com sucesso.",
"accountUpdatedMessage": "Sua conta foi atualizada",
"accountPasswordUpdatedMessage": "Sua senha foi atualizada",
"missingIdentityProviderMessage": "Provedor de identidade nĂŁo especificado",
"invalidFederatedIdentityActionMessage": "Ação invålida ou ausente",
"identityProviderNotFoundMessage": "O provedor de identidade especificado nĂŁo foi encontrado",
"federatedIdentityLinkNotActiveMessage": "Esta identidade nĂŁo estĂĄ mais em atividade",
"federatedIdentityRemovingLastProviderMessage": "VocĂȘ nĂŁo pode remover a Ășltima identidade federada como vocĂȘ nĂŁo tem senha",
"identityProviderRedirectErrorMessage": "Falha ao redirecionar para o provedor de identidade",
"identityProviderRemovedMessage": "Provedor de identidade removido com sucesso",
"identityProviderAlreadyLinkedMessage": "Identidade federada retornado por {0} jĂĄ estĂĄ ligado a outro usuĂĄrio.",
"accountDisabledMessage": "Conta desativada, contate o administrador",
"accountTemporarilyDisabledMessage": "A conta estĂĄ temporariamente indisponĂ­vel, contate o administrador ou tente novamente mais tarde",
"invalidPasswordMinLengthMessage": "Senha invĂĄlida: comprimento mĂ­nimo {0}",
"invalidPasswordMinLowerCaseCharsMessage": "Senha invĂĄlida: deve conter pelo menos {0} caractere(s) minĂșsculo",
"invalidPasswordMinDigitsMessage": "Senha invĂĄlida: deve conter pelo menos {0} nĂșmero(s)",
"invalidPasswordMinUpperCaseCharsMessage": "Senha invĂĄlida: deve conter pelo menos {0} caractere(s) maiĂșsculo",
"invalidPasswordMinSpecialCharsMessage": "Senha invĂĄlida: deve conter pelo menos {0} caractere(s) especial",
"invalidPasswordNotUsernameMessage": "Senha invĂĄlida: nĂŁo deve ser igual ao nome de usuĂĄrio",
"invalidPasswordRegexPatternMessage": "Senha invĂĄlida: nĂŁo corresponde ao padrĂŁo da expressĂŁo regular.",
"invalidPasswordHistoryMessage": "Senha invĂĄlida: nĂŁo pode ser igual a qualquer uma das {0} Ășltimas senhas."
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,143 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "ĐĄĐŸŃ…Ń€Đ°ĐœĐžŃ‚ŃŒ",
"doCancel": "ĐžŃ‚ĐŒĐ”ĐœĐ°",
"doLogOutAllSessions": "ВыĐčто Оз ĐČсДх сДссОĐč",
"doRemove": "ĐŁĐŽĐ°Đ»ĐžŃ‚ŃŒ",
"doAdd": "Đ”ĐŸĐ±Đ°ĐČоть",
"doSignOut": "Đ’Ń‹Ń…ĐŸĐŽ",
"editAccountHtmlTitle": "Đ˜Đ·ĐŒĐ”ĐœĐ”ĐœĐžĐ” ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč запОсО",
"federatedIdentitiesHtmlTitle": "ЀДЎДратОĐČĐœŃ‹Đ” ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Ń‹",
"accountLogHtmlTitle": "Đ›ĐŸĐł ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč запОсО",
"changePasswordHtmlTitle": "ĐĄĐŒĐ”ĐœĐ° ĐżĐ°Ń€ĐŸĐ»Ń",
"sessionsHtmlTitle": "ХДссОО",
"accountManagementTitle": "УпраĐČĐ»Đ”ĐœĐžĐ” ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč Đ·Đ°ĐżĐžŃŃŒŃŽ",
"authenticatorTitle": "ĐŃƒŃ‚Đ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€",
"applicationsHtmlTitle": "ĐŸŃ€ĐžĐ»ĐŸĐ¶Đ”ĐœĐžŃ",
"authenticatorCode": "ĐžĐŽĐœĐŸŃ€Đ°Đ·ĐŸĐČыĐč ĐșĐŸĐŽ",
"email": "E-mail",
"firstName": "Đ˜ĐŒŃ",
"givenName": "Đ˜ĐŒŃ",
"fullName": "ĐŸĐŸĐ»ĐœĐŸĐ” ĐžĐŒŃ",
"lastName": "Đ€Đ°ĐŒĐžĐ»ĐžŃ",
"familyName": "Đ€Đ°ĐŒĐžĐ»ĐžŃ",
"password": "ĐŸĐ°Ń€ĐŸĐ»ŃŒ",
"passwordConfirm": "ĐŸĐŸĐŽŃ‚ĐČĐ”Ń€Đ¶ĐŽĐ”ĐœĐžĐ” ĐżĐ°Ń€ĐŸĐ»Ń",
"passwordNew": "ĐĐŸĐČыĐč ĐżĐ°Ń€ĐŸĐ»ŃŒ",
"username": "Đ˜ĐŒŃ ĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Ń‚Đ”Đ»Ń",
"address": "АЎрДс",
"street": "УлОца",
"locality": "Đ“ĐŸŃ€ĐŸĐŽ",
"region": "Đ Đ”ĐłĐžĐŸĐœ",
"postal_code": "ĐŸĐŸŃ‡Ń‚ĐŸĐČыĐč ĐžĐœĐŽĐ”Đșс",
"country": "ĐĄŃ‚Ń€Đ°ĐœĐ°",
"emailVerified": "E-mail ĐżĐŸĐŽŃ‚ĐČĐ”Ń€Đ¶ĐŽĐ”Đœ",
"gssDelegationCredential": "Đ”Đ”Đ»Đ”ĐłĐžŃ€ĐŸĐČĐ°ĐœĐžĐ” ŃƒŃ‡Đ”Ń‚ĐœŃ‹Ń… ĐŽĐ°ĐœĐœŃ‹Ń… чДрДз GSS",
"role_admin": "ĐĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€",
"role_realm-admin": "ĐĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€ realm",
"role_create-realm": "ĐĄĐŸĐ·ĐŽĐ°Ń‚ŃŒ realm",
"role_view-realm": "ĐŸŃ€ĐŸŃĐŒĐŸŃ‚Ń€ realm",
"role_view-users": "ĐŸŃ€ĐŸŃĐŒĐŸŃ‚Ń€ ĐżĐŸĐ»ŃŒĐ·ĐŸĐČатДлДĐč",
"role_view-applications": "ĐŸŃ€ĐŸŃĐŒĐŸŃ‚Ń€ ĐżŃ€ĐžĐ»ĐŸĐ¶Đ”ĐœĐžĐč",
"role_view-clients": "ĐŸŃ€ĐŸŃĐŒĐŸŃ‚Ń€ ĐșĐ»ĐžĐ”ĐœŃ‚ĐŸĐČ",
"role_view-events": "ĐŸŃ€ĐŸŃĐŒĐŸŃ‚Ń€ ŃĐŸĐ±Ń‹Ń‚ĐžĐč",
"role_view-identity-providers": "ĐŸŃ€ĐŸŃĐŒĐŸŃ‚Ń€ ĐżŃ€ĐŸĐČаĐčĐŽĐ”Ń€ĐŸĐČ ŃƒŃ‡Đ”Ń‚ĐœŃ‹Ń… запОсДĐč",
"role_manage-realm": "УпраĐČĐ»Đ”ĐœĐžĐ” realm",
"role_manage-users": "УпраĐČĐ»Đ”ĐœĐžĐ” ĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Ń‚Đ”Đ»ŃĐŒĐž",
"role_manage-applications": "УпраĐČĐ»Đ”ĐœĐžĐ” ĐżŃ€ĐžĐ»ĐŸĐ¶Đ”ĐœĐžŃĐŒĐž",
"role_manage-identity-providers": "УпраĐČĐ»Đ”ĐœĐžĐ” ĐżŃ€ĐŸĐČаĐčĐŽĐ”Ń€Đ°ĐŒĐž ŃƒŃ‡Đ”Ń‚ĐœŃ‹Ń… запОсДĐč",
"role_manage-clients": "УпраĐČĐ»Đ”ĐœĐžĐ” ĐșĐ»ĐžĐ”ĐœŃ‚Đ°ĐŒĐž",
"role_manage-events": "УпраĐČĐ»Đ”ĐœĐžĐ” ŃĐŸĐ±Ń‹Ń‚ĐžŃĐŒĐž",
"role_view-profile": "ĐŸŃ€ĐŸŃĐŒĐŸŃ‚Ń€ ĐżŃ€ĐŸŃ„ĐžĐ»Ń",
"role_manage-account": "УпраĐČĐ»Đ”ĐœĐžĐ” ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč Đ·Đ°ĐżĐžŃŃŒŃŽ",
"role_read-token": "Đ§Ń‚Đ”ĐœĐžĐ” Ń‚ĐŸĐșĐ”ĐœĐ°",
"role_offline-access": "Đ”ĐŸŃŃ‚ŃƒĐż ĐŸŃ„Ń„Đ»Đ°ĐčĐœ",
"role_uma_authorization": "ĐŸĐŸĐ»ŃƒŃ‡Đ”ĐœĐžĐ” Ń€Đ°Đ·Ń€Đ”ŃˆĐ”ĐœĐžĐč",
"client_account": "ĐŁŃ‡Đ”Ń‚ĐœĐ°Ń Đ·Đ°ĐżĐžŃŃŒ",
"client_security-admin-console": "ĐšĐŸĐœŃĐŸĐ»ŃŒ Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€Đ° Đ±Đ”Đ·ĐŸĐżĐ°ŃĐœĐŸŃŃ‚Đž",
"client_admin-cli": "ĐšĐŸĐŒĐ°ĐœĐŽĐœŃ‹Đč ĐžĐœŃ‚Đ”Ń€Ń„Đ”Đčс Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€Đ°",
"client_realm-management": "УпраĐČĐ»Đ”ĐœĐžĐ” Realm",
"client_broker": "Đ‘Ń€ĐŸĐșДр",
"requiredFields": "ĐžĐ±ŃĐ·Đ°Ń‚Đ”Đ»ŃŒĐœŃ‹Đ” ĐżĐŸĐ»Ń",
"allFieldsRequired": "ВсД ĐżĐŸĐ»Ń ĐŸĐ±ŃĐ·Đ°Ń‚Đ”Đ»ŃŒĐœŃ‹",
"backToApplication": "&laquo; ĐĐ°Đ·Đ°ĐŽ ĐČ ĐżŃ€ĐžĐ»ĐŸĐ¶Đ”ĐœĐžĐ”",
"backTo": "ĐĐ°Đ·Đ°ĐŽ ĐČ {0}",
"date": "Дата",
"event": "ĐĄĐŸĐ±Ń‹Ń‚ĐžĐ”",
"ip": "IP",
"client": "ĐšĐ»ĐžĐ”ĐœŃ‚",
"clients": "ĐšĐ»ĐžĐ”ĐœŃ‚Ń‹",
"details": "ДДталО",
"started": "Начата",
"lastAccess": "ĐŸĐŸŃĐ»Đ”ĐŽĐœĐžĐč ĐŽĐŸŃŃ‚ŃƒĐż",
"expires": "Đ˜ŃŃ‚Đ”ĐșаДт",
"applications": "ĐŸŃ€ĐžĐ»ĐŸĐ¶Đ”ĐœĐžŃ",
"account": "ĐŁŃ‡Đ”Ń‚ĐœĐ°Ń Đ·Đ°ĐżĐžŃŃŒ",
"federatedIdentity": "ЀДЎДратОĐČĐœŃ‹Đč ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€",
"authenticator": "ĐŃƒŃ‚Đ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€",
"sessions": "ХДссОО",
"log": "Đ–ŃƒŃ€ĐœĐ°Đ»",
"application": "ĐŸŃ€ĐžĐ»ĐŸĐ¶Đ”ĐœĐžĐ”",
"availablePermissions": "Đ”ĐŸŃŃ‚ŃƒĐżĐœŃ‹Đ” Ń€Đ°Đ·Ń€Đ”ŃˆĐ”ĐœĐžŃ",
"grantedPermissions": "ĐĄĐŸĐłĐ»Đ°ŃĐŸĐČĐ°ĐœĐœŃ‹Đ” Ń€Đ°Đ·Ń€Đ”ŃˆĐ”ĐœĐžŃ",
"grantedPersonalInfo": "ĐĄĐŸĐłĐ»Đ°ŃĐŸĐČĐ°ĐœĐœĐ°Ń ĐżĐ”Ń€ŃĐŸĐœĐ°Đ»ŃŒĐœĐ°Ń ĐžĐœŃ„ĐŸŃ€ĐŒĐ°Ń†ĐžŃ",
"additionalGrants": "Đ”ĐŸĐżĐŸĐ»ĐœĐžŃ‚Đ”Đ»ŃŒĐœŃ‹Đ” ŃĐŸĐłĐ»Đ°ŃĐŸĐČĐ°ĐœĐžŃ",
"action": "ДДĐčстĐČОД",
"inResource": "ĐČ",
"fullAccess": "ĐŸĐŸĐ»ĐœŃ‹Đč ĐŽĐŸŃŃ‚ŃƒĐż",
"offlineToken": "ОффлаĐčĐœ Ń‚ĐŸĐșĐ”Đœ",
"revoke": "ĐžŃ‚ĐŸĐ·ĐČать ŃĐŸĐłĐ»Đ°ŃĐŸĐČĐ°ĐœĐžĐ”",
"configureAuthenticators": "ĐĄĐșĐŸĐœŃ„ĐžĐłŃƒŃ€ĐžŃ€ĐŸĐČĐ°ĐœĐœŃ‹Đ” Đ°ŃƒŃ‚Đ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Ń‹",
"mobile": "ĐœĐŸĐ±ĐžĐ»ŃŒĐœĐŸĐ” ĐżŃ€ĐžĐ»ĐŸĐ¶Đ”ĐœĐžĐ”",
"totpStep1":
'ĐŁŃŃ‚Đ°ĐœĐŸĐČОтД <a href="https://freeotp.github.io/" target="_blank">FreeOTP</a> ОлО Google Authenticator. Оба ĐżŃ€ĐžĐ»ĐŸĐ¶Đ”ĐœĐžŃ ĐŽĐŸŃŃ‚ŃƒĐżĐœŃ‹ ĐœĐ° <a href="https://play.google.com">Google Play</a> Đž ĐČ Apple App Store.',
"totpStep2": "ОтĐșŃ€ĐŸĐčтД ĐżŃ€ĐžĐ»ĐŸĐ¶Đ”ĐœĐžĐ” Đž ĐżŃ€ĐŸŃĐșĐ°ĐœĐžŃ€ŃƒĐčтД барĐșĐŸĐŽ, Đ»ĐžĐ±ĐŸ ĐČĐČДЎОтД Đșлюч.",
"totpStep3": "ВĐČДЎОтД ĐŸĐŽĐœĐŸŃ€Đ°Đ·ĐŸĐČыĐč ĐșĐŸĐŽ, ĐČŃ‹ĐŽĐ°ĐœĐœŃ‹Đč ĐżŃ€ĐžĐ»ĐŸĐ¶Đ”ĐœĐžĐ”ĐŒ, Đž ĐœĐ°Đ¶ĐŒĐžŃ‚Đ” ŃĐŸŃ…Ń€Đ°ĐœĐžŃ‚ŃŒ ĐŽĐ»Ń заĐČĐ”Ń€ŃˆĐ”ĐœĐžŃ ŃƒŃŃ‚Đ°ĐœĐŸĐČĐșĐž.",
"missingUsernameMessage": "ВĐČДЎОтД ĐžĐŒŃ ĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Ń‚Đ”Đ»Ń.",
"missingFirstNameMessage": "ВĐČДЎОтД ĐžĐŒŃ.",
"invalidEmailMessage": "ВĐČДЎОтД ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč E-mail.",
"missingLastNameMessage": "ВĐČДЎОтД Ń„Đ°ĐŒĐžĐ»ĐžŃŽ.",
"missingEmailMessage": "ВĐČДЎОтД E-mail.",
"missingPasswordMessage": "ВĐČДЎОтД ĐżĐ°Ń€ĐŸĐ»ŃŒ.",
"notMatchPasswordMessage": "ĐŸĐ°Ń€ĐŸĐ»Đž ĐœĐ” ŃĐŸĐČпаЮают.",
"missingTotpMessage": "ВĐČДЎОтД ĐșĐŸĐŽ Đ°ŃƒŃ‚Đ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Đ°.",
"invalidPasswordExistingMessage": "ĐĄŃƒŃ‰Đ”ŃŃ‚ĐČующоĐč ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐœĐ”ĐČĐ”Ń€ĐœŃ‹Đč.",
"invalidPasswordConfirmMessage": "ĐŸĐŸĐŽŃ‚ĐČĐ”Ń€Đ¶ĐŽĐ”ĐœĐžĐ” ĐżĐ°Ń€ĐŸĐ»Ń ĐœĐ” ŃĐŸĐČпаЎаДт.",
"invalidTotpMessage": "ĐĐ”ĐČĐ”Ń€ĐœŃ‹Đč ĐșĐŸĐŽ Đ°ŃƒŃ‚Đ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€Đ°.",
"usernameExistsMessage": "Đ˜ĐŒŃ ĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Ń‚Đ”Đ»Ń ужД ŃŃƒŃ‰Đ”ŃŃ‚ĐČŃƒĐ”Ń‚.",
"emailExistsMessage": "E-mail ужД ŃŃƒŃ‰Đ”ŃŃ‚ĐČŃƒĐ”Ń‚.",
"readOnlyUserMessage": "Вы ĐœĐ” ĐŒĐŸĐ¶Đ”Ń‚Đ” ĐŸĐ±ĐœĐŸĐČоть ĐžĐœŃ„ĐŸŃ€ĐŒĐ°Ń†ĐžŃŽ ĐČашДĐč ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč запОсО, т.Đș. ĐŸĐœĐ° ĐŽĐŸŃŃ‚ŃƒĐżĐœĐ° Ń‚ĐŸĐ»ŃŒĐșĐŸ ĐŽĐ»Ń Ń‡Ń‚Đ”ĐœĐžŃ.",
"readOnlyPasswordMessage": "Вы ĐœĐ” ĐŒĐŸĐ¶Đ”Ń‚Đ” ĐŸĐ±ĐœĐŸĐČоть ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐČашДĐč ŃƒŃ‡Đ”Ń‚ĐœĐŸĐč запОсО, т.Đș. ĐŸĐœ ĐŽĐŸŃŃ‚ŃƒĐżĐ”Đœ Ń‚ĐŸĐ»ŃŒĐșĐŸ ĐŽĐ»Ń Ń‡Ń‚Đ”ĐœĐžŃ.",
"successTotpMessage": "ĐŃƒŃ‚Đ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€ ĐČ ĐŒĐŸĐ±ĐžĐ»ŃŒĐœĐŸĐŒ ĐżŃ€ĐžĐ»ĐŸĐ¶Đ”ĐœĐžĐž сĐșĐŸĐœŃ„ĐžĐłŃƒŃ€ĐžŃ€ĐŸĐČĐ°Đœ.",
"successTotpRemovedMessage": "ĐŃƒŃ‚Đ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€ ĐČ ĐŒĐŸĐ±ĐžĐ»ŃŒĐœĐŸĐŒ ĐżŃ€ĐžĐ»ĐŸĐ¶Đ”ĐœĐžĐž ŃƒĐŽĐ°Đ»Đ”Đœ.",
"successGrantRevokedMessage": "ĐĄĐŸĐłĐ»Đ°ŃĐŸĐČĐ°ĐœĐžĐ” ĐŸŃ‚ĐŸĐ·ĐČĐ°ĐœĐŸ ŃƒŃĐżĐ”ŃˆĐœĐŸ.",
"accountUpdatedMessage": "Ваша ŃƒŃ‡Đ”Ń‚ĐœĐ°Ń Đ·Đ°ĐżĐžŃŃŒ ĐŸĐ±ĐœĐŸĐČĐ»Đ”ĐœĐ°.",
"accountPasswordUpdatedMessage": "Ваш ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐŸĐ±ĐœĐŸĐČĐ»Đ”Đœ.",
"missingIdentityProviderMessage": "ĐŸŃ€ĐŸĐČаĐčЎДр ŃƒŃ‡Đ”Ń‚ĐœŃ‹Ń… запОсДĐč ĐœĐ” Đ·Đ°ĐŽĐ°Đœ.",
"invalidFederatedIdentityActionMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœĐŸĐ” ОлО ĐœĐ”ĐŽĐŸĐżŃƒŃŃ‚ĐžĐŒĐŸĐ” ĐŽĐ”ĐčстĐČОД.",
"identityProviderNotFoundMessage": "Đ—Đ°ĐŽĐ°ĐœĐœŃ‹Đč ĐżŃ€ĐŸĐČаĐčЎДр ŃƒŃ‡Đ”Ń‚ĐœŃ‹Ń… запОсДĐč ĐœĐ” ĐœĐ°ĐčĐŽĐ”Đœ.",
"federatedIdentityLinkNotActiveMessage": "Đ˜ĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€ Đ±ĐŸĐ»ŃŒŃˆĐ” ĐœĐ” аĐșтоĐČĐ”Đœ.",
"federatedIdentityRemovingLastProviderMessage": "Вы ĐœĐ” ĐŒĐŸĐ¶Đ”Ń‚Đ” ŃƒĐŽĐ°Đ»ĐžŃ‚ŃŒ ĐżĐŸŃĐ»Đ”ĐŽĐœĐžĐč фДЎДратОĐČĐœŃ‹Đč ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€, т.Đș. Вы ĐœĐ” ĐžĐŒĐ”Đ”Ń‚Đ” ĐżĐ°Ń€ĐŸĐ»Ń.",
"identityProviderRedirectErrorMessage": "ĐžŃˆĐžĐ±Đșа ĐżĐ”Ń€Đ”ĐœĐ°ĐżŃ€Đ°ĐČĐ»Đ”ĐœĐžŃ ĐČ ĐżŃ€ĐŸĐČаĐčЎДр ŃƒŃ‡Đ”Ń‚ĐœŃ‹Ń… запОсДĐč.",
"identityProviderRemovedMessage": "ĐŸŃ€ĐŸĐČаĐčЎДр ŃƒŃ‡Đ”Ń‚ĐœŃ‹Ń… запОсДĐč ŃƒŃĐżĐ”ŃˆĐœĐŸ ŃƒĐŽĐ°Đ»Đ”Đœ.",
"identityProviderAlreadyLinkedMessage": "ЀДЎДратОĐČĐœŃ‹Đč ĐžĐŽĐ”ĐœŃ‚ĐžŃ„ĐžĐșĐ°Ń‚ĐŸŃ€, ĐČĐŸĐ·ĐČŃ€Đ°Ń‰Đ”ĐœĐœŃ‹Đč {0} ужД ĐžŃĐżĐŸĐ»ŃŒĐ·ŃƒĐ”Ń‚ŃŃ ĐŽŃ€ŃƒĐłĐžĐŒ ĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Ń‚Đ”Đ»Đ”ĐŒ.",
"staleCodeAccountMessage": "ĐĄŃ‚Ń€Đ°ĐœĐžŃ†Đ° ŃƒŃŃ‚Đ°Ń€Đ”Đ»Đ°. ĐŸĐŸĐżŃ€ĐŸĐ±ŃƒĐčтД ДщД раз.",
"consentDenied": "В ŃĐŸĐłĐ»Đ°ŃĐŸĐČĐ°ĐœĐžĐž ĐŸŃ‚ĐșĐ°Đ·Đ°ĐœĐŸ.",
"accountDisabledMessage": "ĐŁŃ‡Đ”Ń‚ĐœĐ°Ń Đ·Đ°ĐżĐžŃŃŒ Đ·Đ°Đ±Đ»ĐŸĐșĐžŃ€ĐŸĐČĐ°ĐœĐ°, ĐŸĐ±Ń€Đ°Ń‚ĐžŃ‚Đ”ŃŃŒ Đș Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€Ńƒ.",
"accountTemporarilyDisabledMessage": "ĐŁŃ‡Đ”Ń‚ĐœĐ°Ń Đ·Đ°ĐżĐžŃŃŒ ĐČŃ€Đ”ĐŒĐ”ĐœĐœĐŸ Đ·Đ°Đ±Đ»ĐŸĐșĐžŃ€ĐŸĐČĐ°ĐœĐ°, ĐŸĐ±Ń€Đ°Ń‚ĐžŃ‚Đ”ŃŃŒ Đș Đ°ĐŽĐŒĐžĐœĐžŃŃ‚Ń€Đ°Ń‚ĐŸŃ€Ńƒ ОлО ĐżĐŸĐżŃ€ĐŸĐ±ŃƒĐčтД ĐżĐŸĐ·Đ¶Đ”.",
"invalidPasswordMinLengthMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐŽĐ»ĐžĐœĐ° ĐżĐ°Ń€ĐŸĐ»Ń ĐŽĐŸĐ»Đ¶ĐœĐ° Đ±Ń‹Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} ŃĐžĐŒĐČĐŸĐ»Đ°(ĐŸĐČ).",
"invalidPasswordMinLowerCaseCharsMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} ŃĐžĐŒĐČĐŸĐ»Đ°(ĐŸĐČ) ĐČ ĐœĐžĐ¶ĐœĐ”ĐŒ рДгОстрД.",
"invalidPasswordMinDigitsMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} цофр(ы).",
"invalidPasswordMinUpperCaseCharsMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} ŃĐžĐŒĐČĐŸĐ»Đ°(ĐŸĐČ) ĐČ ĐČĐ”Ń€Ń…ĐœĐ”ĐŒ рДгОстрД.",
"invalidPasswordMinSpecialCharsMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐŽĐ”Ń€Đ¶Đ°Ń‚ŃŒ ĐœĐ” ĐŒĐ”ĐœĐ”Đ” {0} ŃĐżĐ”Ń†ŃĐžĐŒĐČĐŸĐ»Đ°(ĐŸĐČ).",
"invalidPasswordNotUsernameMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐœĐ” ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐČпаЮать с ĐžĐŒĐ”ĐœĐ”ĐŒ ĐżĐŸĐ»ŃŒĐ·ĐŸĐČĐ°Ń‚Đ”Đ»Ń.",
"invalidPasswordRegexPatternMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐœĐ” ŃƒĐŽĐŸĐČлДтĐČĐŸŃ€ŃĐ”Ń‚ Ń€Đ”ĐłŃƒĐ»ŃŃ€ĐœĐŸĐŒŃƒ ĐČŃ‹Ń€Đ°Đ¶Đ”ĐœĐžŃŽ.",
"invalidPasswordHistoryMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐœĐ” ĐŽĐŸĐ»Đ¶Đ”Đœ ŃĐŸĐČпаЮать с ĐżĐŸŃĐ»Đ”ĐŽĐœĐžĐŒ(Đž) {0} ĐżĐ°Ń€ĐŸĐ»ŃĐŒĐž.",
"invalidPasswordGenericMessage": "ĐĐ”ĐșĐŸŃ€Ń€Đ”ĐșŃ‚ĐœŃ‹Đč ĐżĐ°Ń€ĐŸĐ»ŃŒ: ĐœĐŸĐČыĐč ĐżĐ°Ń€ĐŸĐ»ŃŒ ĐœĐ” ŃĐŸĐŸŃ‚ĐČДтстĐČŃƒĐ”Ń‚ праĐČĐžĐ»Đ°ĐŒ ĐżĐ°Ń€ĐŸĐ»Ń."
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,180 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "UloĆŸiĆ„",
"doCancel": "ZruƥiƄ",
"doLogOutAllSessions": "OdhlĂĄsenie vĆĄetkĂœch relĂĄciĂ­",
"doRemove": "OdstråniƄ",
"doAdd": "PridaƄ",
"doSignOut": "OdhlåsiƄ",
"editAccountHtmlTitle": "UpraviĆ„ Ășčet",
"federatedIdentitiesHtmlTitle": "PrepojenĂĄ identita",
"accountLogHtmlTitle": "DennĂ­k zmien uĆŸĂ­vateÄŸskĂœch Ășčtov",
"changePasswordHtmlTitle": "Zmena hesla",
"sessionsHtmlTitle": "RelĂĄcie",
"accountManagementTitle": "SprĂĄva Ășčtu Keycloak",
"authenticatorTitle": "AutentifikĂĄtor",
"applicationsHtmlTitle": "AplikĂĄcie",
"authenticatorCode": "JednorĂĄzovĂœ kĂłd",
"email": "E-mail",
"firstName": "Meno",
"givenName": "Meno pri narodenĂ­",
"fullName": "Celé meno",
"lastName": "Priezvisko",
"familyName": "Rodné meno",
"password": "Heslo",
"passwordConfirm": "Potrvrdenie hesla",
"passwordNew": "Nové heslo",
"username": "Meno pouĆŸĂ­vateÄŸa",
"address": "Adresa",
"street": "Ulica",
"locality": "Mesto alebo lokalita",
"region": "Kraj",
"postal_code": "PSČ",
"country": "Ć tĂĄt",
"emailVerified": "E-mail overenĂœ",
"gssDelegationCredential": "GSS delegované opråvnenie",
"role_admin": "AdministrĂĄtor",
"role_realm-admin": "AdministrĂĄtor realmu",
"role_create-realm": "VytvoriƄ realm",
"role_view-realm": "ZobraziƄ realm",
"role_view-users": "ZobraziĆ„ pouĆŸĂ­vateÄŸov",
"role_view-applications": "ZobraziƄ aplikåcie",
"role_view-clients": "ZobraziƄ klientov",
"role_view-events": "ZobraziƄ udalosti",
"role_view-identity-providers": "ZobraziĆ„ klientov poskytovateÄŸov identity",
"role_manage-realm": "SpravovaƄ realm",
"role_manage-users": "SpravovaĆ„ pouĆŸĂ­vateÄŸov",
"role_manage-applications": "SpravovaƄ aplikåcie",
"role_manage-identity-providers": "SpravovaĆ„ poskytovateÄŸov identity",
"role_manage-clients": "SpravovaƄ klientov",
"role_manage-events": "SpravovaƄ udalosti",
"role_view-profile": "ZobraziƄ profil",
"role_manage-account": "SpravovaĆ„ Ășčet",
"role_manage-account-links": "SpravovaĆ„ odkazy na Ășčet",
"role_read-token": "ČítaĆ„ token",
"role_offline-access": "Offline prĂ­stup",
"role_uma_authorization": "AutorizĂĄcia pouĆŸĂ­vateÄŸom riadenĂ©ho prĂ­stupu",
"client_account": "Účet klienta",
"client_security-admin-console": "Bezpečnostná administrátorská konzola",
"client_admin-cli": "SpravovaƄ CLI klienta",
"client_realm-management": "SpravovaƄ realmy klienta",
"client_broker": "Broker",
"requiredFields": "Povinné polia",
"allFieldsRequired": "VĆĄetky poĆŸadovanĂ© polia",
"backToApplication": "&laquo; SpÀƄ na aplikåciu",
"backTo": "SpÀƄ na {0}",
"date": "DĂĄtum",
"event": "UdalosƄ",
"ip": "IP",
"client": "Klient",
"clients": "Klienti",
"details": "Podrobnosti",
"started": "Začíname",
"lastAccess": "PoslednĂœ prĂ­stup",
"expires": "VyprĆĄĂ­",
"applications": "AplikĂĄcie",
"account": "Účet",
"federatedIdentity": "PrepojenĂĄ identita",
"authenticator": "AutentifikĂĄtor",
"sessions": "RelĂĄcie",
"log": "DennĂ­k",
"application": "AplikĂĄcia",
"availablePermissions": "Dostupné opråvnenia",
"grantedPermissions": "Pridelené opråvnenia",
"grantedPersonalInfo": "Poskytnuté osobné informåcie",
"additionalGrants": "DodatočnĂ© oprĂĄvnenia",
"action": "Akcia",
"inResource": "v",
"fullAccess": "ÚplnĂœ prĂ­stup",
"offlineToken": "Offline token",
"revoke": "ZruƥiƄ opråvnenie",
"configureAuthenticators": "Nakonfigurované autentifikåtory",
"mobile": "MobilnĂœ",
"totpStep1":
'NainĆĄtalujte vo svojom zariadenĂ­ <a href="https://freeotp.github.io/" target="_blank"> FreeOTP </a> alebo Google Authenticator. Obidve aplikĂĄcie sĂș k dispozĂ­cii v <a href="https://play.google.com"> Google Play </a> a Apple App Store.',
"totpStep2": "Otvorte aplikĂĄciu a naskenujte čiarovĂœ kĂłd alebo zadajte kÄŸĂșč.",
"totpStep3": "Zadajte jednorazovĂœ kĂłd poskytnutĂœ aplikĂĄciou a kliknutĂ­m na tlačidlo UloĆŸiĆ„ dokončíte nastavenie.",
"totpManualStep2": "Otvorte aplikĂĄciu a zadajte kÄŸĂșč",
"totpManualStep3": "PouĆŸite nasledujĂșce hodnoty konfigurĂĄcie, ak aplikĂĄcia umoĆŸĆˆuje ich nastavenie",
"totpUnableToScan": "NemoĆŸno skenovaĆ„?",
"totpScanBarcode": "Skenovanie čiarovĂ©ho kĂłdu?",
"totp.totp": "ZaloĆŸenĂ© na čase",
"totp.hotp": "ZaloĆŸenĂ© na počítadle",
"totpType": "Typ",
"totpAlgorithm": "Algoritmus",
"totpDigits": "Číslica",
"totpInterval": "Interval",
"totpCounter": "Počítadlo",
"missingUsernameMessage": "Zadajte pouĆŸĂ­vateÄŸskĂ© meno.",
"missingFirstNameMessage": "Zadajte meno.",
"invalidEmailMessage": "NeplatnĂĄ e-mailovĂĄ adresa.",
"missingLastNameMessage": "Zadajte priezvisko.",
"missingEmailMessage": "Zadajte e-mail.",
"missingPasswordMessage": "Zadajte heslo, prosĂ­m.",
"notMatchPasswordMessage": "HeslĂĄ sa nezhodujĂș.",
"missingTotpMessage": "Zadajte jednorazovĂœ kĂłd, prosĂ­m",
"invalidPasswordExistingMessage": "NeplatnĂ© existujĂșce heslo.",
"invalidPasswordConfirmMessage": "Potvrdenie hesla sa nezhoduje.",
"invalidTotpMessage": "NeplatnĂœ jednorazovĂœ kĂłd.",
"usernameExistsMessage": "UĆŸĂ­vateÄŸskĂ© meno uĆŸ existuje.",
"emailExistsMessage": "E-mail uĆŸ existuje.",
"readOnlyUserMessage": "VĂĄĆĄ Ășčet nemĂŽĆŸete aktualizovaĆ„, pretoĆŸe je iba na čítanie.",
"readOnlyUsernameMessage": "NemĂŽĆŸete aktualizovaĆ„ svoje pouĆŸĂ­vateÄŸskĂ© meno, pretoĆŸe je iba na čítanie.",
"readOnlyPasswordMessage": "Heslo nemĂŽĆŸete aktualizovaĆ„, pretoĆŸe vĂĄĆĄ Ășčet je iba na čítanie.",
"successTotpMessage": "Konfiguråcia mobilného autentifikåtora.",
"successTotpRemovedMessage": "MobilnĂœ autentifikĂĄtor bol odstrĂĄnenĂœ.",
"successGrantRevokedMessage": "OprĂĄvnenie bolo ĂșspeĆĄne zruĆĄenĂ©.",
"accountUpdatedMessage": "VĂĄĆĄ Ășčet bol aktualizovanĂœ.",
"accountPasswordUpdatedMessage": "Vaƥe heslo bolo aktualizované.",
"missingIdentityProviderMessage": "PoskytovateÄŸ identity nie je zadanĂœ.",
"invalidFederatedIdentityActionMessage": "NeplatnĂĄ alebo chĂœbajĂșca akcia.",
"identityProviderNotFoundMessage": "ZadanĂœ poskytovateÄŸ identity nenĂĄjdenĂœ.",
"federatedIdentityLinkNotActiveMessage": "Identita uĆŸ nie je aktĂ­vna.",
"federatedIdentityRemovingLastProviderMessage": "NemĂŽĆŸete odstrĂĄniĆ„ poslednĂș spojenĂș identitu, pretoĆŸe nemĂĄte heslo.",
"identityProviderRedirectErrorMessage": "Nepodarilo sa presmerovaĆ„ na poskytovateÄŸa identity.",
"identityProviderRemovedMessage": "PoskytovateÄŸ identity bol ĂșspeĆĄne odstrĂĄnenĂœ.",
"identityProviderAlreadyLinkedMessage": "SpojenĂĄ identita vrĂĄtenĂĄ {0} je uĆŸ prepojenĂĄ s inĂœm pouĆŸĂ­vateÄŸom.",
"staleCodeAccountMessage": "PlatnosĆ„ vyprĆĄala. SkĂșste eĆĄte raz.",
"consentDenied": "SĂșhlas bol zamietnutĂœ.",
"accountDisabledMessage": "Účet je zakĂĄzanĂœ, kontaktujte sprĂĄvcu.",
"accountTemporarilyDisabledMessage": "Účet je dočasne zakĂĄzanĂœ, kontaktujte administrĂĄtora alebo skĂșste neskĂŽr.",
"invalidPasswordMinLengthMessage": "NeplatnĂ© heslo: minimĂĄlna dÄșĆŸka {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Neplatné heslo: musí obsahovaƄ minimålne {0} malé písmenå.",
"invalidPasswordMinDigitsMessage": "NeplatnĂ© heslo: musĂ­ obsahovaĆ„ aspoƈ {0} číslic.",
"invalidPasswordMinUpperCaseCharsMessage": "NeplatnĂ© heslo: musĂ­ obsahovaĆ„ aspoƈ {0} veÄŸkĂ© pĂ­smenĂĄ.",
"invalidPasswordMinSpecialCharsMessage": "Neplatné heslo: musí obsahovaƄ aspoƈ {0} ƥpeciålne znaky.",
"invalidPasswordNotUsernameMessage": "NeplatnĂ© heslo: nesmie byĆ„ rovnakĂ© ako pouĆŸĂ­vateÄŸskĂ© meno.",
"invalidPasswordRegexPatternMessage": "NeplatnĂ© heslo: nezodpovedĂĄ regulĂĄrnemu vĂœrazu.",
"invalidPasswordHistoryMessage": "NeplatnĂ© heslo: nesmie sa rovnaĆ„ ĆŸiadnemu z poslednĂœch {0} hesiel.",
"invalidPasswordBlacklistedMessage": "NeplatnĂ© heslo: heslo je na čiernej listine.",
"invalidPasswordGenericMessage": "Neplatné heslo: nové heslo nezodpovedå pravidlåm hesiel.",
"myResources": "Moje Zdroje",
"myResourcesSub": "Moje zdroje",
"doDeny": "ZakåzaƄ",
"doRevoke": "OdvolaƄ",
"doApprove": "SchvåliƄ",
"doRemoveSharing": "OdstrĂĄnenie zdieÄŸania",
"doRemoveRequest": "OdstrĂĄniĆ„ poĆŸiadavku",
"peopleAccessResource": "Äœudia s prĂ­stupom k tomuto zdroju",
"name": "NĂĄzov",
"scopes": "Rozsahy",
"resource": "Zdroj",
"user": "PouĆŸĂ­vateÄŸ",
"peopleSharingThisResource": "Äœudia zdieÄŸajĂșci tento zdroj",
"shareWithOthers": "ZdieÄŸaĆ„ s ostatnĂœmi",
"needMyApproval": "Potrebuje mĂŽj sĂșhlas",
"requestsWaitingApproval": "VaĆĄe poĆŸiadavky čakajĂș na schvĂĄlenie",
"icon": "Ikona",
"requestor": "ĆœiadateÄŸ",
"owner": "VlastnĂ­k",
"resourcesSharedWithMe": "Zdroje zdieÄŸanĂ© so mnou",
"permissionRequestion": "Ćœiadosti o povolenie",
"permission": "OprĂĄvnenie",
"shares": "podiel (y)"
};
export default messages;
/* spell-checker: enable */

View File

@ -0,0 +1,139 @@
//This code was automatically generated by running dist/bin/generate-i18n-messages.js
//PLEASE DO NOT EDIT MANUALLY
/* spell-checker: disable */
const messages = {
"doSave": "Spara",
"doCancel": "Avbryt",
"doLogOutAllSessions": "Logga ut frÄn samtliga sessioner",
"doRemove": "Ta bort",
"doAdd": "LĂ€gg till",
"doSignOut": "Logga ut",
"editAccountHtmlTitle": "Redigera konto",
"federatedIdentitiesHtmlTitle": "Federerade identiteter",
"accountLogHtmlTitle": "Kontologg",
"changePasswordHtmlTitle": "Byt lösenord",
"sessionsHtmlTitle": "Sessioner",
"accountManagementTitle": "Kontohantering för Keycloak",
"authenticatorTitle": "Autentiserare",
"applicationsHtmlTitle": "Applikationer",
"authenticatorCode": "EngÄngskod",
"email": "E-post",
"firstName": "Förnamn",
"lastName": "Efternamn",
"password": "Lösenord",
"passwordConfirm": "BekrÀftelse",
"passwordNew": "Nytt lösenord",
"username": "AnvÀndarnamn",
"address": "Adress",
"street": "Gata",
"locality": "Postort",
"region": "Stat, Provins eller Region",
"postal_code": "Postnummer",
"country": "Land",
"emailVerified": "E-post verifierad",
"gssDelegationCredential": "GSS Delegation Credential",
"role_admin": "Administratör",
"role_realm-admin": "Realm-administratör",
"role_create-realm": "Skapa realm",
"role_view-realm": "Visa realm",
"role_view-users": "Visa anvÀndare",
"role_view-applications": "Visa applikationer",
"role_view-clients": "Visa klienter",
"role_view-events": "Visa event",
"role_view-identity-providers": "Visa identitetsleverantörer",
"role_manage-realm": "Hantera realm",
"role_manage-users": "Hantera anvÀndare",
"role_manage-applications": "Hantera applikationer",
"role_manage-identity-providers": "Hantera identitetsleverantörer",
"role_manage-clients": "Hantera klienter",
"role_manage-events": "Hantera event",
"role_view-profile": "Visa profil",
"role_manage-account": "Hantera konto",
"role_read-token": "LĂ€s element",
"role_offline-access": "Åtkomst offline",
"role_uma_authorization": "ErhÄll tillstÄnd",
"client_account": "Konto",
"client_security-admin-console": "SÀkerhetsadministratörskonsol",
"client_admin-cli": "Administratörs-CLI",
"client_realm-management": "Realmhantering",
"requiredFields": "Obligatoriska fÀlt",
"allFieldsRequired": "Samtliga fÀlt krÀvs",
"backToApplication": "&laquo; Tillbaka till applikationen",
"backTo": "Tillbaka till {0}",
"date": "Datum",
"event": "Event",
"ip": "IP",
"client": "Klient",
"clients": "Klienter",
"details": "Detaljer",
"started": "Startade",
"lastAccess": "Senast Ätkomst",
"expires": "Upphör",
"applications": "Applikationer",
"account": "Konto",
"federatedIdentity": "Federerad identitet",
"authenticator": "Autentiserare",
"sessions": "Sessioner",
"log": "Logg",
"application": "Applikation",
"availablePermissions": "TillgÀngliga rÀttigheter",
"grantedPermissions": "Beviljade rÀttigheter",
"grantedPersonalInfo": "Medgiven personlig information",
"additionalGrants": "Ytterligare medgivanden",
"action": "ÅtgĂ€rd",
"inResource": "i",
"fullAccess": "FullstÀndig Ätkomst",
"offlineToken": "Offline token",
"revoke": "UpphÀv rÀttighet",
"configureAuthenticators": "Konfigurerade autentiserare",
"mobile": "Mobil",
"totpStep1":
'Installera <a href="https://freeotp.github.io/" target="_blank">FreeOTP</a> eller Google Authenticator pÄ din enhet. BÄda applikationerna finns tillgÀngliga pÄ <a href="https://play.google.com">Google Play</a> och Apple App Store.',
"totpStep2": "Öppna applikationen och skanna streckkoden eller skriv i nyckeln.",
"totpStep3": "Fyll i engÄngskoden som tillhandahÄlls av applikationen och klicka pÄ Spara för att avsluta instÀllningarna.",
"missingUsernameMessage": "VÀnligen ange anvÀndarnamn.",
"missingFirstNameMessage": "VÀnligen ange förnamn.",
"invalidEmailMessage": "Ogiltig e-postadress.",
"missingLastNameMessage": "VĂ€nligen ange efternamn.",
"missingEmailMessage": "VĂ€nligen ange e-post.",
"missingPasswordMessage": "VÀnligen ange lösenord.",
"notMatchPasswordMessage": "Lösenorden matchar inte.",
"missingTotpMessage": "VĂ€nligen ange autentiseringskoden.",
"invalidPasswordExistingMessage": "Det nuvarande lösenordet Àr ogiltigt.",
"invalidPasswordConfirmMessage": "LösenordsbekrÀftelsen matchar inte.",
"invalidTotpMessage": "Autentiseringskoden Àr ogiltig.",
"usernameExistsMessage": "AnvÀndarnamnet finns redan.",
"emailExistsMessage": "E-posten finns redan.",
"readOnlyUserMessage": "Du kan inte uppdatera ditt konto eftersom det Àr skrivskyddat.",
"readOnlyPasswordMessage": "Du kan inte uppdatera ditt lösenord eftersom ditt konto Àr skrivskyddat.",
"successTotpMessage": "Mobilautentiseraren Àr instÀlld.",
"successTotpRemovedMessage": "Mobilautentiseraren Àr borttagen.",
"successGrantRevokedMessage": "UpphÀvandet av rÀttigheten lyckades.",
"accountUpdatedMessage": "Ditt konto har uppdaterats.",
"accountPasswordUpdatedMessage": "Ditt lösenord har uppdaterats.",
"missingIdentityProviderMessage": "Identitetsleverantör Àr inte angiven.",
"invalidFederatedIdentityActionMessage": "ÅtgĂ€rden Ă€r ogiltig eller saknas.",
"identityProviderNotFoundMessage": "Angiven identitetsleverantör hittas inte.",
"federatedIdentityLinkNotActiveMessage": "Den hÀr identiteten Àr inte lÀngre aktiv.",
"federatedIdentityRemovingLastProviderMessage": "Du kan inte ta bort senaste federerade identiteten eftersom du inte har ett lösenord.",
"identityProviderRedirectErrorMessage": "Misslyckades med att omdirigera till identitetsleverantör.",
"identityProviderRemovedMessage": "Borttagningen av identitetsleverantören lyckades.",
"identityProviderAlreadyLinkedMessage": "Den federerade identiteten som returnerades av {0} Àr redan lÀnkad till en annan anvÀndare.",
"staleCodeAccountMessage": "Sidan har upphört att gÀlla. VÀnligen försök igen.",
"consentDenied": "Samtycket förnekades.",
"accountDisabledMessage": "Kontot Àr inaktiverat, kontakta administratör.",
"accountTemporarilyDisabledMessage": "Kontot Àr tillfÀlligt inaktiverat, kontakta administratör eller försök igen senare.",
"invalidPasswordMinLengthMessage": "Ogiltigt lösenord. Minsta lÀngd Àr {0}.",
"invalidPasswordMinLowerCaseCharsMessage": "Ogiltigt lösenord: mÄste innehÄlla minst {0} smÄ bokstÀver.",
"invalidPasswordMinDigitsMessage": "Ogiltigt lösenord: mÄste innehÄlla minst {0} siffror.",
"invalidPasswordMinUpperCaseCharsMessage": "Ogiltigt lösenord: mÄste innehÄlla minst {0} stora bokstÀver.",
"invalidPasswordMinSpecialCharsMessage": "Ogiltigt lösenord: mÄste innehÄlla minst {0} specialtecken.",
"invalidPasswordNotUsernameMessage": "Ogiltigt lösenord: FÄr inte vara samma som anvÀndarnamnet.",
"invalidPasswordRegexPatternMessage": "Ogiltigt lösenord: matchar inte kravet för lösenordsmönster.",
"invalidPasswordHistoryMessage": "Ogiltigt lösenord: FÄr inte vara samma som de senaste {0} lösenorden.",
"invalidPasswordGenericMessage": "Ogiltigt lösenord: Det nya lösenordet stÀmmer inte med lösenordspolicyn."
};
export default messages;
/* spell-checker: enable */

Some files were not shown because too many files have changed in this diff Show More