diff options
18 files changed, 120 insertions, 33 deletions
diff --git a/app/[lng]/evcp/(evcp)/(master-data)/basic-contract-template/page.tsx b/app/[lng]/evcp/(evcp)/(master-data)/basic-contract-template/page.tsx index f4cab5a0..d3d6fd76 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/basic-contract-template/page.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/basic-contract-template/page.tsx @@ -9,13 +9,17 @@ import { getBasicContractTemplates } from "@/lib/basic-contract/service" import { searchParamsTemplatesCache } from "@/lib/basic-contract/validations" import { BasicContractTemplateTable } from "@/lib/basic-contract/template/basic-contract-template" import { InformationButton } from "@/components/information/information-button" +import { useTranslation } from "@/i18n" interface IndexPageProps { + params: Promise<{ lng: string }> searchParams: Promise<SearchParams> } export default async function IndexPage(props: IndexPageProps) { + const { lng } = await props.params + const { t } = await useTranslation(lng, 'menu') const searchParams = await props.searchParams const search = searchParamsTemplatesCache.parse(searchParams) @@ -36,7 +40,7 @@ export default async function IndexPage(props: IndexPageProps) { <div> <div className="flex items-center gap-2"> <h2 className="text-2xl font-bold tracking-tight"> - 기본 계약문서 관리 + {t('menu.master_data.basic_contract_template')} </h2> <InformationButton pagePath="evcp/basic-contract-template" /> </div> diff --git a/app/[lng]/evcp/(evcp)/(master-data)/bid-projects/layout.tsx b/app/[lng]/evcp/(evcp)/(master-data)/bid-projects/layout.tsx index 9c142df1..5994d3f9 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/bid-projects/layout.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/bid-projects/layout.tsx @@ -2,19 +2,25 @@ import * as React from "react" import { BidProjectsContainer } from "@/components/bidding-projects/bid-projects-container" import { Shell } from "@/components/shell" import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton" +import { useTranslation } from "@/i18n" // Layout 컴포넌트는 서버 컴포넌트입니다 -export default function BidProjectsLayout({ +export default async function BidProjectsLayout({ + params, children, }: { + params: Promise<{ lng: string }> children: React.ReactNode }) { + const { lng } = await params + const { t } = await useTranslation(lng, 'menu') + // 프로젝트 타입 정의 const projectTypes = [ - { id: "all", name: "전체" }, - { id: "SHIP", name: "조선" }, - { id: "TOP", name: "해양 TOP" }, - { id: "HULL", name: "해양 HULL" }, + { id: "all", name: t('common.all') || "전체" }, + { id: "SHIP", name: t('groups.shipbuilding') }, + { id: "TOP", name: `${t('groups.offshore')} TOP` }, + { id: "HULL", name: `${t('groups.offshore')} HULL` }, ] return ( @@ -30,7 +36,7 @@ export default function BidProjectsLayout({ /> } > - <BidProjectsContainer projectTypes={projectTypes}> + <BidProjectsContainer lng={lng} projectTypes={projectTypes}> {children} </BidProjectsContainer> </React.Suspense> diff --git a/app/[lng]/evcp/(evcp)/(master-data)/bid-projects/page.tsx b/app/[lng]/evcp/(evcp)/(master-data)/bid-projects/page.tsx index e98d391b..92879fe9 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/bid-projects/page.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/bid-projects/page.tsx @@ -9,10 +9,14 @@ import { BidProjectsTable } from "@/lib/bidding-projects/table/projects-table" import type { Filter } from "@/types/table" interface IndexPageProps { + params: Promise<{ lng: string }> searchParams: Promise<SearchParams> } export default async function IndexPage(props: IndexPageProps) { + const params = await props.params + const { lng } = params + const searchParams = await props.searchParams const search = searchParamsBidProjectsCache.parse(searchParams) diff --git a/app/[lng]/evcp/(evcp)/(master-data)/buyer-signature/page.tsx b/app/[lng]/evcp/(evcp)/(master-data)/buyer-signature/page.tsx index fa3a1953..96bf783c 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/buyer-signature/page.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/buyer-signature/page.tsx @@ -1,15 +1,19 @@ import { BuyerSignatureUploadForm } from '@/lib/shi-signature/upload-form'; import { SignatureList } from '@/lib/shi-signature/signature-list'; import { getAllSignatures } from '@/lib/shi-signature/buyer-signature'; +import { useTranslation } from "@/i18n" + +export default async function BuyerSignaturePage(props: { params: Promise<{ lng: string }> }) { + const { lng } = await props.params + const { t } = await useTranslation(lng, 'menu') -export default async function BuyerSignaturePage() { const signatures = await getAllSignatures(); return ( <div className="container mx-auto py-8 max-w-4xl"> <div className="space-y-8"> <div> - <h1 className="text-3xl font-bold">구매자 서명 관리</h1> + <h1 className="text-3xl font-bold">{t('menu.master_data.buyer_signature')}</h1> <p className="text-muted-foreground mt-2"> 계약서에 자동으로 적용될 삼성중공업 서명을 관리합니다. </p> diff --git a/app/[lng]/evcp/(evcp)/(master-data)/compliance/page.tsx b/app/[lng]/evcp/(evcp)/(master-data)/compliance/page.tsx index cf624ae8..a355ec37 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/compliance/page.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/compliance/page.tsx @@ -9,12 +9,17 @@ import { getComplianceSurveyTemplates } from "@/lib/compliance/services" import { searchParamsComplianceCache } from "@/lib/compliance/validations" import { ComplianceSurveyTemplatesTable } from "@/lib/compliance/table/compliance-survey-templates-table" import { InformationButton } from "@/components/information/information-button" +import { useTranslation } from "@/i18n" interface IndexPageProps { + params: Promise<{ lng: string }> searchParams: Promise<SearchParams> } export default async function IndexPage(props: IndexPageProps) { + const { lng } = await props.params + const { t } = await useTranslation(lng, 'menu') + const searchParams = await props.searchParams const search = searchParamsComplianceCache.parse(searchParams) @@ -34,12 +39,12 @@ export default async function IndexPage(props: IndexPageProps) { <div> <div className="flex items-center gap-2"> <h2 className="text-2xl font-bold tracking-tight"> - 준법 설문조사 관리 + {t('menu.master_data.compliance_survey')} </h2> <InformationButton pagePath="evcp/compliance" /> </div> <p className="text-muted-foreground"> - 준법 설문조사 템플릿을 관리하고 응답 현황을 확인할 수 있습니다. + {t('menu.master_data.compliance_survey_desc')} </p> </div> </div> diff --git a/app/[lng]/evcp/(evcp)/(master-data)/consent/page.tsx b/app/[lng]/evcp/(evcp)/(master-data)/consent/page.tsx index 3e06cb0f..2319a041 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/consent/page.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/consent/page.tsx @@ -4,6 +4,7 @@ import { eq, desc } from 'drizzle-orm' import db from '@/db/db' import { policyVersions } from '@/db/schema' import { PolicyPageClient } from '@/components/polices/policy-page-client' +import { useTranslation } from "@/i18n" export const metadata: Metadata = { title: '정책 관리 | eVCP Admin', @@ -82,8 +83,10 @@ async function getPoliciesData() { } -export default async function PoliciesPage() { +export default async function PoliciesPage(props: { params: Promise<{ lng: string }> }) { + const { lng } = await props.params + const data = await getPoliciesData() - return <PolicyPageClient data={data} /> + return <PolicyPageClient data={data as any} lng={lng} /> } diff --git a/app/[lng]/evcp/(evcp)/(master-data)/equip-class/page.tsx b/app/[lng]/evcp/(evcp)/(master-data)/equip-class/page.tsx index ddfabf52..5c992a55 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/equip-class/page.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/equip-class/page.tsx @@ -10,12 +10,17 @@ import { FormListsTable } from "@/lib/form-list/table/formLists-table" import { getTagClassists } from "@/lib/equip-class/service" import { EquipClassTable } from "@/lib/equip-class/table/equipClass-table" import { InformationButton } from "@/components/information/information-button" +import { useTranslation } from "@/i18n" interface IndexPageProps { + params: Promise<{ lng: string }> searchParams: Promise<SearchParams> } export default async function IndexPage(props: IndexPageProps) { + const { lng } = await props.params + const { t } = await useTranslation(lng, 'menu') + const searchParams = await props.searchParams const search = searchParamsCache.parse(searchParams) @@ -36,7 +41,7 @@ export default async function IndexPage(props: IndexPageProps) { <div> <div className="flex items-center gap-2"> <h2 className="text-2xl font-bold tracking-tight"> - 객체 클래스 목록 from S-EDP + {t('menu.master_data.object_class')} </h2> <InformationButton pagePath="evcp/equip-class" /> </div> diff --git a/app/[lng]/evcp/(evcp)/(master-data)/form-list/page.tsx b/app/[lng]/evcp/(evcp)/(master-data)/form-list/page.tsx index 7f04cc3e..43023429 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/form-list/page.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/form-list/page.tsx @@ -10,13 +10,18 @@ import { ItemsTable } from "@/lib/items/table/items-table" import { getFormLists } from "@/lib/form-list/service" import { FormListsTable } from "@/lib/form-list/table/formLists-table" import { InformationButton } from "@/components/information/information-button" +import { useTranslation } from "@/i18n" interface IndexPageProps { + params: Promise<{ lng: string }> searchParams: Promise<SearchParams> } export default async function IndexPage(props: IndexPageProps) { + const { lng } = await props.params + const { t } = await useTranslation(lng, 'menu') + const searchParams = await props.searchParams const search = searchParamsCache.parse(searchParams) @@ -37,7 +42,7 @@ export default async function IndexPage(props: IndexPageProps) { <div> <div className="flex items-center gap-2"> <h2 className="text-2xl font-bold tracking-tight"> - 레지스터 목록 from S-EDP + {t('menu.master_data.form_register')} </h2> <InformationButton pagePath="evcp/form-list" /> </div> diff --git a/app/[lng]/evcp/(evcp)/(master-data)/gtc/page.tsx b/app/[lng]/evcp/(evcp)/(master-data)/gtc/page.tsx index 33c504df..c899d99f 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/gtc/page.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/gtc/page.tsx @@ -8,12 +8,22 @@ import { InformationButton } from "@/components/information/information-button" import { GtcDocumentsTable } from "@/lib/gtc-contract/status/gtc-contract-table" import { getGtcDocuments,getProjectsForFilter,getUsersForFilter } from "@/lib/gtc-contract/service" import { searchParamsCache } from "@/lib/gtc-contract/validations" +import { useTranslation } from "@/i18n" + +interface IndexPageProps { + params: Promise<{ lng: string }> + searchParams: Promise<SearchParams> +} interface GtcPageProps { + params: Promise<{ lng: string }> searchParams: Promise<SearchParams> } -export default async function GtcPage(props: GtcPageProps) { +export default async function GtcPage(props: IndexPageProps) { + const { lng } = await props.params + const { t } = await useTranslation(lng, 'menu') + const searchParams = await props.searchParams const search = searchParamsCache.parse(searchParams) const validFilters = getValidFilters(search.filters) @@ -34,7 +44,7 @@ export default async function GtcPage(props: GtcPageProps) { <div> <div className="flex items-center gap-2"> <h2 className="text-2xl font-bold tracking-tight"> - GTC 목록관리 + {t('menu.master_data.gtc')} </h2> <InformationButton pagePath="evcp/basic-contract-template/gtc" /> </div> diff --git a/app/[lng]/evcp/(evcp)/(master-data)/incoterms/page.tsx b/app/[lng]/evcp/(evcp)/(master-data)/incoterms/page.tsx index bf7f9313..cb0aab9b 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/incoterms/page.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/incoterms/page.tsx @@ -8,11 +8,21 @@ import { SearchParamsCache } from "@/lib/incoterms/validations"; import { getIncoterms } from "@/lib/incoterms/service"; import { IncotermsTable } from "@/lib/incoterms/table/incoterms-table"; import { InformationButton } from "@/components/information/information-button"; +import { useTranslation } from "@/i18n" + +interface IndexPageProps { + params: Promise<{ lng: string }> + searchParams: Promise<SearchParams> +} interface IndexPageProps { - searchParams: Promise<SearchParams>; + params: Promise<{ lng: string }> + searchParams: Promise<SearchParams> } export default async function IndexPage(props: IndexPageProps) { + const { lng } = await props.params + const { t } = await useTranslation(lng, 'menu') + const searchParams = await props.searchParams; const search = SearchParamsCache.parse(searchParams); const validFilters = getValidFilters(search.filters); @@ -29,7 +39,7 @@ export default async function IndexPage(props: IndexPageProps) { <div className="flex items-center justify-between space-y-2"> <div> <div className="flex items-center gap-2"> - <h2 className="text-2xl font-bold tracking-tight">인코텀즈 관리</h2> + <h2 className="text-2xl font-bold tracking-tight">{t('menu.master_data.incoterms')}</h2> <InformationButton pagePath="evcp/incoterms" /> </div> {/* <p className="text-muted-foreground"> diff --git a/app/[lng]/evcp/(evcp)/(master-data)/items/page.tsx b/app/[lng]/evcp/(evcp)/(master-data)/items/page.tsx index d61b50df..64f0b4d8 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/items/page.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/items/page.tsx @@ -10,11 +10,17 @@ import { getItems } from "@/lib/items/service" import { ItemsTable } from "@/lib/items/table/items-table" import { ViewModeToggle } from "@/components/data-table/view-mode-toggle" import { InformationButton } from "@/components/information/information-button" +import { useTranslation } from "@/i18n" + interface IndexPageProps { + params: Promise<{ lng: string }> searchParams: Promise<SearchParams> } export default async function IndexPage(props: IndexPageProps) { + const { lng } = await props.params + const { t } = await useTranslation(lng, 'menu') + const searchParams = await props.searchParams const search = searchParamsCache.parse(searchParams) @@ -36,7 +42,7 @@ export default async function IndexPage(props: IndexPageProps) { <div> <div className="flex items-center gap-2"> <h2 className="text-2xl font-bold tracking-tight"> - 패키지 넘버 + {t('menu.master_data.package_numbers')} </h2> <InformationButton pagePath="evcp/items" /> </div> diff --git a/app/[lng]/evcp/(evcp)/(master-data)/projects/page.tsx b/app/[lng]/evcp/(evcp)/(master-data)/projects/page.tsx index c9e6b0e3..a7b5e8d0 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/projects/page.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/projects/page.tsx @@ -10,12 +10,16 @@ import { getProjectLists } from "@/lib/projects/service" import { ProjectsTable } from "@/lib/projects/table/projects-table" import { searchParamsProjectsCache } from "@/lib/projects/validation" import { InformationButton } from "@/components/information/information-button" +import { useTranslation } from "@/i18n" interface IndexPageProps { + params: Promise<{ lng: string }> searchParams: Promise<SearchParams> } export default async function IndexPage(props: IndexPageProps) { + const { lng } = await props.params + const { t } = await useTranslation(lng, 'menu') const searchParams = await props.searchParams const search = searchParamsProjectsCache.parse(searchParams) @@ -36,7 +40,7 @@ export default async function IndexPage(props: IndexPageProps) { <div> <div className="flex items-center gap-2"> <h2 className="text-2xl font-bold tracking-tight"> - 프로젝트 리스트 + {t('menu.master_data.projects')} </h2> <InformationButton pagePath="evcp/projects" /> </div> diff --git a/app/[lng]/evcp/(evcp)/(master-data)/tag-numbering/page.tsx b/app/[lng]/evcp/(evcp)/(master-data)/tag-numbering/page.tsx index ef231108..e6ce9efe 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/tag-numbering/page.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/tag-numbering/page.tsx @@ -9,12 +9,18 @@ import { searchParamsCache } from "@/lib/tag-numbering/validation" import { getTagNumbering } from "@/lib/tag-numbering/service" import { TagNumberingTable } from "@/lib/tag-numbering/table/tagNumbering-table" import { InformationButton } from "@/components/information/information-button" +import { useTranslation } from "@/i18n" interface IndexPageProps { + params: Promise<{ lng: string }> searchParams: Promise<SearchParams> } export default async function IndexPage(props: IndexPageProps) { + const params = await props.params + const { lng } = params + const { t } = await useTranslation(lng, 'menu') + const searchParams = await props.searchParams const search = searchParamsCache.parse(searchParams) @@ -35,7 +41,7 @@ export default async function IndexPage(props: IndexPageProps) { <div> <div className="flex items-center gap-2"> <h2 className="text-2xl font-bold tracking-tight"> - 태그 타입 목록 from S-EDP + {t('menu.master_data.tag_types')} </h2> <InformationButton pagePath="evcp/tag-numbering" /> </div> diff --git a/app/[lng]/evcp/(evcp)/(master-data)/vendor-type/page.tsx b/app/[lng]/evcp/(evcp)/(master-data)/vendor-type/page.tsx index 2e1aa396..e0eedb91 100644 --- a/app/[lng]/evcp/(evcp)/(master-data)/vendor-type/page.tsx +++ b/app/[lng]/evcp/(evcp)/(master-data)/vendor-type/page.tsx @@ -9,12 +9,17 @@ import { searchParamsCache } from "@/lib/vendor-type/validations" import { VendorTypesTable } from "@/lib/vendor-type/table/vendorTypes-table" import { getVendorTypes } from "@/lib/vendor-type/service" import { InformationButton } from "@/components/information/information-button" +import { useTranslation } from "@/i18n" interface IndexPageProps { + params: Promise<{ lng: string }> searchParams: Promise<SearchParams> } export default async function IndexPage(props: IndexPageProps) { + const { lng } = await props.params + const { t } = await useTranslation(lng, 'menu') + const searchParams = await props.searchParams const search = searchParamsCache.parse(searchParams) @@ -35,7 +40,7 @@ export default async function IndexPage(props: IndexPageProps) { <div> <div className="flex items-center gap-2"> <h2 className="text-2xl font-bold tracking-tight"> - 업체 유형 + {t('menu.master_data.vendor_types')} </h2> <InformationButton pagePath="evcp/vendor-type" /> </div> diff --git a/components/bidding-projects/bid-projects-container.tsx b/components/bidding-projects/bid-projects-container.tsx index 9890a959..6d6638f6 100644 --- a/components/bidding-projects/bid-projects-container.tsx +++ b/components/bidding-projects/bid-projects-container.tsx @@ -12,6 +12,7 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { InformationButton } from "@/components/information/information-button" +import { useTranslation } from "@/i18n/client" interface ProjectType { id: string @@ -19,14 +20,17 @@ interface ProjectType { } interface BidProjectsContainerProps { + lng: string projectTypes: ProjectType[] children: React.ReactNode } export function BidProjectsContainer({ + lng, projectTypes, children, }: BidProjectsContainerProps) { + const { t } = useTranslation(lng, 'menu') const router = useRouter() const pathname = usePathname() const searchParamsObj = useSearchParams() @@ -41,7 +45,7 @@ export function BidProjectsContainer({ const projectType = searchParams.get("type") || "all" // 선택한 프로젝트 타입에 해당하는 이름 찾기 - const selectedProject = projectTypes.find((project) => project.id === projectType)?.name || "전체" + const selectedProject = projectTypes.find((project) => project.id === projectType)?.name || t('common.all') || "전체" // 프로젝트 타입 변경 핸들러 const handleProjectTypeChange = React.useCallback((value: string) => { @@ -66,7 +70,7 @@ export function BidProjectsContainer({ {/* 왼쪽: 타이틀 & 설명 */} <div> <div className="flex items-center gap-2"> - <h2 className="text-2xl font-bold tracking-tight">견적 프로젝트 리스트</h2> + <h2 className="text-2xl font-bold tracking-tight">{t('menu.master_data.bid_projects')}</h2> <InformationButton pagePath="evcp/bid-projects" /> </div> {/* <p className="text-muted-foreground"> diff --git a/components/polices/policy-page-client.tsx b/components/polices/policy-page-client.tsx index ccc87c31..86bd3128 100644 --- a/components/polices/policy-page-client.tsx +++ b/components/polices/policy-page-client.tsx @@ -4,6 +4,7 @@ import { useState } from 'react' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { FileText, Shield, Clock, Calendar, User } from 'lucide-react' import { PolicyManagementClient } from '@/components/polices/policy-management-client' +import { useTranslation } from '@/i18n/client' interface Policy { id: number @@ -44,7 +45,8 @@ interface PolicyPageClientProps { } lastUpdate: string | null } - } + }, + lng: string } // 선택된 locale의 가장 최근 업데이트 날짜를 가져오는 함수 @@ -64,7 +66,9 @@ function getLastUpdateForLocale(data: PolicyPageClientProps['data'], locale: 'ko return sortedPolicies[0]?.createdAt || null } -export function PolicyPageClient({ data }: PolicyPageClientProps) { +export function PolicyPageClient({ data, lng }: PolicyPageClientProps) { + const { t } = useTranslation(lng, 'menu') + const [selectedLocale, setSelectedLocale] = useState<'ko' | 'en'>('ko') // 선택된 locale에 맞는 데이터 필터링 @@ -90,9 +94,9 @@ export function PolicyPageClient({ data }: PolicyPageClientProps) { {/* 헤더 */} <div className="flex items-center justify-between"> <div> - <h2 className="text-2xl font-bold tracking-tight">정책 관리</h2> + <h2 className="text-2xl font-bold tracking-tight">{t('menu.vendor_management.vendor_consent')}</h2> <p className="text-muted-foreground"> - 개인정보 처리방침과 이용약관을 버전별로 관리합니다 + {t('menu.vendor_management.vendor_consent_desc')} </p> </div> diff --git a/i18n/locales/en/menu.json b/i18n/locales/en/menu.json index bb99f0ef..bee0a946 100644 --- a/i18n/locales/en/menu.json +++ b/i18n/locales/en/menu.json @@ -292,8 +292,9 @@ "settings": "Settings", "logout": "Logout" }, - "common": { - "search": "Search", - "no_available_menus": "No available menus." - } + "common": { + "all": "All", + "search": "Search", + "no_available_menus": "No available menus." + } }
\ No newline at end of file diff --git a/i18n/locales/ko/menu.json b/i18n/locales/ko/menu.json index d5c159e2..376bf811 100644 --- a/i18n/locales/ko/menu.json +++ b/i18n/locales/ko/menu.json @@ -292,6 +292,7 @@ "logout": "로그아웃" }, "common": { + "all": "전체", "search": "검색", "no_available_menus": "사용 가능한 메뉴가 없습니다." } |
