142 lines
4.2 KiB
TypeScript
142 lines
4.2 KiB
TypeScript
"use client";
|
|
|
|
import React, { createContext, useContext, useState, useEffect, useMemo, ReactNode } from "react";
|
|
import { apiClient } from "@/lib/api/client";
|
|
import { useMultiLang } from "@/hooks/useMultiLang";
|
|
import { ComponentData } from "@/types/screen";
|
|
|
|
interface ScreenMultiLangContextValue {
|
|
translations: Record<string, string>;
|
|
loading: boolean;
|
|
getTranslatedText: (langKey: string | undefined, fallback: string) => string;
|
|
}
|
|
|
|
const ScreenMultiLangContext = createContext<ScreenMultiLangContextValue | null>(null);
|
|
|
|
interface ScreenMultiLangProviderProps {
|
|
children: ReactNode;
|
|
components: ComponentData[];
|
|
companyCode?: string;
|
|
}
|
|
|
|
/**
|
|
* 화면 컴포넌트들의 다국어 번역을 제공하는 Provider
|
|
* 모든 langKey를 수집하여 한 번에 배치 조회하고, 하위 컴포넌트에서 번역 텍스트를 사용할 수 있게 함
|
|
*/
|
|
export const ScreenMultiLangProvider: React.FC<ScreenMultiLangProviderProps> = ({
|
|
children,
|
|
components,
|
|
companyCode = "*",
|
|
}) => {
|
|
const { userLang } = useMultiLang();
|
|
const [translations, setTranslations] = useState<Record<string, string>>({});
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
// 모든 컴포넌트에서 langKey 수집
|
|
const langKeys = useMemo(() => {
|
|
const keys: string[] = [];
|
|
|
|
const collectLangKeys = (comps: ComponentData[]) => {
|
|
comps.forEach((comp) => {
|
|
// 컴포넌트 라벨의 langKey
|
|
if ((comp as any).langKey) {
|
|
keys.push((comp as any).langKey);
|
|
}
|
|
// componentConfig 내의 langKey (버튼 텍스트 등)
|
|
if ((comp as any).componentConfig?.langKey) {
|
|
keys.push((comp as any).componentConfig.langKey);
|
|
}
|
|
// properties 내의 langKey (레거시)
|
|
if ((comp as any).properties?.langKey) {
|
|
keys.push((comp as any).properties.langKey);
|
|
}
|
|
// 테이블 리스트 컬럼의 langKey 수집
|
|
if ((comp as any).componentConfig?.columns) {
|
|
(comp as any).componentConfig.columns.forEach((col: any) => {
|
|
if (col.langKey) {
|
|
keys.push(col.langKey);
|
|
}
|
|
});
|
|
}
|
|
// 자식 컴포넌트 재귀 처리
|
|
if ((comp as any).children) {
|
|
collectLangKeys((comp as any).children);
|
|
}
|
|
});
|
|
};
|
|
|
|
collectLangKeys(components);
|
|
return [...new Set(keys)]; // 중복 제거
|
|
}, [components]);
|
|
|
|
// langKey가 있으면 배치 조회
|
|
useEffect(() => {
|
|
const loadTranslations = async () => {
|
|
if (langKeys.length === 0 || !userLang) {
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
try {
|
|
console.log("🌐 [ScreenMultiLang] 다국어 배치 로드:", { langKeys: langKeys.length, userLang, companyCode });
|
|
|
|
const response = await apiClient.post(
|
|
"/multilang/batch",
|
|
{ langKeys },
|
|
{
|
|
params: {
|
|
userLang,
|
|
companyCode,
|
|
},
|
|
}
|
|
);
|
|
|
|
if (response.data?.success && response.data?.data) {
|
|
console.log("✅ [ScreenMultiLang] 다국어 로드 완료:", Object.keys(response.data.data).length, "개");
|
|
setTranslations(response.data.data);
|
|
}
|
|
} catch (error) {
|
|
console.error("❌ [ScreenMultiLang] 다국어 로드 실패:", error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
loadTranslations();
|
|
}, [langKeys, userLang, companyCode]);
|
|
|
|
// 번역 텍스트 가져오기 헬퍼
|
|
const getTranslatedText = (langKey: string | undefined, fallback: string): string => {
|
|
if (!langKey) return fallback;
|
|
return translations[langKey] || fallback;
|
|
};
|
|
|
|
const value = useMemo(
|
|
() => ({
|
|
translations,
|
|
loading,
|
|
getTranslatedText,
|
|
}),
|
|
[translations, loading]
|
|
);
|
|
|
|
return <ScreenMultiLangContext.Provider value={value}>{children}</ScreenMultiLangContext.Provider>;
|
|
};
|
|
|
|
/**
|
|
* 화면 다국어 컨텍스트 사용 훅
|
|
*/
|
|
export const useScreenMultiLang = (): ScreenMultiLangContextValue => {
|
|
const context = useContext(ScreenMultiLangContext);
|
|
if (!context) {
|
|
// 컨텍스트가 없으면 기본값 반환 (fallback)
|
|
return {
|
|
translations: {},
|
|
loading: false,
|
|
getTranslatedText: (_, fallback) => fallback,
|
|
};
|
|
}
|
|
return context;
|
|
};
|
|
|