diff options
Diffstat (limited to 'lib/basic-contract/vendor-table/basic-contract-columns.tsx')
| -rw-r--r-- | lib/basic-contract/vendor-table/basic-contract-columns.tsx | 96 |
1 files changed, 78 insertions, 18 deletions
diff --git a/lib/basic-contract/vendor-table/basic-contract-columns.tsx b/lib/basic-contract/vendor-table/basic-contract-columns.tsx index c9e8da53..1b11285c 100644 --- a/lib/basic-contract/vendor-table/basic-contract-columns.tsx +++ b/lib/basic-contract/vendor-table/basic-contract-columns.tsx @@ -32,14 +32,65 @@ import { BasicContractView } from "@/db/schema" interface GetColumnsProps { setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<BasicContractView> | null>> + locale?: string + t: (key: string) => string // 번역 함수 } +// 기본 번역값들 (fallback) +const fallbackTranslations = { + ko: { + download: "다운로드", + selectAll: "전체 선택", + selectRow: "행 선택", + fileInfoMissing: "파일 정보가 없습니다.", + fileDownloadError: "파일 다운로드 중 오류가 발생했습니다.", + statusValues: { + PENDING: "서명대기", + COMPLETED: "서명완료" + } + }, + en: { + download: "Download", + selectAll: "Select all", + selectRow: "Select row", + fileInfoMissing: "File information is missing.", + fileDownloadError: "An error occurred while downloading the file.", + statusValues: { + PENDING: "Pending", + COMPLETED: "Completed" + } + } +}; + +// 안전한 번역 함수 +const safeTranslate = (t: (key: string) => string, key: string, locale: string = 'ko', fallback?: string): string => { + try { + const translated = t(key); + // 번역 키가 그대로 반환되는 경우 (번역 실패) fallback 사용 + if (translated === key && fallback) { + return fallback; + } + return translated || fallback || key; + } catch (error) { + console.warn(`Translation failed for key: ${key}`, error); + return fallback || key; + } +}; + /** * 파일 다운로드 함수 */ -const handleFileDownload = async (filePath: string | null, fileName: string | null) => { +const handleFileDownload = async ( + filePath: string | null, + fileName: string | null, + t: (key: string) => string, + locale: string = 'ko' +) => { + const fallback = fallbackTranslations[locale as keyof typeof fallbackTranslations] || fallbackTranslations.ko; + if (!filePath || !fileName) { - toast.error("파일 정보가 없습니다."); + const message = safeTranslate(t, "basicContracts.fileInfoMissing", locale, fallback.fileInfoMissing); + toast.error(message); return; } @@ -57,14 +108,17 @@ const handleFileDownload = async (filePath: string | null, fileName: string | nu } } catch (error) { console.error("파일 다운로드 오류:", error); - toast.error("파일 다운로드 중 오류가 발생했습니다."); + const message = safeTranslate(t, "basicContracts.fileDownloadError", locale, fallback.fileDownloadError); + toast.error(message); } }; /** * tanstack table 컬럼 정의 (중첩 헤더 버전) */ -export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<BasicContractView>[] { +export function getColumns({ setRowAction, locale = 'ko', t }: GetColumnsProps): ColumnDef<BasicContractView>[] { + const fallback = fallbackTranslations[locale as keyof typeof fallbackTranslations] || fallbackTranslations.ko; + // ---------------------------------------------------------------- // 1) select 컬럼 (체크박스) // ---------------------------------------------------------------- @@ -77,7 +131,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<BasicCo (table.getIsSomePageRowsSelected() && "indeterminate") } onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)} - aria-label="Select all" + aria-label={safeTranslate(t, "basicContracts.selectAll", locale, fallback.selectAll)} className="translate-y-0.5" /> ), @@ -85,7 +139,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<BasicCo <Checkbox checked={row.getIsSelected()} onCheckedChange={(value) => row.toggleSelected(!!value)} - aria-label="Select row" + aria-label={safeTranslate(t, "basicContracts.selectRow", locale, fallback.selectRow)} className="translate-y-0.5" /> ), @@ -105,18 +159,19 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<BasicCo // PENDING 상태일 때는 원본 PDF 파일 (signedFilePath), COMPLETED일 때는 서명된 파일 (signedFilePath) const filePath = contract.signedFilePath; const fileName = contract.signedFileName; + const downloadText = safeTranslate(t, "basicContracts.download", locale, fallback.download); return ( <Button variant="ghost" size="icon" - onClick={() => handleFileDownload(filePath, fileName)} - title={`${fileName} 다운로드`} + onClick={() => handleFileDownload(filePath, fileName, t, locale)} + title={`${fileName} ${downloadText}`} className="hover:bg-muted" disabled={!filePath || !fileName} > <Paperclip className="h-4 w-4" /> - <span className="sr-only">다운로드</span> + <span className="sr-only">{downloadText}</span> </Button> ); }, @@ -124,7 +179,6 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<BasicCo enableSorting: false, } - // ---------------------------------------------------------------- // 4) 일반 컬럼들을 "그룹"별로 묶어 중첩 columns 생성 // ---------------------------------------------------------------- @@ -152,22 +206,28 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<BasicCo type: cfg.type, }, cell: ({ row, cell }) => { - // 날짜 형식 처리 + // 날짜 형식 처리 - 로케일 적용 if (cfg.id === "createdAt" || cfg.id === "updatedAt" || cfg.id === "completedAt") { const dateVal = cell.getValue() as Date - return formatDateTime(dateVal) + return formatDateTime(dateVal, locale) } - // Status 컬럼에 Badge 적용 + // Status 컬럼에 Badge 적용 - 다국어 적용 if (cfg.id === "status") { const status = row.getValue(cfg.id) as string const isPending = status === "PENDING" + const statusText = safeTranslate( + t, + `basicContracts.statusValues.${status}`, + locale, + fallback.statusValues[status as keyof typeof fallback.statusValues] || status + ); return ( <Badge variant={!isPending ? "default" : "secondary"} > - {status} + {statusText} </Badge> ) } @@ -175,8 +235,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<BasicCo // 나머지 컬럼은 그대로 값 표시 return row.getValue(cfg.id) ?? "" }, - minSize: 80, - + minSize: 80, } groupMap[groupName].push(childCol) @@ -194,10 +253,11 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<BasicCo // 그룹 없음 → 그냥 최상위 레벨 컬럼 nestedColumns.push(...colDefs) } else { - // 상위 컬럼 + // 상위 컬럼 - 그룹명 다국어 적용 + const translatedGroupName = t(`basicContracts.groups.${groupName}`) || groupName; nestedColumns.push({ id: groupName, - header: groupName, // "Basic Info", "Metadata" 등 + header: translatedGroupName, columns: colDefs, }) } |
