diff --git a/adminfront/package.json b/adminfront/package.json index 84419dea..0ff96d03 100644 --- a/adminfront/package.json +++ b/adminfront/package.json @@ -12,7 +12,8 @@ "preview": "vite preview", "test": "playwright test", "test:unit": "vitest run", - "test:ui": "playwright test --ui" + "test:ui": "playwright test --ui", + "i18n-scan": "cd .. && node tools/i18n-scanner/index.js && node tools/i18n-scanner/report.js" }, "dependencies": { "@radix-ui/react-avatar": "^1.1.4", diff --git a/fix_toml.py b/fix_toml.py new file mode 100644 index 00000000..d8b21fd8 --- /dev/null +++ b/fix_toml.py @@ -0,0 +1,43 @@ +import os +import re + +def fix_toml(filepath): + with open(filepath, 'r', encoding='utf-8') as f: + lines = f.readlines() + + sections = {} + current_section = None + + for line in lines: + sline = line.strip() + + if sline.startswith('[') and sline.endswith(']'): + current_section = sline + if current_section not in sections: + sections[current_section] = [] + else: + if current_section is None: + if sline: # Ignore empty lines at the very top before any section + current_section = "_TOP_" + if current_section not in sections: + sections[current_section] = [] + if current_section is not None: + sections[current_section].append(line) + + with open(filepath, 'w', encoding='utf-8') as f: + if "_TOP_" in sections: + for line in sections["_TOP_"]: + f.write(line) + del sections["_TOP_"] + + for sec, slines in sections.items(): + f.write(sec + '\n') + for line in slines: + if line.strip(): # keep only non-empty to avoid huge gaps + f.write(line) + f.write('\n') + +for file in ['locales/template.toml', 'locales/ko.toml', 'locales/en.toml']: + fix_toml(file) + print("Fixed", file) + diff --git a/locales/en.toml b/locales/en.toml index 177d7c74..61fd7bc4 100644 --- a/locales/en.toml +++ b/locales/en.toml @@ -1,4 +1,3 @@ - [domain] [domain.affiliation] @@ -202,6 +201,8 @@ empty = "Empty" remove_confirm = "Remove Confirm" remove_success = "Remove Success" subtitle = "Subtitle" +remove_last = "Cannot remove the last admin." +remove_self = "Cannot remove yourself." [msg.admin.tenants.owners] add_success = "Owner added successfully." @@ -209,6 +210,8 @@ empty = "No owners registered." remove_confirm = "Are you sure you want to remove this owner?" remove_success = "Owner permission revoked." subtitle = "List of owners with top-level permissions for this tenant." +remove_last = "Cannot remove the last owner." +remove_self = "Cannot remove yourself." [msg.admin.tenants.create] subtitle = "Subtitle" @@ -237,6 +240,7 @@ missing_id = "Tenant ID missing" subtitle = "Define custom attributes for users in this tenant." update_error = "Failed to update schema" update_success = "Schema updated successfully" +forbidden_desc = "Only administrators can access user schema settings." [msg.admin.tenants.sub] empty = "Empty" @@ -253,6 +257,8 @@ move_error = "Error moving users." move_success = "{{count}} users moved successfully." parsed_count = "Parsed {{count}} rows." update_success = "User info updated successfully." +schema_incompatible = "Fields not in target schema may be lost:" +schema_missing = "Missing required fields for target tenant:" [msg.admin.users.create] error = "Failed to User Create." @@ -280,6 +286,7 @@ edit_subtitle = "Edit Subtitle" not_found = "Not Found" update_error = "Failed to User Edit." update_success = "Update Success" +password_generated = "A secure password has been generated." [msg.admin.users.detail.form] field_required = "Required." @@ -309,6 +316,8 @@ parsing = "Parsing data..." requesting = "Requesting..." saving = "Saving..." unknown_error = "unknown error" +copied_to_clipboard = "Copied to clipboard." +forbidden = "Access Denied." [msg.dev] logout_confirm = "Are you sure you want to log out?" @@ -990,6 +999,9 @@ type_date = "Date" type_number = "Number" type_text = "Text" validation_placeholder = "Regex Pattern (Optional)" +type_datetime = "DateTime" +type_float = "Float" +unsigned = "Unsigned" [ui.admin.tenants.sub] add = "Add" @@ -1029,6 +1041,8 @@ select_group = "Select Target Tenant" selected_count = "{{count}} users selected" start_upload = "Start Upload" title = "Bulk Actions" +acknowledge_warning = "I acknowledge the warning and will proceed." +schema_warning = "Schema Compatibility Warning" [ui.admin.users.create] back = "Back" @@ -1073,6 +1087,7 @@ title = "Title" back = "Back" edit_title = "Edit Title" title = "User Details" +generate_password = "Auto Generate" [ui.admin.users.detail.breadcrumb] section = "Users" @@ -1138,7 +1153,6 @@ email = "Email" name = "Name" role = "Role" - [ui.common] add = "Add" all = "All" @@ -1191,6 +1205,7 @@ theme_dark = "Dark" theme_light = "Light" theme_toggle = "Theme Toggle" unknown = "Unknown" +generate = "Generate" [ui.common.badge] admin_only = "Admin only" @@ -1689,39 +1704,3 @@ verify = "Verify" [ui.userfront.signup.success] action = "Action" -[msg.admin.tenants.admins] -remove_last = "Cannot remove the last admin." -remove_self = "Cannot remove yourself." - -[msg.admin.tenants.owners] -remove_last = "Cannot remove the last owner." -remove_self = "Cannot remove yourself." - -[msg.admin.tenants.schema] -forbidden_desc = "Only administrators can access user schema settings." - -[msg.admin.users.bulk] -schema_incompatible = "Fields not in target schema may be lost:" -schema_missing = "Missing required fields for target tenant:" - -[msg.admin.users.detail] -password_generated = "A secure password has been generated." - -[msg.common] -copied_to_clipboard = "Copied to clipboard." -forbidden = "Access Denied." - -[ui.admin.tenants.schema.field] -type_datetime = "DateTime" -type_float = "Float" -unsigned = "Unsigned" - -[ui.admin.users.bulk] -acknowledge_warning = "I acknowledge the warning and will proceed." -schema_warning = "Schema Compatibility Warning" - -[ui.admin.users.detail] -generate_password = "Auto Generate" - -[ui.common] -generate = "Generate" diff --git a/locales/ko.toml b/locales/ko.toml index 000661d7..aec1a837 100644 --- a/locales/ko.toml +++ b/locales/ko.toml @@ -1,4 +1,3 @@ - [domain] [domain.affiliation] @@ -202,6 +201,8 @@ empty = "등록된 관리자가 없습니다." remove_confirm = "관리자를 삭제하시겠습니까?" remove_success = "권한이 회수되었습니다." subtitle = "이 테넌트의 자원을 관리할 수 있는 사용자 목록입니다." +remove_last = "마지막 관리자는 회수할 수 없습니다." +remove_self = "본인의 권한은 회수할 수 없습니다." [msg.admin.tenants.owners] add_success = "소유자가 추가되었습니다." @@ -209,6 +210,8 @@ empty = "등록된 소유자가 없습니다." remove_confirm = "소유자를 삭제하시겠습니까?" remove_success = "소유자 권한이 회수되었습니다." subtitle = "이 테넌트의 최상위 권한을 가진 소유자(조직장) 목록입니다." +remove_last = "마지막 소유자는 회수할 수 없습니다." +remove_self = "본인의 권한은 회수할 수 없습니다." [msg.admin.tenants.create] subtitle = "글로벌 운영 기준의 신규 테넌트를 등록합니다." @@ -237,6 +240,7 @@ missing_id = "테넌트 ID가 없습니다." subtitle = "이 테넌트의 사용자에게 적용할 커스텀 속성을 정의합니다." update_error = "스키마 업데이트에 실패했습니다." update_success = "스키마가 성공적으로 업데이트되었습니다." +forbidden_desc = "사용자 스키마 설정은 관리자만 접근할 수 있습니다." [msg.admin.tenants.sub] empty = "하위 테넌트가 없습니다." @@ -253,6 +257,8 @@ move_error = "사용자 이동 중 오류가 발생했습니다." move_success = "{{count}}명의 사용자가 성공적으로 이동되었습니다." parsed_count = "{{count}}행의 데이터가 파싱되었습니다." update_success = "사용자 정보가 일괄 업데이트되었습니다." +schema_incompatible = "대상 테넌트 스키마에 없는 필드는 유실될 수 있습니다:" +schema_missing = "대상 테넌트의 필수 필드가 누락되어 있습니다:" [msg.admin.users.create] error = "사용자 생성에 실패했습니다." @@ -280,6 +286,7 @@ edit_subtitle = "{{email}} 계정의 정보를 수정합니다." not_found = "사용자를 찾을 수 없습니다." update_error = "사용자 수정에 실패했습니다." update_success = "사용자 정보가 수정되었습니다." +password_generated = "안전한 비밀번호가 생성되었습니다." [msg.admin.users.detail.form] field_required = "필수입니다." @@ -309,6 +316,8 @@ parsing = "데이터 파싱 중..." requesting = "요청 중..." saving = "저장 중..." unknown_error = "알 수 없는 오류" +copied_to_clipboard = "클립보드에 복사되었습니다." +forbidden = "접근 권한이 없습니다." [msg.dev] logout_confirm = "로그아웃 하시겠습니까?" @@ -990,6 +999,9 @@ type_date = "Date" type_number = "Number" type_text = "Text" validation_placeholder = "정규표현식 (선택 사항)" +type_datetime = "일시 (DateTime)" +type_float = "실수 (Float)" +unsigned = "음수 불가" [ui.admin.tenants.sub] add = "하위 테넌트 추가" @@ -1029,6 +1041,8 @@ select_group = "대상 테넌트 선택" selected_count = "{{count}}명 선택됨" start_upload = "업로드 시작" title = "일괄 작업" +acknowledge_warning = "경고를 확인했으며 계속 진행합니다." +schema_warning = "스키마 호환성 경고" [ui.admin.users.create] back = "목록으로 돌아가기" @@ -1073,6 +1087,7 @@ title = "초기 비밀번호 생성 완료" back = "목록으로 돌아가기" edit_title = "정보 수정" title = "사용자 상세" +generate_password = "자동 생성" [ui.admin.users.detail.breadcrumb] section = "Users" @@ -1138,7 +1153,6 @@ email = "이메일" name = "이름" role = "역할" - [ui.common] add = "추가" all = "전체" @@ -1191,6 +1205,7 @@ theme_dark = "Dark" theme_light = "Light" theme_toggle = "테마 전환" unknown = "Unknown" +generate = "생성" [ui.common.badge] admin_only = "Admin only" @@ -1685,39 +1700,3 @@ verify = "본인인증" [ui.userfront.signup.success] action = "로그인하기" -[msg.admin.tenants.admins] -remove_last = "마지막 관리자는 회수할 수 없습니다." -remove_self = "본인의 권한은 회수할 수 없습니다." - -[msg.admin.tenants.owners] -remove_last = "마지막 소유자는 회수할 수 없습니다." -remove_self = "본인의 권한은 회수할 수 없습니다." - -[msg.admin.tenants.schema] -forbidden_desc = "사용자 스키마 설정은 관리자만 접근할 수 있습니다." - -[msg.admin.users.bulk] -schema_incompatible = "대상 테넌트 스키마에 없는 필드는 유실될 수 있습니다:" -schema_missing = "대상 테넌트의 필수 필드가 누락되어 있습니다:" - -[msg.admin.users.detail] -password_generated = "안전한 비밀번호가 생성되었습니다." - -[msg.common] -copied_to_clipboard = "클립보드에 복사되었습니다." -forbidden = "접근 권한이 없습니다." - -[ui.admin.tenants.schema.field] -type_datetime = "일시 (DateTime)" -type_float = "실수 (Float)" -unsigned = "음수 불가" - -[ui.admin.users.bulk] -acknowledge_warning = "경고를 확인했으며 계속 진행합니다." -schema_warning = "스키마 호환성 경고" - -[ui.admin.users.detail] -generate_password = "자동 생성" - -[ui.common] -generate = "생성" diff --git a/locales/template.toml b/locales/template.toml index 1d55c1f6..db7e269b 100644 --- a/locales/template.toml +++ b/locales/template.toml @@ -1,4 +1,3 @@ - [domain] [domain.affiliation] @@ -202,6 +201,8 @@ empty = "" remove_confirm = "" remove_success = "" subtitle = "" +remove_last = "" +remove_self = "" [msg.admin.tenants.owners] add_success = "" @@ -209,6 +210,8 @@ empty = "" remove_confirm = "" remove_success = "" subtitle = "" +remove_last = "" +remove_self = "" [msg.admin.tenants.create] subtitle = "" @@ -237,6 +240,7 @@ missing_id = "" subtitle = "" update_error = "" update_success = "" +forbidden_desc = "" [msg.admin.tenants.sub] empty = "" @@ -253,6 +257,8 @@ move_error = "" move_success = "" parsed_count = "" update_success = "" +schema_incompatible = "" +schema_missing = "" [msg.admin.users.create] error = "" @@ -280,6 +286,7 @@ edit_subtitle = "" not_found = "" update_error = "" update_success = "" +password_generated = "" [msg.admin.users.detail.form] field_required = "" @@ -309,6 +316,8 @@ parsing = "" requesting = "" saving = "" unknown_error = "" +copied_to_clipboard = "" +forbidden = "" [msg.dev] logout_confirm = "" @@ -990,6 +999,9 @@ type_date = "" type_number = "" type_text = "" validation_placeholder = "" +type_datetime = "" +type_float = "" +unsigned = "" [ui.admin.tenants.sub] add = "" @@ -1029,6 +1041,8 @@ select_group = "" selected_count = "" start_upload = "" title = "" +acknowledge_warning = "" +schema_warning = "" [ui.admin.users.create] back = "" @@ -1073,6 +1087,7 @@ title = "" back = "" edit_title = "" title = "" +generate_password = "" [ui.admin.users.detail.breadcrumb] section = "" @@ -1138,7 +1153,6 @@ email = "" name = "" role = "" - [ui.common] add = "" all = "" @@ -1191,6 +1205,7 @@ theme_dark = "" theme_light = "" theme_toggle = "" unknown = "" +generate = "" [ui.common.badge] admin_only = "" @@ -1685,39 +1700,3 @@ verify = "" [ui.userfront.signup.success] action = "" -[msg.admin.tenants.admins] -remove_last = "" -remove_self = "" - -[msg.admin.tenants.owners] -remove_last = "" -remove_self = "" - -[msg.admin.tenants.schema] -forbidden_desc = "" - -[msg.admin.users.bulk] -schema_incompatible = "" -schema_missing = "" - -[msg.admin.users.detail] -password_generated = "" - -[msg.common] -copied_to_clipboard = "" -forbidden = "" - -[ui.admin.tenants.schema.field] -type_datetime = "" -type_float = "" -unsigned = "" - -[ui.admin.users.bulk] -acknowledge_warning = "" -schema_warning = "" - -[ui.admin.users.detail] -generate_password = "" - -[ui.common] -generate = ""