2.8. 管理ユーザー API を通じてユーザーを更新する際のユーザー属性の部分的な更新がサポート対象外に
管理ユーザー API を介してユーザー属性を更新する場合は、username
、email
、firstName
、lastName
などのルート属性を含むユーザー属性を更新するときに、部分的な更新ができません。
2.8.1. 非推奨の auto-build
CLI オプションの削除
auto-build
CLI オプションは、長い間、非推奨とマークされていました。このリリースで完全に削除され、サポートされなくなりました。
start
コマンドを実行すると、設定に基づいてサーバーが自動的に構築されます。この動作を防ぐには、--optimized
フラグを設定します。
2.8.2. イベントの詳細の長さを短縮するオプションの削除
このリリース以降、Keycloak は EventEntity
詳細列の長い値をサポートします。そのため、イベントの詳細の長さを短縮するためのオプション --spi-events-store-jpa-max-detail-length
および --spi-events-store-jpa-max-field-length
がサポートされなくなりました。
2.8.3. 翻訳からの名前空間の削除
すべての翻訳を admin-ui の 1 つのファイルに移動しました。独自の翻訳を作成したり、admin-ui を拡張したりした場合は、この新しい形式に移行する必要があります。また、データベースに "オーバーライド" がある場合は、キーから名前空間を削除する必要があります。一部のキーは名前空間を除いて同じです。これが最もわかりやすいのは help です。このような場合には、キーの末尾に Help
が付いています。
必要に応じて、次のノードスクリプトを使用して移行に役立てることができます。このスクリプトは、すべての単一ファイルを取得して新しいファイルに格納し、さらにマッピングの一部を処理します。
import { readFileSync, writeFileSync, appendFileSync } from "node:fs"; const ns = [ "common", "common-help", "dashboard", "clients", "clients-help", "client-scopes", "client-scopes-help", "groups", "realm", "roles", "users", "users-help", "sessions", "events", "realm-settings", "realm-settings-help", "authentication", "authentication-help", "user-federation", "user-federation-help", "identity-providers", "identity-providers-help", "dynamic", ]; const map = new Map(); const dup = []; ns.forEach((n) => { const rawData = readFileSync(n + ".json"); const translation = JSON.parse(rawData); Object.entries(translation).map((e) => { const name = e[0]; const value = e[1]; if (map.has(name) && map.get(name) !== value) { if (n.includes("help")) { map.set(name + "Help", value); } else { map.set(name, value); dup.push({ name: name, value: map.get(name), dup: { ns: n, value: value }, }); } } else { map.set(name, value); } }); }); writeFileSync( "translation.json", JSON.stringify(Object.fromEntries(map.entries()), undefined, 2), ); const mapping = [ ["common:clientScope", "clientScopeType"], ["identity-providers:createSuccess", "createIdentityProviderSuccess"], ["identity-providers:createError", "createIdentityProviderError"], ["clients:createError", "createClientError"], ["clients:createSuccess", "createClientSuccess"], ["user-federation:createSuccess", "createUserProviderSuccess"], ["user-federation:createError", "createUserProviderError"], ["authentication-help:name", "flowNameHelp"], ["authentication-help:description", "flowDescriptionHelp"], ["clientScopes:noRoles", "noRoles-clientScope"], ["clientScopes:noRolesInstructions", "noRolesInstructions-clientScope"], ["users:noRoles", "noRoles-user"], ["users:noRolesInstructions", "noRolesInstructions-user"], ["clients:noRoles", "noRoles-client"], ["clients:noRolesInstructions", "noRolesInstructions-client"], ["groups:noRoles", "noRoles-group"], ["groups:noRolesInstructions", "noRolesInstructions-group"], ["roles:noRoles", "noRoles-roles"], ["roles:noRolesInstructions", "noRolesInstructions-roles"], ["realm:realmName:", "realmNameField"], ["client-scopes:searchFor", "searchForClientScope"], ["roles:searchFor", "searchForRoles"], ["authentication:title", "titleAuthentication"], ["events:title", "titleEvents"], ["roles:title", "titleRoles"], ["users:title", "titleUsers"], ["sessions:title", "titleSessions"], ["client-scopes:deleteConfirm", "deleteConfirmClientScopes"], ["users:deleteConfirm", "deleteConfirmUsers"], ["groups:deleteConfirm_one", "deleteConfirmGroup_one"], ["groups:deleteConfirm_other", "deleteConfirmGroup_other"], ["identity-providers:deleteConfirm", "deleteConfirmIdentityProvider"], ["realm-settings:deleteConfirm", "deleteConfirmRealmSetting"], ["roles:whoWillAppearLinkText", "whoWillAppearLinkTextRoles"], ["users:whoWillAppearLinkText", "whoWillAppearLinkTextUsers"], ["roles:whoWillAppearPopoverText", "whoWillAppearPopoverTextRoles"], ["users:whoWillAppearPopoverText", "whoWillAppearPopoverTextUsers"], ["client-scopes:deletedSuccess", "deletedSuccessClientScope"], ["identity-providers:deletedSuccess", "deletedSuccessIdentityProvider"], ["realm-settings:deleteSuccess", "deletedSuccessRealmSetting"], ["client-scopes:deleteError", "deletedErrorClientScope"], ["identity-providers:deleteError", "deletedErrorIdentityProvider"], ["realm-settings:deleteError", "deletedErrorRealmSetting"], ["realm-settings:saveSuccess", "realmSaveSuccess"], ["user-federation:saveSuccess", "userProviderSaveSuccess"], ["realm-settings:saveError", "realmSaveError"], ["user-federation:saveError", "userProviderSaveError"], ["realm-settings:validateName", "validateAttributeName"], ["identity-providers:disableConfirm", "disableConfirmIdentityProvider"], ["realm-settings:disableConfirm", "disableConfirmRealm"], ["client-scopes:updateSuccess", "updateSuccessClientScope"], ["client-scopes:updateError", "updateErrorClientScope"], ["identity-providers:updateSuccess", "updateSuccessIdentityProvider"], ["identity-providers:updateError", "updateErrorIdentityProvider"], ["user-federation:orderChangeSuccess", "orderChangeSuccessUserFed"], ["user-federation:orderChangeError", "orderChangeErrorUserFed"], ["authentication-help:alias", "authenticationAliasHelp"], ["authentication-help:flowType", "authenticationFlowTypeHelp"], ["authentication:createFlow", "authenticationCreateFlowHelp"], ["client-scopes-help:rolesScope", "clientScopesRolesScope"], ["client-scopes-help:name", "scopeNameHelp"], ["client-scopes-help:description", "scopeDescriptionHelp"], ["client-scopes-help:type", "scopeTypeHelp"], ["clients-help:description", "clientDescriptionHelp"], ["clients-help:clientType", "clientsClientTypeHelp"], ["clients-help:scopes", "clientsClientScopesHelp"], ["common:clientScope", "clientScopeTypes"], ["dashboard:realmName", "realmNameTitle"], ["common:description", "description"], ]; mapping.forEach((m) => { const key = m[0].split(":"); try { const data = readFileSync(key[0] + ".json"); const translation = JSON.parse(data); const value = translation[key[1]]; if (value) { appendFileSync( "translation.json", '"' + m[1] + '": ' + JSON.stringify(value) + ',\n', ); } } catch (error) { console.error("skipping namespace key: " + key); } });
これを public/locale/<language>
フォルダー内の transform.mjs
というファイルに保存し、次のコマンドで実行します。
node ./transform.mjs
これでは完全な変換を実行できない可能性がありますが、それに非常に近いものになります。