From b919f600e10f11fe9eee05b13901e789f166d9b6 Mon Sep 17 00:00:00 2001 From: kyy Date: Tue, 9 Jun 2026 17:49:22 +0900 Subject: [PATCH] =?UTF-8?q?=EB=88=84=EB=9D=BD=20locale=20=ED=82=A4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EB=A6=B0=ED=8A=B8=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/clients/ClientGeneralPage.tsx | 7 +- devfront/src/features/clients/ClientsPage.tsx | 19 +++-- .../developer-access/developerAccessPages.ts | 10 +-- .../developer-grants/DeveloperGrantsPage.tsx | 70 ++++++++--------- .../DeveloperRequestPage.tsx | 31 ++++---- devfront/src/lib/devApi.ts | 9 ++- devfront/src/locales/en.toml | 4 + devfront/src/locales/ko.toml | 4 + locales/en.toml | 55 ++++++++++++++ locales/ko.toml | 76 +++++++++++++++++++ locales/template.toml | 55 ++++++++++++++ 11 files changed, 266 insertions(+), 74 deletions(-) diff --git a/devfront/src/features/clients/ClientGeneralPage.tsx b/devfront/src/features/clients/ClientGeneralPage.tsx index 69eb77c0..ec409582 100644 --- a/devfront/src/features/clients/ClientGeneralPage.tsx +++ b/devfront/src/features/clients/ClientGeneralPage.tsx @@ -17,6 +17,7 @@ import { useCallback, useEffect, useState } from "react"; import { useAuth } from "react-oidc-context"; import { Link, useNavigate, useParams } from "react-router-dom"; import { PageHeader } from "../../../../common/core/components/page"; +import { DeveloperAccessRequestCard } from "../../components/common/DeveloperAccessRequestCard"; import { Badge } from "../../components/ui/badge"; import { Button } from "../../components/ui/button"; import { @@ -30,7 +31,6 @@ import { Input } from "../../components/ui/input"; import { Label } from "../../components/ui/label"; import { Switch } from "../../components/ui/switch"; import { Textarea } from "../../components/ui/textarea"; -import { DeveloperAccessRequestCard } from "../../components/common/DeveloperAccessRequestCard"; import { toast } from "../../components/ui/use-toast"; import type { ClientStatus, @@ -1208,7 +1208,10 @@ function ClientGeneralPage() { "msg.dev.clients.general.create_forbidden_detail", "개발자 권한 신청에서 연동 앱 추가 권한을 선택한 뒤 승인받아주세요.", )} - actionLabel={t("ui.dev.welcome.btn_request", "개발자 등록 신청하기")} + actionLabel={t( + "ui.dev.welcome.btn_request", + "개발자 등록 신청하기", + )} onAction={() => navigate("/developer-requests")} /> diff --git a/devfront/src/features/clients/ClientsPage.tsx b/devfront/src/features/clients/ClientsPage.tsx index a771ab34..1586fd40 100644 --- a/devfront/src/features/clients/ClientsPage.tsx +++ b/devfront/src/features/clients/ClientsPage.tsx @@ -17,11 +17,11 @@ import { toggleSort, } from "../../../../common/core/utils"; import { SearchFilterBar } from "../../../../common/ui/search-filter-bar"; -import { DeveloperAccessRequestCard } from "../../components/common/DeveloperAccessRequestCard"; import { commonTableShellClass, commonTableViewportClass, } from "../../../../common/ui/table"; +import { DeveloperAccessRequestCard } from "../../components/common/DeveloperAccessRequestCard"; import { ForbiddenMessage } from "../../components/common/ForbiddenMessage"; import { Badge } from "../../components/ui/badge"; import { Button } from "../../components/ui/button"; @@ -243,7 +243,10 @@ function ClientsPage() { "msg.dev.clients.access_denied_detail", "개발자 권한 신청에서 개요 또는 연동 앱 추가 권한을 선택한 뒤 승인받아주세요.", )} - actionLabel={t("ui.dev.welcome.btn_request", "개발자 등록 신청하기")} + actionLabel={t( + "ui.dev.welcome.btn_request", + "개발자 등록 신청하기", + )} onAction={() => navigate("/developer-requests")} /> @@ -506,11 +509,11 @@ function ClientsPage() { "msg.dev.clients.empty_can_create", "아직 등록된 연동 앱이 없습니다.", ) - : isClientCreatePending - ? t( - "msg.dev.clients.empty_pending", - "개발자 권한 신청을 검토 중입니다.", - ) + : isClientCreatePending + ? t( + "msg.dev.clients.empty_pending", + "개발자 권한 신청을 검토 중입니다.", + ) : t( "msg.dev.clients.empty", "조회 가능한 RP가 없습니다.", @@ -528,7 +531,7 @@ function ClientsPage() { "msg.dev.clients.empty_can_create_detail", "연동 앱 추가 버튼으로 새 RP를 생성하면 이 목록에 표시됩니다.", ) - : isClientCreatePending + : isClientCreatePending ? t( "msg.dev.clients.empty_pending_detail", "super admin이 승인하면 연동 앱을 추가할 수 있습니다.", diff --git a/devfront/src/features/developer-access/developerAccessPages.ts b/devfront/src/features/developer-access/developerAccessPages.ts index 4cc4c29c..ce7608f1 100644 --- a/devfront/src/features/developer-access/developerAccessPages.ts +++ b/devfront/src/features/developer-access/developerAccessPages.ts @@ -25,18 +25,16 @@ export function normalizeDeveloperAccessPages( ): DeveloperAccessPage[] { const normalized = new Set(); for (const raw of pages) { - const page = String(raw ?? "").trim().toLowerCase(); + const page = String(raw ?? "") + .trim() + .toLowerCase(); if (!page) { continue; } if (page === "all") { return ["all"]; } - if ( - page === "overview" || - page === "client_create" || - page === "audit" - ) { + if (page === "overview" || page === "client_create" || page === "audit") { normalized.add(page); } } diff --git a/devfront/src/features/developer-grants/DeveloperGrantsPage.tsx b/devfront/src/features/developer-grants/DeveloperGrantsPage.tsx index f412d369..8b967b86 100644 --- a/devfront/src/features/developer-grants/DeveloperGrantsPage.tsx +++ b/devfront/src/features/developer-grants/DeveloperGrantsPage.tsx @@ -27,20 +27,20 @@ import { Textarea } from "../../components/ui/textarea"; import { toast } from "../../components/ui/use-toast"; import { createDeveloperGrant, - fetchDeveloperGrants, - fetchDevUsers, - fetchDevUser, - revokeDeveloperGrant, type DevAssignableUser, + fetchDeveloperGrants, + fetchDevUser, + fetchDevUsers, + revokeDeveloperGrant, } from "../../lib/devApi"; import { t } from "../../lib/i18n"; import { resolveProfileRole } from "../../lib/role"; import { fetchMe } from "../auth/authApi"; import { - developerAccessPageOptions, - normalizeDeveloperAccessPages, - normalizeDeveloperAccessPageSelection, type DeveloperAccessPage, + developerAccessPageOptions, + normalizeDeveloperAccessPageSelection, + normalizeDeveloperAccessPages, } from "../developer-access/developerAccessPages"; function formatUserLabel(user: DevAssignableUser) { @@ -74,10 +74,7 @@ export default function DeveloperGrantsPage() { const [grantNotes, setGrantNotes] = useState(""); const [adminNotes, setAdminNotes] = useState>({}); - const { - data: userSearchData, - isFetching: isUserSearchLoading, - } = useQuery({ + const { data: userSearchData, isFetching: isUserSearchLoading } = useQuery({ queryKey: ["developer-grant-users", deferredUserSearch], queryFn: () => fetchDevUsers(deferredUserSearch, 10), enabled: @@ -87,14 +84,12 @@ export default function DeveloperGrantsPage() { selectedUser == null, }); - const { - data: selectedUserDetail, - isFetching: isSelectedUserDetailLoading, - } = useQuery({ - queryKey: ["developer-grant-user", selectedUser?.id], - queryFn: () => fetchDevUser(selectedUser?.id || ""), - enabled: hasAccessToken && isSuperAdmin && selectedUser != null, - }); + const { data: selectedUserDetail, isFetching: isSelectedUserDetailLoading } = + useQuery({ + queryKey: ["developer-grant-user", selectedUser?.id], + queryFn: () => fetchDevUser(selectedUser?.id || ""), + enabled: hasAccessToken && isSuperAdmin && selectedUser != null, + }); const { data: grants, @@ -145,13 +140,8 @@ export default function DeveloperGrantsPage() { }); const revokeGrantMutation = useMutation({ - mutationFn: ({ - id, - adminNotes, - }: { - id: number; - adminNotes: string; - }) => revokeDeveloperGrant(id, adminNotes), + mutationFn: ({ id, adminNotes }: { id: number; adminNotes: string }) => + revokeDeveloperGrant(id, adminNotes), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["developer-grants"] }); toast( @@ -203,10 +193,7 @@ export default function DeveloperGrantsPage() { const handleGrant = () => { if (!selectedUser) { toast( - t( - "msg.dev.grants.user_required", - "부여할 사용자를 선택해주세요.", - ), + t("msg.dev.grants.user_required", "부여할 사용자를 선택해주세요."), "error", ); return; @@ -374,10 +361,7 @@ export default function DeveloperGrantsPage() {
- {t( - "ui.dev.grants.selected_info", - "선택된 사용자 정보", - )} + {t("ui.dev.grants.selected_info", "선택된 사용자 정보")} {t("ui.dev.grants.read_only", "읽기 전용")} @@ -476,7 +460,9 @@ export default function DeveloperGrantsPage() { handleAccessPageToggle(option.value)} + onChange={() => + handleAccessPageToggle(option.value) + } /> {option.label} @@ -577,8 +563,12 @@ export default function DeveloperGrantsPage() { {t("ui.dev.grants.user", "사용자")} {t("ui.dev.grants.tenant", "테넌트")} - {t("ui.dev.grants.reason", "부여 사유")} - {t("ui.dev.grants.pages", "권한 페이지")} + + {t("ui.dev.grants.reason", "부여 사유")} + + + {t("ui.dev.grants.pages", "권한 페이지")} + {t("ui.dev.grants.status", "상태")} {t("ui.dev.grants.date", "부여일")} @@ -597,7 +587,7 @@ export default function DeveloperGrantsPage() {
{grant.email || grant.userId}
-
+
{grant.userId}
@@ -605,7 +595,9 @@ export default function DeveloperGrantsPage() {
- {grant.organization || grant.tenantId || t("ui.common.na", "없음")} + {grant.organization || + grant.tenantId || + t("ui.common.na", "없음")}
{grant.tenantId || t("ui.common.na", "없음")} diff --git a/devfront/src/features/developer-request/DeveloperRequestPage.tsx b/devfront/src/features/developer-request/DeveloperRequestPage.tsx index a16cb7e2..5f11a631 100644 --- a/devfront/src/features/developer-request/DeveloperRequestPage.tsx +++ b/devfront/src/features/developer-request/DeveloperRequestPage.tsx @@ -48,10 +48,10 @@ import { t } from "../../lib/i18n"; import { resolveProfileRole } from "../../lib/role"; import { fetchMe } from "../auth/authApi"; import { - developerAccessPageOptions, - normalizeDeveloperAccessPages, - normalizeDeveloperAccessPageSelection, type DeveloperAccessPage, + developerAccessPageOptions, + normalizeDeveloperAccessPageSelection, + normalizeDeveloperAccessPages, } from "../developer-access/developerAccessPages"; export default function DeveloperRequestPage() { @@ -158,9 +158,7 @@ export default function DeveloperRequestPage() { ); } - const hasActiveRequest = requests?.some( - (r) => r.status === "pending", - ); + const hasActiveRequest = requests?.some((r) => r.status === "pending"); const approvedRequestCount = requests?.filter((request) => request.status === "approved").length ?? 0; const isActionPending = @@ -269,7 +267,8 @@ export default function DeveloperRequestPage() { )} - {req.organization?.trim() || t("ui.common.na", "없음")} + {req.organization?.trim() || + t("ui.common.na", "없음")}
@@ -284,15 +283,15 @@ export default function DeveloperRequestPage() {
{req.accessPages?.length ? ( - normalizeDeveloperAccessPages(req.accessPages).map( - (page) => ( - - {developerAccessPageOptions.find( - (option) => option.value === page, - )?.label ?? page} - - ), - ) + normalizeDeveloperAccessPages( + req.accessPages, + ).map((page) => ( + + {developerAccessPageOptions.find( + (option) => option.value === page, + )?.label ?? page} + + )) ) : ( {t("ui.common.na", "없음")} diff --git a/devfront/src/lib/devApi.ts b/devfront/src/lib/devApi.ts index 0ba3c63a..d7488cb1 100644 --- a/devfront/src/lib/devApi.ts +++ b/devfront/src/lib/devApi.ts @@ -607,9 +607,12 @@ export async function cancelDeveloperRequestApproval( } export async function fetchDeveloperGrants(tenantId?: string) { - const { data } = await apiClient.get("/dev/developer-grants", { - params: { tenantId }, - }); + const { data } = await apiClient.get( + "/dev/developer-grants", + { + params: { tenantId }, + }, + ); return data; } diff --git a/devfront/src/locales/en.toml b/devfront/src/locales/en.toml index 5844575b..3c97cb22 100644 --- a/devfront/src/locales/en.toml +++ b/devfront/src/locales/en.toml @@ -331,6 +331,7 @@ user_desc = "Review your request history and submit a new access request." desc = "Please enter the reason for your request. It will be approved after administrator review." tenant_required = "Please submit a developer access request." tenant_required_detail = "Enter a request reason and submit it for administrator review." +pages_hint = "If you select All, Overview, Add linked app, and Audit Logs are all included." [msg.dev.clients] load_error = "Error loading clients: {{error}}" @@ -1348,6 +1349,7 @@ form.title = "Direct Grant" grant = "Grant Directly" input_section = "Input" list.title = "Granted Access" +pages = "Access Pages" read_only = "Read Only" reason = "Grant Reason" reason_placeholder = "e.g. Developer console access is required for operational support." @@ -1365,6 +1367,7 @@ user_search_placeholder = "Search by name or email..." email = "Email" name = "Name" org = "Organization" +pages = "Access Pages" phone = "Phone Number" reason = "Reason" reason_placeholder = "e.g. I need to create an OIDC client for internal service integration and testing." @@ -1382,6 +1385,7 @@ actions = "Actions" date = "Requested At" org = "Organization" reason = "Reason" +pages = "Access Pages" status = "Status" user = "User" diff --git a/devfront/src/locales/ko.toml b/devfront/src/locales/ko.toml index ab055458..4f7920c6 100644 --- a/devfront/src/locales/ko.toml +++ b/devfront/src/locales/ko.toml @@ -331,6 +331,7 @@ user_desc = "내 신청 내역을 확인하고 새로운 권한을 신청할 수 desc = "신청 사유를 입력해 주세요. 관리자 확인 후 승인됩니다." tenant_required = "개발자 권한 신청을 진행해 주세요." tenant_required_detail = "신청 사유를 입력해 제출하면 관리자 검토 후 승인됩니다." +pages_hint = "전체를 선택하면 개요, 연동 앱 추가, 감사로그가 모두 포함됩니다." [msg.dev.clients] deleted = "앱이 삭제되었습니다." @@ -1348,6 +1349,7 @@ form.title = "직접 부여" grant = "직접 부여" input_section = "입력" list.title = "부여된 권한" +pages = "권한 페이지" read_only = "읽기 전용" reason = "부여 사유" reason_placeholder = "예: 운영 지원을 위해 개발 콘솔 접근이 필요합니다." @@ -1365,6 +1367,7 @@ user_search_placeholder = "이름 또는 이메일 검색..." email = "이메일" name = "성함" org = "소속" +pages = "권한 페이지" phone = "전화번호" reason = "신청 사유" reason_placeholder = "예: 자체 서비스 연동 및 테스트용 OIDC 클라이언트 생성이 필요합니다." @@ -1382,6 +1385,7 @@ actions = "관리" date = "신청일" org = "소속" reason = "신청 사유" +pages = "권한 페이지" status = "상태" user = "사용자" diff --git a/locales/en.toml b/locales/en.toml index 000444dc..58d38cc0 100644 --- a/locales/en.toml +++ b/locales/en.toml @@ -420,8 +420,37 @@ phone = "Phone" reason = "Request Reason" reason_placeholder = "Explain why you need developer access." role = "Role" +pages_hint = "If you select All, Overview, Add linked app, and Audit Logs are all included." title = "Developer Registration Request" +[msg.dev.grants] +admin_notes_description = "Leaving a short note for the direct grant helps later reviews and revocations." +admin_notes_hint = "Revocations are handled from the list below." +admin_notes_placeholder = "e.g. Grant access after verifying the test environment" +approved = "Approved" +count = "Total {{count}}" +create_success = "Developer access has been granted directly." +description = "Directly grant developer access to users and revoke granted access." +empty = "There are no granted permissions." +forbidden = "Only super admin can directly grant developer access." +forbidden_desc = "This screen is available only to super admin." +form.description = "Select a user to view their current tenant, email, and phone, then grant developer access immediately." +list.description = "Current developer access grants." +load_error = "Failed to load developer access grants." +pages_hint = "If you select All, Overview, Add linked app, and Audit Logs are all included." +phone_missing = "No phone number is registered." +reason = "Grant reason" +revoke = "Revoke" +revoke_success = "Developer access has been revoked." +search_empty = "No users found." +search_loading = "Searching users..." +selected_info_description = "Review the selected user's tenant, email, and phone." +selected_user = "Selected user: {{user}}" +tenant_missing = "No tenant information is available for the selected user." +tenant_required = "The selected user's tenant information is unavailable." +user_required = "Select a user before granting access." +user_section_description = "Enter a search term to select a user. The next-step information stays empty until a user is chosen." + [msg.dev.request.status] approved = "Approved" cancelled = "Approval Cancelled" @@ -2377,6 +2406,7 @@ overview = "Overview" clients = "Connected Application" logout = "Logout" developer_request = "Developer Access Request" +developer_grants = "Developer Access Grants" [ui.dev.welcome] btn_request = "New Request" @@ -2394,6 +2424,7 @@ desc = "Review the information below and enter a request reason to apply for dev email = "Email" name = "Name" org = "Organization" +pages = "Access Pages" phone = "Phone" reason = "Request Reason" reason_placeholder = "Explain why you need developer access." @@ -2411,9 +2442,33 @@ actions = "Actions" date = "Requested At" org = "Organization" reason = "Request Reason" +pages = "Access Pages" status = "Status" user = "User" +[ui.dev.grants] +actions = "Actions" +admin_notes = "Grant Reason" +approved = "Approved" +date = "Granted At" +email = "Email" +form.title = "Direct Grant" +grant = "Grant Directly" +input_section = "Input" +list.title = "Granted Access" +pages = "Access Pages" +read_only = "Read Only" +reason = "Grant Reason" +revoke = "Revoke" +revoke_notes_placeholder = "Revoke note (optional)..." +selected_info = "Selected User Info" +status = "Status" +phone = "Phone Number" +tenant = "Affiliation" +user = "User" +user_search_placeholder = "Search by name or email..." +user_section = "User Selection" + [ui.dev.profile] error = "Failed to load profile." loading = "Loading profile..." diff --git a/locales/ko.toml b/locales/ko.toml index b6a4240d..ef0712e2 100644 --- a/locales/ko.toml +++ b/locales/ko.toml @@ -421,6 +421,7 @@ overview = "개요" clients = "연동 앱" logout = "로그아웃" developer_request = "개발자 권한 신청" +developer_grants = "개발자 권한 부여" [ui.dev.welcome] btn_request = "신규 신청하기" @@ -438,6 +439,7 @@ desc = "개발자 권한을 신청하려면 아래 정보를 확인한 뒤 신 email = "이메일" name = "성함" org = "소속" +pages = "권한 페이지" phone = "전화번호" reason = "신청 사유" reason_placeholder = "개발자 권한이 필요한 이유를 작성해주세요." @@ -455,9 +457,54 @@ actions = "관리" date = "신청일" org = "소속" reason = "신청 사유" +pages = "권한 페이지" status = "상태" user = "사용자" +[ui.dev.grants] +actions = "관리" +admin_notes = "부여 사유" +approved = "승인됨" +date = "부여일" +email = "이메일" +form.title = "직접 부여" +grant = "직접 부여" +input_section = "입력" +list.title = "부여된 권한" +pages = "권한 페이지" +read_only = "읽기 전용" +reason = "부여 사유" +revoke = "회수" +revoke_notes_placeholder = "회수 메모 (선택)..." +selected_info = "선택된 사용자 정보" +status = "상태" +phone = "전화번호" +tenant = "소속" +user = "사용자" +user_search_placeholder = "이름 또는 이메일 검색..." +user_section = "사용자 선택" + +[ui.dev.grants] +actions = "관리" +admin_notes = "부여 사유" +approved = "승인됨" +date = "부여일" +form.title = "직접 부여" +grant = "직접 부여" +input_section = "입력" +list.title = "부여된 권한" +pages = "권한 페이지" +read_only = "읽기 전용" +reason = "부여 사유" +revoke = "회수" +revoke_notes_placeholder = "회수 메모 (선택)..." +selected_info = "선택된 사용자 정보" +status = "상태" +tenant = "소속" +user = "사용자" +user_search_placeholder = "이름 또는 이메일 검색..." +user_section = "사용자 선택" + [ui.dev.tenant] single_notice = "단일 테넌트에 소속되어 전환할 필요가 없습니다." switch_success = "테넌트 전환 완료" @@ -918,8 +965,37 @@ phone = "전화번호" reason = "신청 사유" reason_placeholder = "개발자 권한이 필요한 이유를 작성해주세요." role = "역할" +pages_hint = "전체를 선택하면 개요, 연동 앱 추가, 감사로그가 모두 포함됩니다." title = "개발자 등록 신청" +[msg.dev.grants] +admin_notes_description = "직접 부여의 근거를 간단히 남겨 두면 추후 회수와 검토에 도움이 됩니다." +admin_notes_hint = "회수는 목록의 회수 버튼으로 처리합니다." +admin_notes_placeholder = "예: 테스트 환경 확인 후 권한 부여" +approved = "승인됨" +count = "총 {{count}}건" +create_success = "개발자 권한을 직접 부여했습니다." +description = "사용자에게 개발자 권한을 직접 부여하고, 부여된 권한을 회수합니다." +empty = "부여된 권한이 없습니다." +forbidden = "개발자 권한 직접 부여는 super admin만 사용할 수 있습니다." +forbidden_desc = "이 화면은 super admin만 사용할 수 있습니다." +form.description = "사용자를 선택하면 현재 소속 테넌트, 이메일, 전화번호를 확인한 뒤 개발자 권한을 즉시 부여합니다." +list.description = "현재 부여된 개발자 권한 목록입니다." +load_error = "개발자 권한 목록을 불러오지 못했습니다." +pages_hint = "전체를 선택하면 개요, 연동 앱 추가, 감사로그가 모두 포함됩니다." +phone_missing = "등록된 전화번호가 없습니다." +reason = "부여 사유" +revoke = "회수" +revoke_success = "개발자 권한을 회수했습니다." +search_empty = "검색 결과가 없습니다." +search_loading = "사용자를 찾는 중입니다..." +selected_info_description = "선택된 사용자의 소속, 이메일, 전화번호를 확인합니다." +selected_user = "선택된 사용자: {{user}}" +tenant_missing = "선택한 사용자의 테넌트 정보를 확인할 수 없습니다." +tenant_required = "선택한 사용자의 테넌트 정보를 확인할 수 없습니다." +user_required = "부여할 사용자를 선택해주세요." +user_section_description = "검색어를 입력해 사용자를 선택합니다. 선택 전에는 다음 단계 정보가 비어 있습니다." + [msg.dev.request.status] approved = "승인됨" cancelled = "승인 취소됨" diff --git a/locales/template.toml b/locales/template.toml index 95971af7..2a3ea4c3 100644 --- a/locales/template.toml +++ b/locales/template.toml @@ -278,6 +278,7 @@ success = "" clients = "" logout = "" developer_request = "" +developer_grants = "" [ui.dev.welcome] btn_request = "" @@ -299,6 +300,7 @@ phone = "" reason = "" reason_placeholder = "" role = "" +pages = "" title = "" [ui.dev.request.status] @@ -312,9 +314,33 @@ actions = "" date = "" org = "" reason = "" +pages = "" status = "" user = "" +[ui.dev.grants] +actions = "" +admin_notes = "" +approved = "" +date = "" +email = "" +form.title = "" +grant = "" +input_section = "" +list.title = "" +pages = "" +read_only = "" +reason = "" +revoke = "" +revoke_notes_placeholder = "" +selected_info = "" +status = "" +phone = "" +tenant = "" +user = "" +user_search_placeholder = "" +user_section = "" + [ui.dev.tenant] single_notice = "" switch_success = "" @@ -748,6 +774,34 @@ unknown_error = "" [msg.dev] logout_confirm = "" +[msg.dev.grants] +admin_notes_description = "" +admin_notes_hint = "" +admin_notes_placeholder = "" +approved = "" +count = "" +create_success = "" +description = "" +empty = "" +forbidden = "" +forbidden_desc = "" +form.description = "" +list.description = "" +load_error = "" +pages_hint = "" +phone_missing = "" +reason = "" +revoke = "" +revoke_success = "" +search_empty = "" +search_loading = "" +selected_info_description = "" +selected_user = "" +tenant_missing = "" +tenant_required = "" +user_required = "" +user_section_description = "" + [msg.dev.audit] access_denied = "" access_denied_detail = "" @@ -778,6 +832,7 @@ phone = "" reason = "" reason_placeholder = "" role = "" +pages_hint = "" title = "" [msg.dev.request.status]