From 64cdef81a6a1c60807e2dc245c13e1d9eb05ab21 Mon Sep 17 00:00:00 2001 From: kyy Date: Wed, 6 May 2026 16:31:40 +0900 Subject: [PATCH] =?UTF-8?q?i18n=20=EB=88=84=EB=9D=BD=20=EC=A0=95=EB=A6=AC?= =?UTF-8?q?=20=EB=B0=8F=20=ED=95=98=EB=93=9C=EC=BD=94=EB=94=A9=20=ED=85=8D?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B9=98=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/common/ForbiddenMessage.tsx | 16 ++--- devfront/src/components/layout/AppLayout.tsx | 36 +++++----- .../lib/core/constants/error_whitelist.dart | 23 +++--- .../lib/core/services/auth_proxy_service.dart | 46 ++++++------ .../auth/presentation/error_screen.dart | 43 ++++++----- userfront/lib/i18n_data.dart | 71 +++++++++++++++++++ 6 files changed, 154 insertions(+), 81 deletions(-) diff --git a/devfront/src/components/common/ForbiddenMessage.tsx b/devfront/src/components/common/ForbiddenMessage.tsx index 97c2af01..43dee424 100644 --- a/devfront/src/components/common/ForbiddenMessage.tsx +++ b/devfront/src/components/common/ForbiddenMessage.tsx @@ -14,34 +14,34 @@ export function ForbiddenMessage({ resourceToken }: Props) { let explanation = t( "msg.dev.forbidden.default", - "해당 리소스에 접근할 권한이 없습니다. 관리자에게 문의하세요.", + "You do not have permission to access this resource. Contact your administrator.", ); if (role === "rp_admin") { explanation = t( "msg.dev.forbidden.rp_admin", - "RP 관리자는 담당 앱의 리소스만 조회할 수 있습니다.", + "RP administrators can only access resources for their assigned applications.", ); } else if (role === "tenant_admin") { explanation = t( "msg.dev.forbidden.tenant_admin", - "테넌트 관리자 권한이 올바르게 설정되지 않았거나 만료되었습니다.", + "Your tenant administrator permission is missing, misconfigured, or expired.", ); } else if (role === "user" || role === "tenant_member") { if (resourceToken === "consents") { explanation = t( "msg.dev.forbidden.user.consents", - "해당 앱(RP)에 대한 동의 내역 조회는 'RP 관리자', '동의 조회', '동의 회수' 관계가 부여된 경우에만 사용할 수 있습니다. 권한이 필요하면 관리자에게 요청하세요.", + "Viewing consent records for this application requires an RP administrator, consent read, or consent revoke relationship. Request access from an administrator if needed.", ); } else if (resourceToken === "audit") { explanation = t( "msg.dev.forbidden.user.audit", - "해당 앱(RP)에 대한 감사 로그 조회는 'RP 관리자', '감사 조회' 관계가 부여된 경우에만 사용할 수 있습니다. 권한이 필요하면 관리자에게 요청하세요.", + "Viewing audit logs for this application requires an RP administrator or audit read relationship. Request access from an administrator if needed.", ); } else { explanation = t( "msg.dev.forbidden.user.clients", - "일반 사용자 계정은 담당 RP(앱)에 대한 운영 또는 관리 관계가 부여된 경우에만 해당 기능을 사용할 수 있습니다. 권한이 필요하면 관리자에게 요청하세요.", + "Standard user accounts can use this feature only when an operational or administrative relationship is granted for the target RP. Request access from an administrator if needed.", ); } } @@ -51,9 +51,9 @@ export function ForbiddenMessage({ resourceToken }: Props) { ? t("ui.dev.audit.title", "Audit Logs") : resourceToken === "consents" ? t("ui.dev.clients.consents.title", "User Consent Grants") - : t("ui.dev.clients.registry.subtitle", "연동 앱"); + : t("ui.dev.clients.registry.subtitle", "Connected Applications"); - const title = t("msg.dev.forbidden.title", "{{resource}} 접근 권한 없음", { + const title = t("msg.dev.forbidden.title", "Access denied: {{resource}}", { resource: resourceLabel, }); diff --git a/devfront/src/components/layout/AppLayout.tsx b/devfront/src/components/layout/AppLayout.tsx index be1da833..0f5e1c71 100644 --- a/devfront/src/components/layout/AppLayout.tsx +++ b/devfront/src/components/layout/AppLayout.tsx @@ -32,7 +32,7 @@ const navItems = [ }, { labelKey: "ui.dev.nav.developer_request", - labelFallback: "개발자 권한 신청", + labelFallback: "Developer Access Request", to: "/developer-requests", icon: ClipboardCheck, }, @@ -71,7 +71,11 @@ function AppLayout() { }); const handleLogout = () => { - if (window.confirm(t("msg.dev.logout_confirm", "로그아웃 하시겠습니까?"))) { + if ( + window.confirm( + t("msg.dev.logout_confirm", "Are you sure you want to log out?"), + ) + ) { auth.removeUser(); navigate("/login"); } @@ -136,7 +140,7 @@ function AppLayout() { try { await auth.signinSilent(); } catch (error) { - console.error("세션 자동 연장에 실패했습니다.", error); + console.error("Silent session renewal failed.", error); } finally { isRenewInFlightRef.current = false; } @@ -184,7 +188,7 @@ function AppLayout() { try { await auth.signinSilent(); } catch (error) { - console.error("세션 무제한 유지 갱신에 실패했습니다.", error); + console.error("Unlimited session keepalive renewal failed.", error); } finally { isRenewInFlightRef.current = false; } @@ -241,7 +245,7 @@ function AppLayout() { void auth .signinSilent() .catch((error) => { - console.error("세션 자동 연장에 실패했습니다.", error); + console.error("Silent session renewal failed.", error); }) .finally(() => { isRenewInFlightRef.current = false; @@ -289,15 +293,15 @@ function AppLayout() { let sessionToneClass = "border-emerald-500/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300"; - let sessionText = t("ui.dev.session.active", "세션 활성"); + let sessionText = t("ui.dev.session.active", "Session active"); if (remainingMs === null) { sessionToneClass = "border-border bg-card text-muted-foreground"; - sessionText = t("ui.dev.session.unknown", "알 수 없음"); + sessionText = t("ui.dev.session.unknown", "Unknown"); } else if (remainingMs <= 0) { sessionToneClass = "border-rose-500/30 bg-rose-500/10 text-rose-700 dark:text-rose-300"; - sessionText = t("ui.dev.session.expired", "세션 만료"); + sessionText = t("ui.dev.session.expired", "Session expired"); } else if ( remainingMinutes !== null && remainingSeconds !== null && @@ -307,7 +311,7 @@ function AppLayout() { "border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300"; sessionText = t( "ui.dev.session.expiring", - "만료 임박: {{minutes}}분 {{seconds}}초 남음", + "Expiring soon: {{minutes}}m {{seconds}}s left", { minutes: remainingMinutes, seconds: remainingSeconds, @@ -316,7 +320,7 @@ function AppLayout() { } else { sessionText = t( "ui.dev.session.remaining", - "만료 예정: {{minutes}}분 {{seconds}}초 남음", + "Expires in {{minutes}}m {{seconds}}s", { minutes: remainingMinutes ?? 0, seconds: remainingSeconds ?? 0, @@ -343,7 +347,7 @@ function AppLayout() {

- {t("ui.dev.brand", "Baron 로그인")} + {t("ui.dev.brand", "Baron Sign In")}

{t("ui.dev.console_title", "Developer Console")} @@ -423,7 +427,7 @@ function AppLayout() { type="button" onClick={toggleTheme} className="inline-flex items-center gap-2 rounded-full border border-border px-3 py-2 text-muted-foreground transition hover:bg-muted/20" - aria-label={t("ui.common.theme_toggle", "테마 전환")} + aria-label={t("ui.common.theme_toggle", "Toggle theme")} > {theme === "light" ? : } {theme === "light" @@ -447,7 +451,7 @@ function AppLayout() { className="inline-flex items-center gap-3 rounded-full border border-border bg-card px-3 py-2 transition hover:bg-muted/20" aria-haspopup="menu" aria-expanded={isProfileMenuOpen} - aria-label={t("ui.dev.profile.menu_aria", "계정 메뉴 열기")} + aria-label={t("ui.dev.profile.menu_aria", "Open account menu")} >
{profileInitial} @@ -496,14 +500,14 @@ function AppLayout() {

- {t("ui.dev.session.auto_extend", "세션 만료 관리")} + {t("ui.dev.session.auto_extend", "Session expiry")}

{isSessionExpiryEnabled ? sessionText : t( "ui.dev.session.disabled", - "세션 만료 비활성화", + "Session expiry disabled", )}

@@ -539,7 +543,7 @@ function AppLayout() { }} > - {t("ui.dev.profile.title", "내 정보")} + {t("ui.dev.profile.title", "My Profile")}