Implement multi-language support in user management and system management pages

- Integrated multi-language functionality across various user management components, including user list, roles list, and user authorization pages, enhancing accessibility for diverse users.
- Updated UI elements to utilize translation keys, ensuring that all text is dynamically translated based on user preferences.
- Improved error handling messages to be localized, providing a better user experience in case of issues.

These changes significantly enhance the usability and internationalization of the user management features, making the application more inclusive.
This commit is contained in:
kjs
2026-04-01 15:57:12 +09:00
parent 2ff01456dc
commit 1d49fc7ac7
15 changed files with 812 additions and 200 deletions

View File

@@ -16,6 +16,7 @@ interface UserTableProps {
onStatusToggle: (user: User, newStatus: string) => void;
onPasswordReset: (userId: string, userName: string) => void;
onEdit: (user: User) => void;
t?: (key: string, params?: Record<string, string | number>) => string;
}
/**
@@ -28,7 +29,31 @@ export function UserTable({
onStatusToggle,
onPasswordReset,
onEdit,
t: tProp,
}: UserTableProps) {
// 다국어 함수 (prop이 없으면 한국어 기본값 사용)
const _t = tProp || ((key: string) => {
const defaults: Record<string, string> = {
"table.sabun": "사번",
"table.company": "회사",
"table.dept": "부서명",
"table.position": "직책",
"table.userId": "사용자 ID",
"table.userName": "사용자명",
"table.phone": "전화번호",
"table.email": "이메일",
"table.regDate": "등록일",
"table.status": "상태",
"table.dept.short": "부서",
"table.contact": "연락처",
"table.empty": "등록된 사용자가 없습니다.",
"table.actions": "작업",
"action.edit.user": "사용자 정보 수정",
"action.reset.password": "비밀번호 초기화",
"action.view.history": "변경이력 조회",
};
return defaults[key] || key;
});
const { user: currentUser } = useAuth();
const isSuperAdmin = currentUser?.companyCode === "*" && currentUser?.userType === "SUPER_ADMIN";
@@ -118,7 +143,7 @@ export function UserTable({
},
{
key: "sabun",
label: "사번",
label: _t("table.sabun"),
width: "80px",
hideOnMobile: true,
render: (value) => <span className="font-mono">{value || "-"}</span>,
@@ -127,7 +152,7 @@ export function UserTable({
? [
{
key: "companyCode" as keyof User,
label: "회사",
label: _t("table.company"),
width: "120px",
hideOnMobile: true,
render: (value: any, user: User) => (
@@ -138,42 +163,42 @@ export function UserTable({
: []),
{
key: "deptName",
label: "부서명",
label: _t("table.dept"),
width: "120px",
hideOnMobile: true,
render: (value) => <span className="font-medium">{value || "-"}</span>,
},
{
key: "positionName",
label: "직책",
label: _t("table.position"),
width: "100px",
hideOnMobile: true,
render: (value) => <span className="font-medium">{value || "-"}</span>,
},
{
key: "userId",
label: "사용자 ID",
label: _t("table.userId"),
width: "120px",
hideOnMobile: true,
render: (value) => <span className="font-mono">{value}</span>,
},
{
key: "userName",
label: "사용자명",
label: _t("table.userName"),
width: "100px",
hideOnMobile: true,
render: (value) => <span className="font-medium">{value}</span>,
},
{
key: "tel",
label: "전화번호",
label: _t("table.phone"),
width: "120px",
hideOnMobile: true,
render: (_value, row) => <span>{row.tel || row.cellPhone || "-"}</span>,
},
{
key: "email",
label: "이메일",
label: _t("table.email"),
width: "200px",
hideOnMobile: true,
className: "max-w-[200px] truncate",
@@ -183,14 +208,14 @@ export function UserTable({
},
{
key: "regDate",
label: "등록일",
label: _t("table.regDate"),
width: "100px",
hideOnMobile: true,
render: (value) => <span>{formatDate(value || "")}</span>,
},
{
key: "status",
label: "상태",
label: _t("table.status"),
width: "120px",
hideOnMobile: true,
render: (_value, row) => (
@@ -208,14 +233,14 @@ export function UserTable({
// 모바일 카드 필드 정의
const cardFields: RDVCardField<User>[] = [
{
label: "사번",
label: _t("table.sabun"),
render: (user) => <span className="font-mono font-medium">{user.sabun || "-"}</span>,
hideEmpty: true,
},
...(isSuperAdmin
? [
{
label: "회사",
label: _t("table.company"),
render: (user: User) => (
<span className="font-medium">{(user as any).companyName || user.companyCode || ""}</span>
),
@@ -224,27 +249,27 @@ export function UserTable({
]
: []),
{
label: "부서",
label: _t("table.dept.short"),
render: (user) => <span className="font-medium">{user.deptName || ""}</span>,
hideEmpty: true,
},
{
label: "직책",
label: _t("table.position"),
render: (user) => <span className="font-medium">{user.positionName || ""}</span>,
hideEmpty: true,
},
{
label: "연락처",
label: _t("table.contact"),
render: (user) => <span>{user.tel || user.cellPhone || ""}</span>,
hideEmpty: true,
},
{
label: "이메일",
label: _t("table.email"),
render: (user) => <span className="break-all">{user.email || ""}</span>,
hideEmpty: true,
},
{
label: "등록일",
label: _t("table.regDate"),
render: (user) => <span>{formatDate(user.regDate || "")}</span>,
},
];
@@ -256,7 +281,7 @@ export function UserTable({
columns={columns}
keyExtractor={(u) => u.userId}
isLoading={isLoading}
emptyMessage="등록된 사용자가 없습니다."
emptyMessage={_t("table.empty")}
skeletonCount={10}
cardTitle={(u) => u.userName || ""}
cardSubtitle={(u) => <span className="font-mono">{u.userId}</span>}
@@ -268,7 +293,7 @@ export function UserTable({
/>
)}
cardFields={cardFields}
actionsLabel="작업"
actionsLabel={_t("table.actions")}
actionsWidth="200px"
renderActions={(user) => (
<>
@@ -277,7 +302,7 @@ export function UserTable({
size="icon"
onClick={() => onEdit(user)}
className="h-8 w-8"
title="사용자 정보 수정"
title={_t("action.edit.user")}
>
<Edit className="h-4 w-4" />
</Button>
@@ -286,7 +311,7 @@ export function UserTable({
size="icon"
onClick={() => onPasswordReset(user.userId, user.userName || user.userId)}
className="h-8 w-8"
title="비밀번호 초기화"
title={_t("action.reset.password")}
>
<Key className="h-4 w-4" />
</Button>
@@ -295,7 +320,7 @@ export function UserTable({
size="icon"
onClick={() => handleOpenHistoryModal(user)}
className="h-8 w-8"
title="변경이력 조회"
title={_t("action.view.history")}
>
<History className="h-4 w-4" />
</Button>