diff --git a/backend/internal/handler/user_handler_test.go b/backend/internal/handler/user_handler_test.go index 2319df0d..f1033674 100644 --- a/backend/internal/handler/user_handler_test.go +++ b/backend/internal/handler/user_handler_test.go @@ -120,16 +120,16 @@ func TestUserHandler_BulkCreateUsers(t *testing.T) { payload := map[string]interface{}{ "users": []map[string]interface{}{ { - "email": "user1@test.com", - "name": "User One", - "tenantSlug": "test-tenant", - "metadata": map[string]interface{}{"emp_id": "E001"}, + "email": "user1@test.com", + "name": "User One", + "tenantSlug": "test-tenant", + "metadata": map[string]interface{}{"emp_id": "E001"}, }, { - "email": "user2@test.com", - "name": "User Two", - "tenantSlug": "test-tenant", - "metadata": map[string]interface{}{"emp_id": "E002"}, + "email": "user2@test.com", + "name": "User Two", + "tenantSlug": "test-tenant", + "metadata": map[string]interface{}{"emp_id": "E002"}, }, }, } diff --git a/devfront/tests/clients.spec.ts b/devfront/tests/clients.spec.ts index c1b2dc43..b304583e 100644 --- a/devfront/tests/clients.spec.ts +++ b/devfront/tests/clients.spec.ts @@ -1,38 +1,23 @@ import { expect, test } from "@playwright/test"; -import { seedAuth } from "./helpers/devfront-fixtures"; +import { + type Consent, + installDevApiMock, + makeClient, + seedAuth, +} from "./helpers/devfront-fixtures"; test("clients page loads correctly", async ({ page }) => { await seedAuth(page); - - await page.route("**/api/v1/dev/clients**", async (route) => { - if (route.request().method() !== "GET") { - await route.fulfill({ - status: 404, - contentType: "application/json", - body: JSON.stringify({ error: "Not found" }), - }); - return; - } - - await route.fulfill({ - status: 200, - contentType: "application/json", - body: JSON.stringify({ - items: [ - { - id: "client-playwright", - name: "Playwright Client", - type: "private", - status: "active", - createdAt: new Date().toISOString(), - redirectUris: ["http://localhost:5174/callback"], - scopes: ["openid", "profile", "email"], - }, - ], - limit: 50, - offset: 0, + await installDevApiMock(page, { + clients: [ + makeClient("client-playwright", { + name: "Playwright Client", + createdAt: new Date().toISOString(), + redirectUris: ["http://localhost:5174/callback"], }), - }); + ], + consents: [] as Consent[], + auditLogsByCursor: undefined, }); await page.goto("/clients"); @@ -46,9 +31,9 @@ test("clients page loads correctly", async ({ page }) => { // 테이블 헤더 확인 await expect( - page.getByRole("columnheader", { name: "애플리케이션" }), + page.locator("th").filter({ hasText: "애플리케이션" }), ).toBeVisible(); await expect( - page.getByRole("columnheader", { name: "Client ID" }), + page.locator("th").filter({ hasText: /클라이언트 ID|Client ID/i }), ).toBeVisible(); }); diff --git a/devfront/tests/devfront-audit.spec.ts b/devfront/tests/devfront-audit.spec.ts index efc31c75..8a0890d2 100644 --- a/devfront/tests/devfront-audit.spec.ts +++ b/devfront/tests/devfront-audit.spec.ts @@ -7,6 +7,8 @@ import { seedAuth, } from "./helpers/devfront-fixtures"; +const appNamePlaceholder = /My Awesome Application|예: 멋진 애플리케이션/i; + test.describe("DevFront audit logs", () => { test.beforeEach(async ({ page }) => { page.on("dialog", async (dialog) => { @@ -87,19 +89,18 @@ test.describe("DevFront audit logs", () => { await installDevApiMock(page, state); await page.goto("/clients/new"); - await page - .getByPlaceholder("My Awesome Application") - .fill("Realtime New App"); + await page.getByPlaceholder(appNamePlaceholder).fill("Realtime New App"); await page .getByPlaceholder(/https:\/\/app\.example\.com\/callback/i) .fill("https://realtime.example.com/callback"); await page.getByRole("button", { name: /앱 생성|Create/i }).click(); await expect.poll(() => state.auditLogs.length).toBeGreaterThanOrEqual(1); + await expect.poll(() => state.clients.at(-1)?.id).toMatch(/^client-/); + const createdClientId = state.clients.at(-1)?.id; + expect(createdClientId).toBeTruthy(); - await page.goto("/clients/client-realtime/settings"); - await page - .getByPlaceholder("My Awesome Application") - .fill("Realtime Updated"); + await page.goto(`/clients/${createdClientId}/settings`); + await page.getByPlaceholder(appNamePlaceholder).fill("Realtime Updated"); await page.getByRole("button", { name: /^저장$|^Save$/i }).click(); await expect.poll(() => state.auditLogs.length).toBeGreaterThanOrEqual(2); diff --git a/devfront/tests/devfront-clients-lifecycle.spec.ts b/devfront/tests/devfront-clients-lifecycle.spec.ts index 7a662395..b88c4e29 100644 --- a/devfront/tests/devfront-clients-lifecycle.spec.ts +++ b/devfront/tests/devfront-clients-lifecycle.spec.ts @@ -7,6 +7,8 @@ import { seedAuth, } from "./helpers/devfront-fixtures"; +const appNamePlaceholder = /My Awesome Application|예: 멋진 애플리케이션/i; + test.describe("DevFront clients lifecycle", () => { test.beforeEach(async ({ page }) => { page.on("dialog", async (dialog) => { @@ -36,7 +38,7 @@ test.describe("DevFront clients lifecycle", () => { await expect(page).toHaveURL(/\/clients\/new$/); await page - .getByPlaceholder("My Awesome Application") + .getByPlaceholder(appNamePlaceholder) .fill("Playwright Created App"); await page .getByPlaceholder(/https:\/\/app\.example\.com\/callback/i) @@ -45,7 +47,7 @@ test.describe("DevFront clients lifecycle", () => { .getByRole("button", { name: /앱 생성|클라이언트 생성|Create/i }) .click(); - await expect(page).toHaveURL(/\/clients\/client-2\/settings$/); + await expect(page).toHaveURL(/\/clients\/client-\d+\/settings$/); await expect( page.getByRole("heading", { name: /연동 앱 설정|클라이언트 설정|Client Settings/i, @@ -97,7 +99,7 @@ test.describe("DevFront clients lifecycle", () => { await installDevApiMock(page, state); await page.goto("/clients/client-edit/settings"); - await page.getByPlaceholder("My Awesome Application").fill("After Name"); + await page.getByPlaceholder(appNamePlaceholder).fill("After Name"); await page.getByRole("button", { name: /^저장$|^Save$/i }).click(); await expect.poll(() => state.clients[0]?.name).toBe("After Name"); diff --git a/devfront/tests/devfront-consents.spec.ts b/devfront/tests/devfront-consents.spec.ts index 593cab76..27518c3a 100644 --- a/devfront/tests/devfront-consents.spec.ts +++ b/devfront/tests/devfront-consents.spec.ts @@ -39,7 +39,7 @@ test.describe("DevFront consents", () => { await expect(page.getByText("Alice")).toBeVisible(); await expect(page.getByText("Tenant A")).toBeVisible(); - await page.getByRole("button", { name: /권한 철회|Revoke/i }).click(); + await page.getByRole("button", { name: /권한 철회|철회|Revoke/i }).click(); await expect(page.getByText(/Revoked|철회/i).first()).toBeVisible(); }); }); diff --git a/devfront/tests/devfront-role-switch-report.spec.ts b/devfront/tests/devfront-role-switch-report.spec.ts index 6faedf92..e6b2af07 100644 --- a/devfront/tests/devfront-role-switch-report.spec.ts +++ b/devfront/tests/devfront-role-switch-report.spec.ts @@ -8,6 +8,8 @@ import { } from "./helpers/devfront-fixtures"; import { captureEvidence } from "./helpers/evidence"; +const appNamePlaceholder = /My Awesome Application|예: 멋진 애플리케이션/i; + test.describe("DevFront role report", () => { test.beforeEach(async ({ page }) => { page.on("dialog", async (dialog) => { @@ -91,7 +93,7 @@ test.describe("DevFront role report", () => { await page.goto("/clients/tenant-a-app-1/settings"); await page - .getByPlaceholder("My Awesome Application") + .getByPlaceholder(appNamePlaceholder) .fill("Tenant A CRM Updated"); const updatePromise = page.waitForResponse( @@ -132,7 +134,7 @@ test.describe("DevFront role report", () => { await page.goto("/clients/new"); await page - .getByPlaceholder("My Awesome Application") + .getByPlaceholder(appNamePlaceholder) .fill("Super Admin Created App"); await page .getByPlaceholder(/https:\/\/app\.example\.com\/callback/i) @@ -145,6 +147,17 @@ test.describe("DevFront role report", () => { ); await page.getByRole("button", { name: /앱 생성|Create/i }).click(); await createPromise; + await expect + .poll(() => + state.auditLogs.some((item) => { + try { + return JSON.parse(item.details)?.action === "CREATE_CLIENT"; + } catch { + return false; + } + }), + ) + .toBe(true); await page.goto("/audit-logs"); await expect(page.getByText("CREATE_CLIENT")).toBeVisible({ diff --git a/devfront/tests/devfront-security.spec.ts b/devfront/tests/devfront-security.spec.ts index 7c75e36f..36e526aa 100644 --- a/devfront/tests/devfront-security.spec.ts +++ b/devfront/tests/devfront-security.spec.ts @@ -25,7 +25,11 @@ test.describe("DevFront security and isolation", () => { await installDevApiMock(page, state); await page.goto("/clients/tenant-b-client"); - await expect(page.getByText(/Error loading client|조회/i)).toBeVisible(); + await expect( + page.getByText( + /Error loading (app|client)|앱 정보를 불러오지 못했습니다|클라이언트 정보를 불러오지 못했습니다/i, + ), + ).toBeVisible(); }); test("RBAC: non-AppManager user should not see private apps", async ({ diff --git a/userfront/assets/translations/en.toml b/userfront/assets/translations/en.toml index 538eeb5b..79d64f17 100644 --- a/userfront/assets/translations/en.toml +++ b/userfront/assets/translations/en.toml @@ -21,24 +21,24 @@ user_group = "User Group" [err.userfront] [err.userfront.auth_proxy] -consent_accept = "Consent Accept" -consent_fetch = "Consent Fetch" -consent_reject = "Consent Reject" -linked_app_revoke = "Linked App Revoke" -login_failed = "Login Failed" +consent_accept = "Failed to accept the consent request." +consent_fetch = "Failed to load consent details." +consent_reject = "Failed to reject the consent request." +linked_app_revoke = "Failed to revoke the linked application." +login_failed = "Login failed." oidc_accept = "OIDC Accept" -password_reset_complete = "Password Reset Complete" -password_reset_init = "Password Reset Init" +password_reset_complete = "Failed to complete the password reset." +password_reset_init = "Failed to start the password reset." [err.userfront.profile] -load_failed = "Load Failed" +load_failed = "Failed to load the profile." password_change_failed = "Password Change Failed" -send_code_failed = "Send Code Failed" -update_failed = "Update Failed" -verify_code_failed = "Verify Code Failed" +send_code_failed = "Failed to send the verification code." +update_failed = "Failed to update the profile." +verify_code_failed = "Verification failed." [err.userfront.session] -missing = "Missing" +missing = "No active session was found." [msg.userfront] greeting = "Hello, {name}." @@ -631,3 +631,4 @@ verify = "Verification" [ui.userfront.signup.success] action = "Go to sign-in" + diff --git a/userfront/assets/translations/ko.toml b/userfront/assets/translations/ko.toml index 18d2b303..e87f37ea 100644 --- a/userfront/assets/translations/ko.toml +++ b/userfront/assets/translations/ko.toml @@ -1,5 +1,3 @@ -[domain] - [domain.affiliation] affiliate = "가족사 임직원" general = "일반 사용자" @@ -18,325 +16,9 @@ company_group = "COMPANY_GROUP (그룹사/지주사)" personal = "PERSONAL (개인 워크스페이스)" user_group = "USER_GROUP (내부 부서/팀)" -[err.userfront] - -[err.userfront.auth_proxy] -consent_accept = "동의 처리에 실패했습니다." -consent_fetch = "동의 정보를 가져오지 못했습니다." -consent_reject = "동의 거부에 실패했습니다." -linked_app_revoke = "연동 해지에 실패했습니다." -login_failed = "로그인에 실패했습니다." -oidc_accept = "OIDC 로그인 승인에 실패했습니다." -password_reset_complete = "비밀번호 재설정에 실패했습니다." -password_reset_init = "비밀번호 재설정을 시작하지 못했습니다." - -[err.userfront.profile] -load_failed = "프로필을 불러오지 못했습니다: {error}" -password_change_failed = "비밀번호 변경에 실패했습니다: {error}" -send_code_failed = "인증번호 전송 실패: {error}" -update_failed = "프로필 업데이트에 실패했습니다: {error}" -verify_code_failed = "인증 실패: {error}" - -[err.userfront.session] -missing = "활성 세션이 없습니다." - [msg.userfront] greeting = "안녕하세요, {name}님" -[msg.userfront.audit] -date = "접속일자: {value}" -device = "접속환경: {value}" -end = "더 이상 항목이 없습니다." -ip = "접속 IP: {value}" -load_more_error = "더 불러오지 못했습니다." -result = "인증결과: {value}" -session_id = "Session ID: {value}" -status = "현황: (준비중)" - -[msg.userfront.dashboard] -approved_device = "승인 기기: {device}" -approved_ip = "승인 IP: {ip}" -audit_empty = "최근 접속 이력이 없습니다." -audit_load_error = "접속이력을 불러오지 못했습니다." -auth_method = "인증수단: {method}" -client_id = "Client ID: {id}" -client_id_missing = "Client ID 없음" -current_status = "현재 상태: {status}" -last_auth = "최근 인증: {value}" -link_missing = "이동할 페이지 주소(Client URI)가 설정되지 않았습니다." -link_open_error = "해당 링크를 열 수 없습니다." -render_error = "대시보드 렌더링 오류: {error}" -session_id_copied = "세션 ID가 복사되었습니다." - -[msg.userfront.dashboard.activities] -empty = "연동된 앱이 없습니다." -empty_detail = "앱을 연동하면 최근 활동과 상태가 표시됩니다." -error = "연동 정보를 불러오지 못했습니다." - -[msg.userfront.dashboard.approved_session] -copy_click = "{label}: {id}\n클릭하면 복사됩니다." -copy_tap = "{label}: {id}\n탭하면 복사됩니다." -none = "{label} 없음" - -[msg.userfront.dashboard.revoke] -confirm = "{app} 앱과의 연동을 해지하시겠습니까?\n해지하면 다음 로그인 시 다시 동의가 필요합니다." -error = "해지 실패: {error}" -success = "{app} 연동이 해지되었습니다." - -[msg.userfront.dashboard.scopes] -empty = "요청된 권한이 없습니다." - -[msg.userfront.dashboard.timeline] -load_error = "접속이력을 불러오지 못했습니다." - -[msg.userfront.error] -detail_contact = "관리자에게 문의해 주세요." -detail_generic = "오류가 발생했습니다." -detail_request = "요청을 처리하는 중 문제가 발생했습니다." -id = "오류 ID: {id}" -title = "인증 과정에서 오류가 발생했습니다" -title_generic = "오류가 발생했습니다" -title_with_code = "오류: {code}" -type = "오류 종류: {type}" - -[msg.userfront.error.whitelist] -"$normalizedCode" = "{error}" -bad_request = "입력값을 확인해 주세요." -invalid_session = "세션이 만료되었습니다. 다시 로그인해 주세요." -not_found = "요청한 페이지를 찾을 수 없습니다." -password_or_email_mismatch = "이메일 혹은 비밀번호가 일치하지 않습니다." -rate_limited = "요청이 많습니다. 잠시 후 다시 시도해 주세요." -recovery_expired = "재설정 링크가 만료되었습니다. 다시 요청해 주세요." -recovery_invalid = "재설정 링크가 유효하지 않습니다." -settings_disabled = "현재 계정 설정 화면은 준비 중입니다." -verification_required = "추가 인증이 필요합니다. 안내에 따라 진행해 주세요." - -[msg.userfront.error.ory] -"$normalizedCode" = "{error}" -access_denied = "사용자가 동의를 거부했습니다." -consent_required = "앱 접근 동의가 필요합니다." -interaction_required = "추가 상호작용이 필요합니다. 다시 시도해 주세요." -invalid_client = "클라이언트 인증 정보가 유효하지 않습니다." -invalid_grant = "인증 요청이 만료되었거나 유효하지 않습니다." -invalid_request = "잘못된 요청입니다." -invalid_scope = "요청한 권한 범위가 유효하지 않습니다." -login_required = "로그인이 필요합니다." -request_forbidden = "요청이 거부되었습니다." -server_error = "인증 서버 오류가 발생했습니다." -temporarily_unavailable = "인증 서버를 일시적으로 사용할 수 없습니다." -unauthorized_client = "해당 클라이언트는 이 요청을 수행할 수 없습니다." -unsupported_response_type = "지원하지 않는 응답 타입입니다." - -[msg.userfront.forgot] -description = "계정과 연결된 이메일 주소 또는 휴대폰 번호를 입력하시면, 비밀번호를 재설정할 수 있는 링크를 보내드립니다." -dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다." -error = "전송에 실패했습니다: {error}" -input_required = "이메일 또는 휴대폰 번호를 입력해주세요." -sent = "비밀번호 재설정 링크가 전송되었습니다. 이메일 또는 SMS를 확인해주세요." - -[msg.userfront.login] -cookie_check_failed = "로그인 확인 실패: {error}" -dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다." -link_failed = "오류: {error}" -link_send_failed = "전송 실패: {error}" -link_sent_email = "입력하신 이메일로 로그인 링크를 보냈습니다." -link_sent_phone = "입력하신 번호로 로그인 링크를 보냈습니다." -link_timeout = "시간이 경과되었습니다." -no_account = "계정이 없으신가요?" -oidc_failed = "OIDC 로그인 처리에 실패했습니다. 다시 시도해 주세요." -qr_expired = "시간이 경과되었습니다." -qr_init_failed = "QR 초기화에 실패했습니다: {error}" -qr_login_required = "로그인 한 상태여야 QR 스캔으로 로그인 할 수 있습니다" -token_missing = "로그인 토큰을 확인할 수 없습니다." -verification_failed = "승인 처리에 실패했습니다: {error}" - -[msg.userfront.login.link] -helper = "입력하신 정보로 로그인 링크를 전송합니다." -missing_login_id = "이메일 또는 휴대폰 번호를 입력해 주세요." -missing_phone = "휴대폰 번호를 입력해 주세요." -resend_wait = "재발송은 {time} 후 가능합니다." -short_code_help = "링크로 받은 값의 뒤 문자 2개와 숫자 6자리를 입력하셔도 로그인 할 수 있습니다." - -[msg.userfront.login.password] -failed = "로그인 실패: {error}" -missing_credentials = "이메일(또는 전화번호)와 비밀번호를 모두 입력해주세요." - -[msg.userfront.login.qr] -load_failed = "QR 코드를 불러오지 못했습니다." -scan_hint = "모바일 앱으로 스캔하세요" - -[msg.userfront.login.short_code] -invalid = "문자 2개와 숫자 6자리를 입력해 주세요." - -[msg.userfront.login.unregistered] -body = "가입되지 않은 정보입니다.\n회원가입 후 이용해 주세요." - -[msg.userfront.login.verification] -approved = "승인되었습니다. 로그인은 요청하신 창에서 완료됩니다." -approved_local = "승인 되었습니다. 이 기기는 로그인되어 있는 상태입니다. 원격 창도 로그인이 될 예정입니다" -success = "로그인 승인에 성공했습니다." - -[msg.userfront.login_success] -subtitle = "성공적으로 로그인되었습니다." - -[msg.userfront.consent] -accept_error = "동의 처리에 실패했습니다: {error}" -client_id = "클라이언트 ID: {id}" -client_unknown = "알 수 없는 앱" -description = "아래 서비스가 회원님의 계정 정보에 접근하려고 합니다.\n계속 진행하려면 동의 여부를 선택해 주세요." -load_error = "동의 정보를 불러오는데 실패했습니다: {error}" -missing_redirect = "동의가 처리되었으나 리다이렉트 URL을 받지 못했습니다." -redirect_notice = "동의 후 자동으로 서비스로 이동합니다." -scope_count = "총 {count}개" - -[msg.userfront.consent.cancel] -confirm = "권한 동의를 취소하면 해당 서비스를 이용할 수 없습니다. 취소하시겠습니까?" -error = "취소 처리 중 오류가 발생했습니다: {error}" - -[msg.userfront.consent.scope] -email = "이메일 주소 (계정 식별 및 알림 용도)" -offline_access = "오프라인 접근 (로그인 유지)" -openid = "OpenID 인증 정보 (로그인 상태 확인)" -phone = "휴대폰 번호 (본인 인증 및 알림)" -profile = "기본 프로필 정보 (이름, 사용자 식별자)" - -[msg.userfront.profile] -department_missing = "소속 정보 없음" -department_required = "소속을 입력해주세요." -email_missing = "이메일 없음" -greeting = "안녕하세요, {name}님" -load_failed = "정보를 불러올 수 없습니다." -name_missing = "이름 없음" -name_required = "이름을 입력해주세요." -phone_required = "휴대폰 번호를 입력해주세요." -phone_verify_required = "휴대폰 번호 인증이 필요합니다." -update_failed = "수정 실패: {error}" -update_success = "정보가 수정되었습니다." - -[msg.userfront.profile.password] -change_failed = "비밀번호 변경 실패: {error}" -changed = "비밀번호가 변경되었습니다." -current_required = "현재 비밀번호를 입력해 주세요." -mismatch = "새 비밀번호가 일치하지 않습니다." -new_required = "새 비밀번호를 입력해 주세요." -subtitle = "현재 비밀번호 확인 후 새 비밀번호로 변경합니다." - -[msg.userfront.profile.phone] -code_sent = "인증번호가 전송되었습니다." -send_failed = "전송 실패: {error}" -verified = "인증되었습니다." -verify_failed = "인증 실패: {error}" -verify_notice = "휴대폰 번호를 변경하려면 SMS 인증이 필요합니다." - -[msg.userfront.profile.section] -basic = "계정 기본 정보를 관리합니다." -organization = "소속 및 구분 정보입니다." -security = "비밀번호를 안전하게 관리합니다." - -[msg.userfront.qr] -camera_error = "카메라 오류: {error}" -permission_error = "카메라 권한 요청에 실패했습니다. 브라우저/OS 설정을 확인해주세요." -permission_required = "카메라 권한이 필요합니다." - -[msg.userfront.reset] -invalid_body = "비밀번호 재설정 링크가 만료되었거나 잘못되었습니다. 다시 시도해주세요." -invalid_link = "유효하지 않은 재설정 링크입니다. (loginId/token 누락)" -invalid_title = "유효하지 않은 링크입니다." -policy_loading = "비밀번호 정책을 불러오는 중입니다..." -success = "비밀번호가 성공적으로 변경되었습니다. 다시 로그인해주세요." - -[msg.userfront.reset.error] -empty_password = "비밀번호를 입력해주세요." -generic = "비밀번호 변경에 실패했습니다: {error}" -lowercase = "최소 1개 이상의 소문자를 포함해야 합니다." -min_length = "비밀번호는 최소 {count}자 이상이어야 합니다." -min_types = "비밀번호는 영문 대/소문자/숫자/특수문자 중 {count}가지 이상 포함해야 합니다." -mismatch = "비밀번호가 일치하지 않습니다." -number = "최소 1개 이상의 숫자를 포함해야 합니다." -symbol = "최소 1개 이상의 특수문자를 포함해야 합니다." -uppercase = "최소 1개 이상의 대문자를 포함해야 합니다." - -[msg.userfront.reset.policy] -lowercase = "소문자 1개 이상" -min_length = "최소 {count}자 이상" -min_types = "영문 대/소문자/숫자/특수문자 중 {count}가지 이상" -number = "숫자 1개 이상" -symbol = "특수문자 1개 이상" -uppercase = "대문자 1개 이상" - -[msg.userfront.sections] -apps_subtitle = "현재 연결된 앱과 최근 인증 상태입니다." -audit_subtitle = "Baron 로그인 기준의 최근 접근 기록입니다." - -[msg.userfront.settings] -disabled = "현재 계정 설정 화면은 준비 중입니다." - -[msg.userfront.signup] -failed = "가입 실패: {error}" -privacy_full = "개인정보 수집 및 이용 동의 전문..." -tos_full = "서비스 이용약관 전문..." - -[msg.userfront.signup.agreement] -all_hint = "필수 약관 2개를 모두 확인하고 동의하면 다음 단계로 진행할 수 있습니다." -description = "계속 진행하려면 서비스 이용 조건과 개인정보 수집·이용 항목을 확인한 뒤 동의해주세요." -privacy_summary = "개인정보 수집 항목, 이용 목적, 보관 기준을 안내합니다." -progress = "필수 약관 {total}개 중 {count}개 동의 완료" -tos_summary = "서비스 이용 조건과 책임 범위를 확인할 수 있습니다." -title = "서비스 이용을 위해\n약관에 동의해주세요" - -[msg.userfront.signup.auth] -affiliate_notice = "가족사 회원의 경우 반드시 회사 공식 이메일을 입력해주세요." -title = "본인 확인을 위해\n인증을 진행해주세요" - -[msg.userfront.signup.email] -code_mismatch = "인증코드가 일치하지 않습니다." -duplicate = "이미 가입된 이메일입니다." -invalid = "유효한 이메일 형식이 아닙니다." -send_failed = "발송 실패: {error}" -verified = "✅ 이메일 인증 완료" -verify_failed = "인증 실패: {error}" - -[msg.userfront.signup.password] -length_required = "비밀번호는 최소 12자 이상이어야 합니다." -lowercase_required = "소문자가 최소 1개 이상 포함되어야 합니다." -mismatch = "비밀번호가 일치하지 않습니다." -number_required = "숫자가 최소 1개 이상 포함되어야 합니다." -symbol_required = "특수문자가 최소 1개 이상 포함되어야 합니다." -title = "마지막으로\n비밀번호를 설정해주세요" -uppercase_required = "대문자가 최소 1개 이상 포함되어야 합니다." - -[msg.userfront.signup.password.rule] -lowercase = "소문자" -min_length = "{count}자 이상" -min_types = "문자 유형 {count}가지 이상" -number = "숫자" -symbol = "특수문자" -uppercase = "대문자" - -[msg.userfront.signup.phone] -code_mismatch = "인증코드가 일치하지 않습니다." -send_failed = "발송 실패: {error}" -verified = "✅ 휴대폰 인증 완료" -verify_failed = "인증 실패: {error}" - -[msg.userfront.signup.policy] -loading = "비밀번호 정책을 불러오는 중입니다..." -lowercase = "소문자" -min_length = "최소 {count}자 이상" -min_types = "영문 대/소문자/숫자/특수문자 중 {count}가지 이상" -number = "숫자" -summary = "보안 정책: {rules}" -symbol = "특수문자" -uppercase = "대문자" - -[msg.userfront.signup.profile] -affiliate_hint = "가족사 이메일 사용 시 자동으로 선택됩니다." -title = "회원님의\n소속 정보를 알려주세요" - -[msg.userfront.signup.success] -body = "성공적으로 가입되었습니다." -title = "회원가입 완료" - [ui.common] add = "추가" all = "전체" @@ -391,6 +73,137 @@ theme_toggle = "테마 전환" unknown = "Unknown" generate = "생성" +[ui.userfront] +app_title = "Baron SW 포탈" + +[err.userfront.auth_proxy] +consent_accept = "동의 처리에 실패했습니다." +consent_fetch = "동의 정보를 가져오지 못했습니다." +consent_reject = "동의 거부에 실패했습니다." +linked_app_revoke = "연동 해지에 실패했습니다." +login_failed = "로그인에 실패했습니다." +oidc_accept = "OIDC 로그인 승인에 실패했습니다." +password_reset_complete = "비밀번호 재설정에 실패했습니다." +password_reset_init = "비밀번호 재설정을 시작하지 못했습니다." + +[err.userfront.profile] +load_failed = "프로필을 불러오지 못했습니다: {error}" +password_change_failed = "비밀번호 변경에 실패했습니다: {error}" +send_code_failed = "인증번호 전송 실패: {error}" +update_failed = "프로필 업데이트에 실패했습니다: {error}" +verify_code_failed = "인증 실패: {error}" + +[err.userfront.session] +missing = "활성 세션이 없습니다." + +[msg.userfront.audit] +date = "접속일자: {value}" +device = "접속환경: {value}" +end = "더 이상 항목이 없습니다." +ip = "접속 IP: {value}" +load_more_error = "더 불러오지 못했습니다." +result = "인증결과: {value}" +session_id = "Session ID: {value}" +status = "현황: (준비중)" + +[msg.userfront.dashboard] +approved_device = "승인 기기: {device}" +approved_ip = "승인 IP: {ip}" +audit_empty = "최근 접속 이력이 없습니다." +audit_load_error = "접속이력을 불러오지 못했습니다." +auth_method = "인증수단: {method}" +client_id = "Client ID: {id}" +client_id_missing = "Client ID 없음" +current_status = "현재 상태: {status}" +last_auth = "최근 인증: {value}" +link_missing = "이동할 페이지 주소(Client URI)가 설정되지 않았습니다." +link_open_error = "해당 링크를 열 수 없습니다." +render_error = "대시보드 렌더링 오류: {error}" +session_id_copied = "세션 ID가 복사되었습니다." + +[msg.userfront.error] +detail_contact = "관리자에게 문의해 주세요." +detail_generic = "오류가 발생했습니다." +detail_request = "요청을 처리하는 중 문제가 발생했습니다." +id = "오류 ID: {id}" +title = "인증 과정에서 오류가 발생했습니다" +title_generic = "오류가 발생했습니다" +title_with_code = "오류: {code}" +type = "오류 종류: {type}" + +[msg.userfront.forgot] +description = "계정과 연결된 이메일 주소 또는 휴대폰 번호를 입력하시면, 비밀번호를 재설정할 수 있는 링크를 보내드립니다." +dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다." +error = "전송에 실패했습니다: {error}" +input_required = "이메일 또는 휴대폰 번호를 입력해주세요." +sent = "비밀번호 재설정 링크가 전송되었습니다. 이메일 또는 SMS를 확인해주세요." + +[msg.userfront.login] +cookie_check_failed = "로그인 확인 실패: {error}" +dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다." +link_failed = "오류: {error}" +link_send_failed = "전송 실패: {error}" +link_sent_email = "입력하신 이메일로 로그인 링크를 보냈습니다." +link_sent_phone = "입력하신 번호로 로그인 링크를 보냈습니다." +link_timeout = "시간이 경과되었습니다." +no_account = "계정이 없으신가요?" +oidc_failed = "OIDC 로그인 처리에 실패했습니다. 다시 시도해 주세요." +qr_expired = "시간이 경과되었습니다." +qr_init_failed = "QR 초기화에 실패했습니다: {error}" +qr_login_required = "로그인 한 상태여야 QR 스캔으로 로그인 할 수 있습니다" +token_missing = "로그인 토큰을 확인할 수 없습니다." +verification_failed = "승인 처리에 실패했습니다: {error}" + +[msg.userfront.login_success] +subtitle = "성공적으로 로그인되었습니다." + +[msg.userfront.consent] +accept_error = "동의 처리에 실패했습니다: {error}" +client_id = "클라이언트 ID: {id}" +client_unknown = "알 수 없는 앱" +description = "아래 서비스가 회원님의 계정 정보에 접근하려고 합니다.\n계속 진행하려면 동의 여부를 선택해 주세요." +load_error = "동의 정보를 불러오는데 실패했습니다: {error}" +missing_redirect = "동의가 처리되었으나 리다이렉트 URL을 받지 못했습니다." +redirect_notice = "동의 후 자동으로 서비스로 이동합니다." +scope_count = "총 {count}개" + +[msg.userfront.profile] +department_missing = "소속 정보 없음" +department_required = "소속을 입력해주세요." +email_missing = "이메일 없음" +greeting = "안녕하세요, {name}님" +load_failed = "정보를 불러올 수 없습니다." +name_missing = "이름 없음" +name_required = "이름을 입력해주세요." +phone_required = "휴대폰 번호를 입력해주세요." +phone_verify_required = "휴대폰 번호 인증이 필요합니다." +update_failed = "수정 실패: {error}" +update_success = "정보가 수정되었습니다." + +[msg.userfront.qr] +camera_error = "카메라 오류: {error}" +permission_error = "카메라 권한 요청에 실패했습니다. 브라우저/OS 설정을 확인해주세요." +permission_required = "카메라 권한이 필요합니다." + +[msg.userfront.reset] +invalid_body = "비밀번호 재설정 링크가 만료되었거나 잘못되었습니다. 다시 시도해주세요." +invalid_link = "유효하지 않은 재설정 링크입니다. (loginId/token 누락)" +invalid_title = "유효하지 않은 링크입니다." +policy_loading = "비밀번호 정책을 불러오는 중입니다..." +success = "비밀번호가 성공적으로 변경되었습니다. 다시 로그인해주세요." + +[msg.userfront.sections] +apps_subtitle = "현재 연결된 앱과 최근 인증 상태입니다." +audit_subtitle = "Baron 로그인 기준의 최근 접근 기록입니다." + +[msg.userfront.settings] +disabled = "현재 계정 설정 화면은 준비 중입니다." + +[msg.userfront.signup] +failed = "가입 실패: {error}" +privacy_full = "개인정보 수집 및 이용 동의 전문..." +tos_full = "서비스 이용약관 전문..." + [ui.common.badge] admin_only = "Admin only" command_only = "Command only" @@ -405,27 +218,11 @@ ok = "정상" pending = "준비 중" success = "성공" -[ui.userfront] -app_title = "Baron SW 포탈" - [ui.userfront.app_label] admin_console = "Admin Console" baron = "Baron 로그인" dev_console = "Dev Console" -[ui.userfront.audit] - -[ui.userfront.audit.table] -app = "애플리케이션" -auth_method = "인증수단" -date = "접속일자" -device = "접속환경" -ip = "IP" -pending = "(준비중)" -result = "인증결과" -session_id = "Session ID" -status = "현황" - [ui.userfront.auth_method] ory = "Ory 세션" session = "세션" @@ -434,23 +231,6 @@ session = "세션" last_auth_label = "최근 인증" status_history = "상태 이력" -[ui.userfront.dashboard.activity] -linked = "연동됨" - -[ui.userfront.dashboard.approved_session] -default = "승인한 세션 ID" -userfront = "승인한 Userfront 세션 ID" - -[ui.userfront.dashboard.revoke] -confirm_button = "해지하기" -title = "연동 해지" - -[ui.userfront.dashboard.scopes] -title = "권한 (Scopes)" - -[ui.userfront.dashboard.status] -revoked = "해지됨" - [ui.userfront.device] android = "Mobile(Android)" ios = "Mobile(iOS)" @@ -472,6 +252,258 @@ title = "비밀번호 재설정" forgot_password = "비밀번호를 잊으셨나요?" signup = "회원가입" +[ui.userfront.login_success] +later = "나중에 하기 (대시보드로 이동)" +qr = "QR 인증 (카메라 켜기)" +title = "로그인 완료" + +[ui.userfront.consent] +accept = "동의하고 계속하기" +requested_scopes = "요청된 권한" +title = "접근 권한 요청" + +[ui.userfront.nav] +dashboard = "대시보드" +logout = "로그아웃" +profile = "내 정보" +qr_scan = "QR 스캔" + +[ui.userfront.profile] +department_empty = "소속 정보 없음" +manage = "프로필 관리" +user_fallback = "사용자" + +[ui.userfront.qr] +rescan = "다시 스캔" +result_success = "승인 완료" +title = "Scan QR Code" + +[ui.userfront.reset] +confirm_password = "새 비밀번호 확인" +new_password = "새 비밀번호" +submit = "비밀번호 변경" +subtitle = "새로운 비밀번호 설정" +title = "새 비밀번호 설정" + +[ui.userfront.sections] +apps = "나의 App 현황" +audit = "접속이력" + +[ui.userfront.session] +active = "세션 활성" +unknown = "알 수 없음" + +[ui.userfront.signup] +complete = "가입 완료" +next_step = "다음 단계" +title = "회원가입" + +[msg.userfront.dashboard.activities] +empty = "연동된 앱이 없습니다." +empty_detail = "앱을 연동하면 최근 활동과 상태가 표시됩니다." +error = "연동 정보를 불러오지 못했습니다." + +[msg.userfront.dashboard.approved_session] +copy_click = "{label}: {id}\n클릭하면 복사됩니다." +copy_tap = "{label}: {id}\n탭하면 복사됩니다." +none = "{label} 없음" + +[msg.userfront.dashboard.revoke] +confirm = "{app} 앱과의 연동을 해지하시겠습니까?\n해지하면 다음 로그인 시 다시 동의가 필요합니다." +error = "해지 실패: {error}" +success = "{app} 연동이 해지되었습니다." + +[msg.userfront.dashboard.scopes] +empty = "요청된 권한이 없습니다." + +[msg.userfront.dashboard.timeline] +load_error = "접속이력을 불러오지 못했습니다." + +[msg.userfront.error.whitelist] +"$normalizedCode" = "{error}" +bad_request = "입력값을 확인해 주세요." +invalid_session = "세션이 만료되었습니다. 다시 로그인해 주세요." +not_found = "요청한 페이지를 찾을 수 없습니다." +password_or_email_mismatch = "이메일 혹은 비밀번호가 일치하지 않습니다." +rate_limited = "요청이 많습니다. 잠시 후 다시 시도해 주세요." +recovery_expired = "재설정 링크가 만료되었습니다. 다시 요청해 주세요." +recovery_invalid = "재설정 링크가 유효하지 않습니다." +settings_disabled = "현재 계정 설정 화면은 준비 중입니다." +verification_required = "추가 인증이 필요합니다. 안내에 따라 진행해 주세요." + +[msg.userfront.error.ory] +"$normalizedCode" = "{error}" +access_denied = "사용자가 동의를 거부했습니다." +consent_required = "앱 접근 동의가 필요합니다." +interaction_required = "추가 상호작용이 필요합니다. 다시 시도해 주세요." +invalid_client = "클라이언트 인증 정보가 유효하지 않습니다." +invalid_grant = "인증 요청이 만료되었거나 유효하지 않습니다." +invalid_request = "잘못된 요청입니다." +invalid_scope = "요청한 권한 범위가 유효하지 않습니다." +login_required = "로그인이 필요합니다." +request_forbidden = "요청이 거부되었습니다." +server_error = "인증 서버 오류가 발생했습니다." +temporarily_unavailable = "인증 서버를 일시적으로 사용할 수 없습니다." +unauthorized_client = "해당 클라이언트는 이 요청을 수행할 수 없습니다." +unsupported_response_type = "지원하지 않는 응답 타입입니다." + +[msg.userfront.login.link] +helper = "입력하신 정보로 로그인 링크를 전송합니다." +missing_login_id = "이메일 또는 휴대폰 번호를 입력해 주세요." +missing_phone = "휴대폰 번호를 입력해 주세요." +resend_wait = "재발송은 {time} 후 가능합니다." +short_code_help = "링크로 받은 값의 뒤 문자 2개와 숫자 6자리를 입력하셔도 로그인 할 수 있습니다." + +[msg.userfront.login.password] +failed = "로그인 실패: {error}" +missing_credentials = "이메일(또는 전화번호)와 비밀번호를 모두 입력해주세요." + +[msg.userfront.login.qr] +load_failed = "QR 코드를 불러오지 못했습니다." +scan_hint = "모바일 앱으로 스캔하세요" + +[msg.userfront.login.short_code] +invalid = "문자 2개와 숫자 6자리를 입력해 주세요." + +[msg.userfront.login.unregistered] +body = "가입되지 않은 정보입니다.\n회원가입 후 이용해 주세요." + +[msg.userfront.login.verification] +approved = "승인되었습니다. 로그인은 요청하신 창에서 완료됩니다." +approved_local = "승인 되었습니다. 이 기기는 로그인되어 있는 상태입니다. 원격 창도 로그인이 될 예정입니다" +success = "로그인 승인에 성공했습니다." + +[msg.userfront.consent.cancel] +confirm = "권한 동의를 취소하면 해당 서비스를 이용할 수 없습니다. 취소하시겠습니까?" +error = "취소 처리 중 오류가 발생했습니다: {error}" + +[msg.userfront.consent.scope] +email = "이메일 주소 (계정 식별 및 알림 용도)" +offline_access = "오프라인 접근 (로그인 유지)" +openid = "OpenID 인증 정보 (로그인 상태 확인)" +phone = "휴대폰 번호 (본인 인증 및 알림)" +profile = "기본 프로필 정보 (이름, 사용자 식별자)" + +[msg.userfront.profile.password] +change_failed = "비밀번호 변경 실패: {error}" +changed = "비밀번호가 변경되었습니다." +current_required = "현재 비밀번호를 입력해 주세요." +mismatch = "새 비밀번호가 일치하지 않습니다." +new_required = "새 비밀번호를 입력해 주세요." +subtitle = "현재 비밀번호 확인 후 새 비밀번호로 변경합니다." + +[msg.userfront.profile.phone] +code_sent = "인증번호가 전송되었습니다." +send_failed = "전송 실패: {error}" +verified = "인증되었습니다." +verify_failed = "인증 실패: {error}" +verify_notice = "휴대폰 번호를 변경하려면 SMS 인증이 필요합니다." + +[msg.userfront.profile.section] +basic = "계정 기본 정보를 관리합니다." +organization = "소속 및 구분 정보입니다." +security = "비밀번호를 안전하게 관리합니다." + +[msg.userfront.reset.error] +empty_password = "비밀번호를 입력해주세요." +generic = "비밀번호 변경에 실패했습니다: {error}" +lowercase = "최소 1개 이상의 소문자를 포함해야 합니다." +min_length = "비밀번호는 최소 {count}자 이상이어야 합니다." +min_types = "비밀번호는 영문 대/소문자/숫자/특수문자 중 {count}가지 이상 포함해야 합니다." +mismatch = "비밀번호가 일치하지 않습니다." +number = "최소 1개 이상의 숫자를 포함해야 합니다." +symbol = "최소 1개 이상의 특수문자를 포함해야 합니다." +uppercase = "최소 1개 이상의 대문자를 포함해야 합니다." + +[msg.userfront.reset.policy] +lowercase = "소문자 1개 이상" +min_length = "최소 {count}자 이상" +min_types = "영문 대/소문자/숫자/특수문자 중 {count}가지 이상" +number = "숫자 1개 이상" +symbol = "특수문자 1개 이상" +uppercase = "대문자 1개 이상" + +[msg.userfront.signup.agreement] +all_hint = "필수 약관 2개를 모두 확인하고 동의하면 다음 단계로 진행할 수 있습니다." +description = "계속 진행하려면 서비스 이용 조건과 개인정보 수집·이용 항목을 확인한 뒤 동의해주세요." +privacy_summary = "개인정보 수집 항목, 이용 목적, 보관 기준을 안내합니다." +progress = "필수 약관 {total}개 중 {count}개 동의 완료" +tos_summary = "서비스 이용 조건과 책임 범위를 확인할 수 있습니다." +title = "서비스 이용을 위해\n약관에 동의해주세요" + +[msg.userfront.signup.auth] +affiliate_notice = "가족사 회원의 경우 반드시 회사 공식 이메일을 입력해주세요." +title = "본인 확인을 위해\n인증을 진행해주세요" + +[msg.userfront.signup.email] +code_mismatch = "인증코드가 일치하지 않습니다." +duplicate = "이미 가입된 이메일입니다." +invalid = "유효한 이메일 형식이 아닙니다." +send_failed = "발송 실패: {error}" +verified = "✅ 이메일 인증 완료" +verify_failed = "인증 실패: {error}" + +[msg.userfront.signup.password] +length_required = "비밀번호는 최소 12자 이상이어야 합니다." +lowercase_required = "소문자가 최소 1개 이상 포함되어야 합니다." +mismatch = "비밀번호가 일치하지 않습니다." +number_required = "숫자가 최소 1개 이상 포함되어야 합니다." +symbol_required = "특수문자가 최소 1개 이상 포함되어야 합니다." +title = "마지막으로\n비밀번호를 설정해주세요" +uppercase_required = "대문자가 최소 1개 이상 포함되어야 합니다." + +[msg.userfront.signup.phone] +code_mismatch = "인증코드가 일치하지 않습니다." +send_failed = "발송 실패: {error}" +verified = "✅ 휴대폰 인증 완료" +verify_failed = "인증 실패: {error}" + +[msg.userfront.signup.policy] +loading = "비밀번호 정책을 불러오는 중입니다..." +lowercase = "소문자" +min_length = "최소 {count}자 이상" +min_types = "영문 대/소문자/숫자/특수문자 중 {count}가지 이상" +number = "숫자" +summary = "보안 정책: {rules}" +symbol = "특수문자" +uppercase = "대문자" + +[msg.userfront.signup.profile] +affiliate_hint = "가족사 이메일 사용 시 자동으로 선택됩니다." +title = "회원님의\n소속 정보를 알려주세요" + +[msg.userfront.signup.success] +body = "성공적으로 가입되었습니다." +title = "회원가입 완료" + +[ui.userfront.audit.table] +app = "애플리케이션" +auth_method = "인증수단" +date = "접속일자" +device = "접속환경" +ip = "IP" +pending = "(준비중)" +result = "인증결과" +session_id = "Session ID" +status = "현황" + +[ui.userfront.dashboard.activity] +linked = "연동됨" + +[ui.userfront.dashboard.approved_session] +default = "승인한 세션 ID" +userfront = "승인한 Userfront 세션 ID" + +[ui.userfront.dashboard.revoke] +confirm_button = "해지하기" +title = "연동 해지" + +[ui.userfront.dashboard.scopes] +title = "권한 (Scopes)" + +[ui.userfront.dashboard.status] +revoked = "해지됨" + [ui.userfront.login.action] submit = "로그인" @@ -509,31 +541,10 @@ action_label = "확인" page_title = "로그인 승인" title = "승인 완료" -[ui.userfront.login_success] -later = "나중에 하기 (대시보드로 이동)" -qr = "QR 인증 (카메라 켜기)" -title = "로그인 완료" - -[ui.userfront.consent] -accept = "동의하고 계속하기" -requested_scopes = "요청된 권한" -title = "접근 권한 요청" - [ui.userfront.consent.cancel] confirm_button = "예, 취소합니다" title = "동의 취소" -[ui.userfront.nav] -dashboard = "대시보드" -logout = "로그아웃" -profile = "내 정보" -qr_scan = "QR 스캔" - -[ui.userfront.profile] -department_empty = "소속 정보 없음" -manage = "프로필 관리" -user_fallback = "User" - [ui.userfront.profile.field] affiliation = "구분" company_code = "회사코드" @@ -560,31 +571,6 @@ basic = "기본 정보" organization = "조직 정보" security = "보안" -[ui.userfront.qr] -rescan = "다시 스캔" -result_success = "승인 완료" -title = "Scan QR Code" - -[ui.userfront.reset] -confirm_password = "새 비밀번호 확인" -new_password = "새 비밀번호" -submit = "비밀번호 변경" -subtitle = "새로운 비밀번호 설정" -title = "새 비밀번호 설정" - -[ui.userfront.sections] -apps = "나의 App 현황" -audit = "접속이력" - -[ui.userfront.session] -active = "세션 활성" -unknown = "알 수 없음" - -[ui.userfront.signup] -complete = "가입 완료" -next_step = "다음 단계" -title = "회원가입" - [ui.userfront.signup.agreement] all = "모두 동의합니다" privacy_title = "개인정보 수집 및 이용 동의 (필수)" @@ -595,10 +581,6 @@ tos_title = "바론 소프트웨어 이용약관 (필수)" code_label = "인증코드 6자리" request_code = "인증요청" -[ui.userfront.signup.auth.email] -label = "이메일 주소" -title = "이메일 인증" - [ui.userfront.signup.password] confirm_label = "비밀번호 확인" label = "비밀번호" @@ -622,3 +604,16 @@ verify = "본인인증" [ui.userfront.signup.success] action = "로그인하기" + +[msg.userfront.signup.password.rule] +lowercase = "소문자" +min_length = "{count}자 이상" +min_types = "문자 유형 {count}가지 이상" +number = "숫자" +symbol = "특수문자" +uppercase = "대문자" + +[ui.userfront.signup.auth.email] +label = "이메일 주소" +title = "이메일 인증" + diff --git a/userfront/assets/translations/template.toml b/userfront/assets/translations/template.toml index 44c85800..d954d383 100644 --- a/userfront/assets/translations/template.toml +++ b/userfront/assets/translations/template.toml @@ -1,5 +1,3 @@ -[domain] - [domain.affiliation] affiliate = "" general = "" @@ -18,325 +16,9 @@ company_group = "" personal = "" user_group = "" -[err.userfront] - -[err.userfront.auth_proxy] -consent_accept = "" -consent_fetch = "" -consent_reject = "" -linked_app_revoke = "" -login_failed = "" -oidc_accept = "" -password_reset_complete = "" -password_reset_init = "" - -[err.userfront.profile] -load_failed = "" -password_change_failed = "" -send_code_failed = "" -update_failed = "" -verify_code_failed = "" - -[err.userfront.session] -missing = "" - [msg.userfront] greeting = "" -[msg.userfront.audit] -date = "" -device = "" -end = "" -ip = "" -load_more_error = "" -result = "" -session_id = "" -status = "" - -[msg.userfront.dashboard] -approved_device = "" -approved_ip = "" -audit_empty = "" -audit_load_error = "" -render_error = "" -auth_method = "" -client_id = "" -client_id_missing = "" -current_status = "" -last_auth = "" -link_missing = "" -link_open_error = "" -session_id_copied = "" - -[msg.userfront.dashboard.activities] -empty = "" -empty_detail = "" -error = "" - -[msg.userfront.dashboard.approved_session] -copy_click = "" -copy_tap = "" -none = "" - -[msg.userfront.dashboard.revoke] -confirm = "" -error = "" -success = "" - -[msg.userfront.dashboard.scopes] -empty = "" - -[msg.userfront.dashboard.timeline] -load_error = "" - -[msg.userfront.error] -detail_contact = "" -detail_generic = "" -detail_request = "" -id = "" -title = "" -title_generic = "" -title_with_code = "" -type = "" - -[msg.userfront.error.whitelist] -"$normalizedCode" = "" -settings_disabled = "" -invalid_session = "" -verification_required = "" -recovery_expired = "" -recovery_invalid = "" -rate_limited = "" -not_found = "" -bad_request = "" -password_or_email_mismatch = "" - -[msg.userfront.error.ory] -"$normalizedCode" = "" -access_denied = "" -consent_required = "" -interaction_required = "" -invalid_client = "" -invalid_grant = "" -invalid_request = "" -invalid_scope = "" -login_required = "" -request_forbidden = "" -server_error = "" -temporarily_unavailable = "" -unauthorized_client = "" -unsupported_response_type = "" - -[msg.userfront.forgot] -description = "" -dry_send = "" -error = "" -input_required = "" -sent = "" - -[msg.userfront.login] -cookie_check_failed = "" -dry_send = "" -link_failed = "" -link_send_failed = "" -link_sent_email = "" -link_sent_phone = "" -link_timeout = "" -no_account = "" -oidc_failed = "" -qr_expired = "" -qr_init_failed = "" -qr_login_required = "" -token_missing = "" -verification_failed = "" - -[msg.userfront.login.link] -helper = "" -missing_login_id = "" -missing_phone = "" -resend_wait = "" -short_code_help = "" - -[msg.userfront.login.password] -failed = "" -missing_credentials = "" - -[msg.userfront.login.qr] -load_failed = "" -scan_hint = "" - -[msg.userfront.login.short_code] -invalid = "" - -[msg.userfront.login.unregistered] -body = "" - -[msg.userfront.login.verification] -approved = "" -approved_local = "" -success = "" - -[msg.userfront.login_success] -subtitle = "" - -[msg.userfront.consent] -accept_error = "" -client_id = "" -client_unknown = "" -description = "" -load_error = "" -missing_redirect = "" -redirect_notice = "" -scope_count = "" - -[msg.userfront.consent.cancel] -confirm = "" -error = "" - -[msg.userfront.consent.scope] -email = "" -offline_access = "" -openid = "" -phone = "" -profile = "" - -[msg.userfront.profile] -department_missing = "" -department_required = "" -email_missing = "" -greeting = "" -load_failed = "" -name_missing = "" -name_required = "" -phone_required = "" -phone_verify_required = "" -update_failed = "" -update_success = "" - -[msg.userfront.profile.password] -change_failed = "" -changed = "" -current_required = "" -mismatch = "" -new_required = "" -subtitle = "" - -[msg.userfront.profile.phone] -code_sent = "" -send_failed = "" -verified = "" -verify_failed = "" -verify_notice = "" - -[msg.userfront.profile.section] -basic = "" -organization = "" -security = "" - -[msg.userfront.qr] -camera_error = "" -permission_error = "" -permission_required = "" - -[msg.userfront.reset] -invalid_body = "" -invalid_link = "" -invalid_title = "" -policy_loading = "" -success = "" - -[msg.userfront.reset.error] -empty_password = "" -generic = "" -lowercase = "" -min_length = "" -min_types = "" -mismatch = "" -number = "" -symbol = "" -uppercase = "" - -[msg.userfront.reset.policy] -lowercase = "" -min_length = "" -min_types = "" -number = "" -symbol = "" -uppercase = "" - -[msg.userfront.sections] -apps_subtitle = "" -audit_subtitle = "" - -[msg.userfront.settings] -disabled = "" - -[msg.userfront.signup] -failed = "" -privacy_full = "" -tos_full = "" - -[msg.userfront.signup.agreement] -all_hint = "" -description = "" -privacy_summary = "" -progress = "" -tos_summary = "" -title = "" - -[msg.userfront.signup.auth] -affiliate_notice = "" -title = "" - -[msg.userfront.signup.email] -code_mismatch = "" -duplicate = "" -invalid = "" -send_failed = "" -verified = "" -verify_failed = "" - -[msg.userfront.signup.password] -length_required = "" -lowercase_required = "" -mismatch = "" -number_required = "" -symbol_required = "" -title = "" -uppercase_required = "" - -[msg.userfront.signup.password.rule] -lowercase = "" -min_length = "" -min_types = "" -number = "" -symbol = "" -uppercase = "" - -[msg.userfront.signup.phone] -code_mismatch = "" -send_failed = "" -verified = "" -verify_failed = "" - -[msg.userfront.signup.policy] -loading = "" -lowercase = "" -min_length = "" -min_types = "" -number = "" -summary = "" -symbol = "" -uppercase = "" - -[msg.userfront.signup.profile] -affiliate_hint = "" -title = "" - -[msg.userfront.signup.success] -body = "" -title = "" - [ui.common] add = "" all = "" @@ -391,6 +73,137 @@ theme_toggle = "" unknown = "" generate = "" +[ui.userfront] +app_title = "" + +[err.userfront.auth_proxy] +consent_accept = "" +consent_fetch = "" +consent_reject = "" +linked_app_revoke = "" +login_failed = "" +oidc_accept = "" +password_reset_complete = "" +password_reset_init = "" + +[err.userfront.profile] +load_failed = "" +password_change_failed = "" +send_code_failed = "" +update_failed = "" +verify_code_failed = "" + +[err.userfront.session] +missing = "" + +[msg.userfront.audit] +date = "" +device = "" +end = "" +ip = "" +load_more_error = "" +result = "" +session_id = "" +status = "" + +[msg.userfront.dashboard] +approved_device = "" +approved_ip = "" +audit_empty = "" +audit_load_error = "" +render_error = "" +auth_method = "" +client_id = "" +client_id_missing = "" +current_status = "" +last_auth = "" +link_missing = "" +link_open_error = "" +session_id_copied = "" + +[msg.userfront.error] +detail_contact = "" +detail_generic = "" +detail_request = "" +id = "" +title = "" +title_generic = "" +title_with_code = "" +type = "" + +[msg.userfront.forgot] +description = "" +dry_send = "" +error = "" +input_required = "" +sent = "" + +[msg.userfront.login] +cookie_check_failed = "" +dry_send = "" +link_failed = "" +link_send_failed = "" +link_sent_email = "" +link_sent_phone = "" +link_timeout = "" +no_account = "" +oidc_failed = "" +qr_expired = "" +qr_init_failed = "" +qr_login_required = "" +token_missing = "" +verification_failed = "" + +[msg.userfront.login_success] +subtitle = "" + +[msg.userfront.consent] +accept_error = "" +client_id = "" +client_unknown = "" +description = "" +load_error = "" +missing_redirect = "" +redirect_notice = "" +scope_count = "" + +[msg.userfront.profile] +department_missing = "" +department_required = "" +email_missing = "" +greeting = "" +load_failed = "" +name_missing = "" +name_required = "" +phone_required = "" +phone_verify_required = "" +update_failed = "" +update_success = "" + +[msg.userfront.qr] +camera_error = "" +permission_error = "" +permission_required = "" + +[msg.userfront.reset] +invalid_body = "" +invalid_link = "" +invalid_title = "" +policy_loading = "" +success = "" + +[msg.userfront.sections] +apps_subtitle = "" +audit_subtitle = "" + +[msg.userfront.settings] +disabled = "" + +[msg.userfront.signup] +failed = "" +privacy_full = "" +tos_full = "" + [ui.common.badge] admin_only = "" command_only = "" @@ -405,27 +218,11 @@ ok = "" pending = "" success = "" -[ui.userfront] -app_title = "" - [ui.userfront.app_label] admin_console = "" baron = "" dev_console = "" -[ui.userfront.audit] - -[ui.userfront.audit.table] -app = "" -auth_method = "" -date = "" -device = "" -ip = "" -pending = "" -result = "" -session_id = "" -status = "" - [ui.userfront.auth_method] ory = "" session = "" @@ -434,23 +231,6 @@ session = "" last_auth_label = "" status_history = "" -[ui.userfront.dashboard.activity] -linked = "" - -[ui.userfront.dashboard.approved_session] -default = "" -userfront = "" - -[ui.userfront.dashboard.revoke] -confirm_button = "" -title = "" - -[ui.userfront.dashboard.scopes] -title = "" - -[ui.userfront.dashboard.status] -revoked = "" - [ui.userfront.device] android = "" ios = "" @@ -472,6 +252,258 @@ title = "" forgot_password = "" signup = "" +[ui.userfront.login_success] +later = "" +qr = "" +title = "" + +[ui.userfront.consent] +accept = "" +requested_scopes = "" +title = "" + +[ui.userfront.nav] +dashboard = "" +logout = "" +profile = "" +qr_scan = "" + +[ui.userfront.profile] +department_empty = "" +manage = "" +user_fallback = "" + +[ui.userfront.qr] +rescan = "" +result_success = "" +title = "" + +[ui.userfront.reset] +confirm_password = "" +new_password = "" +submit = "" +subtitle = "" +title = "" + +[ui.userfront.sections] +apps = "" +audit = "" + +[ui.userfront.session] +active = "" +unknown = "" + +[ui.userfront.signup] +complete = "" +next_step = "" +title = "" + +[msg.userfront.dashboard.activities] +empty = "" +empty_detail = "" +error = "" + +[msg.userfront.dashboard.approved_session] +copy_click = "" +copy_tap = "" +none = "" + +[msg.userfront.dashboard.revoke] +confirm = "" +error = "" +success = "" + +[msg.userfront.dashboard.scopes] +empty = "" + +[msg.userfront.dashboard.timeline] +load_error = "" + +[msg.userfront.error.whitelist] +"$normalizedCode" = "" +settings_disabled = "" +invalid_session = "" +verification_required = "" +recovery_expired = "" +recovery_invalid = "" +rate_limited = "" +not_found = "" +bad_request = "" +password_or_email_mismatch = "" + +[msg.userfront.error.ory] +"$normalizedCode" = "" +access_denied = "" +consent_required = "" +interaction_required = "" +invalid_client = "" +invalid_grant = "" +invalid_request = "" +invalid_scope = "" +login_required = "" +request_forbidden = "" +server_error = "" +temporarily_unavailable = "" +unauthorized_client = "" +unsupported_response_type = "" + +[msg.userfront.login.link] +helper = "" +missing_login_id = "" +missing_phone = "" +resend_wait = "" +short_code_help = "" + +[msg.userfront.login.password] +failed = "" +missing_credentials = "" + +[msg.userfront.login.qr] +load_failed = "" +scan_hint = "" + +[msg.userfront.login.short_code] +invalid = "" + +[msg.userfront.login.unregistered] +body = "" + +[msg.userfront.login.verification] +approved = "" +approved_local = "" +success = "" + +[msg.userfront.consent.cancel] +confirm = "" +error = "" + +[msg.userfront.consent.scope] +email = "" +offline_access = "" +openid = "" +phone = "" +profile = "" + +[msg.userfront.profile.password] +change_failed = "" +changed = "" +current_required = "" +mismatch = "" +new_required = "" +subtitle = "" + +[msg.userfront.profile.phone] +code_sent = "" +send_failed = "" +verified = "" +verify_failed = "" +verify_notice = "" + +[msg.userfront.profile.section] +basic = "" +organization = "" +security = "" + +[msg.userfront.reset.error] +empty_password = "" +generic = "" +lowercase = "" +min_length = "" +min_types = "" +mismatch = "" +number = "" +symbol = "" +uppercase = "" + +[msg.userfront.reset.policy] +lowercase = "" +min_length = "" +min_types = "" +number = "" +symbol = "" +uppercase = "" + +[msg.userfront.signup.agreement] +all_hint = "" +description = "" +privacy_summary = "" +progress = "" +tos_summary = "" +title = "" + +[msg.userfront.signup.auth] +affiliate_notice = "" +title = "" + +[msg.userfront.signup.email] +code_mismatch = "" +duplicate = "" +invalid = "" +send_failed = "" +verified = "" +verify_failed = "" + +[msg.userfront.signup.password] +length_required = "" +lowercase_required = "" +mismatch = "" +number_required = "" +symbol_required = "" +title = "" +uppercase_required = "" + +[msg.userfront.signup.phone] +code_mismatch = "" +send_failed = "" +verified = "" +verify_failed = "" + +[msg.userfront.signup.policy] +loading = "" +lowercase = "" +min_length = "" +min_types = "" +number = "" +summary = "" +symbol = "" +uppercase = "" + +[msg.userfront.signup.profile] +affiliate_hint = "" +title = "" + +[msg.userfront.signup.success] +body = "" +title = "" + +[ui.userfront.audit.table] +app = "" +auth_method = "" +date = "" +device = "" +ip = "" +pending = "" +result = "" +session_id = "" +status = "" + +[ui.userfront.dashboard.activity] +linked = "" + +[ui.userfront.dashboard.approved_session] +default = "" +userfront = "" + +[ui.userfront.dashboard.revoke] +confirm_button = "" +title = "" + +[ui.userfront.dashboard.scopes] +title = "" + +[ui.userfront.dashboard.status] +revoked = "" + [ui.userfront.login.action] submit = "" @@ -509,31 +541,10 @@ action_label = "" page_title = "" title = "" -[ui.userfront.login_success] -later = "" -qr = "" -title = "" - -[ui.userfront.consent] -accept = "" -requested_scopes = "" -title = "" - [ui.userfront.consent.cancel] confirm_button = "" title = "" -[ui.userfront.nav] -dashboard = "" -logout = "" -profile = "" -qr_scan = "" - -[ui.userfront.profile] -department_empty = "" -manage = "" -user_fallback = "" - [ui.userfront.profile.field] affiliation = "" company_code = "" @@ -560,31 +571,6 @@ basic = "" organization = "" security = "" -[ui.userfront.qr] -rescan = "" -result_success = "" -title = "" - -[ui.userfront.reset] -confirm_password = "" -new_password = "" -submit = "" -subtitle = "" -title = "" - -[ui.userfront.sections] -apps = "" -audit = "" - -[ui.userfront.session] -active = "" -unknown = "" - -[ui.userfront.signup] -complete = "" -next_step = "" -title = "" - [ui.userfront.signup.agreement] all = "" privacy_title = "" @@ -595,10 +581,6 @@ tos_title = "" code_label = "" request_code = "" -[ui.userfront.signup.auth.email] -label = "" -title = "" - [ui.userfront.signup.password] confirm_label = "" label = "" @@ -622,3 +604,16 @@ verify = "" [ui.userfront.signup.success] action = "" + +[msg.userfront.signup.password.rule] +lowercase = "" +min_length = "" +min_types = "" +number = "" +symbol = "" +uppercase = "" + +[ui.userfront.signup.auth.email] +label = "" +title = "" +