Files
vexplor/frontend/hooks/useMultiLang.ts

155 lines
5.0 KiB
TypeScript

import { useState, useEffect } from "react";
import { apiClient } from "@/lib/api/client";
// 전역 언어 상태 (다른 컴포넌트에서 접근 가능)
let globalUserLang = "KR";
let globalChangeLangCallback: ((lang: string) => void) | null = null;
export const useMultiLang = (options: { companyCode?: string } = {}) => {
const [userLang, setUserLang] = useState<string>("KR");
const companyCode = options.companyCode || "*";
// 전역 언어 상태 동기화
useEffect(() => {
if (globalUserLang !== userLang) {
setUserLang(globalUserLang);
}
}, [globalUserLang]);
// 언어 변경 시 전역 콜백 호출
useEffect(() => {
if (globalChangeLangCallback) {
globalChangeLangCallback(userLang);
}
}, [userLang]);
// 사용자 로케일 조회 (한 번만 실행)
useEffect(() => {
// 이미 로케일이 설정되어 있으면 중복 호출 방지
if (globalUserLang && globalUserLang !== "KR") {
setUserLang(globalUserLang);
return;
}
const fetchUserLocale = async () => {
try {
console.log("🔍 사용자 로케일 조회 시작");
const response = await apiClient.get("/admin/user-locale");
if (response.data.success && response.data.data) {
const userLocale = response.data.data;
console.log("✅ 사용자 로케일 조회 성공:", userLocale);
// 데이터베이스의 locale 값을 그대로 사용 (매핑 없음)
setUserLang(userLocale);
globalUserLang = userLocale; // 전역 상태도 업데이트
return;
}
// API 호출 실패 시 브라우저 언어 사용
console.warn("⚠️ 사용자 로케일 조회 실패, 브라우저 언어 사용");
const browserLang = navigator.language.split("-")[0];
// 브라우저 언어를 그대로 사용 (매핑 없음)
if (["ko", "en", "ja", "zh"].includes(browserLang)) {
setUserLang(browserLang);
globalUserLang = browserLang;
}
} catch (error) {
console.error("❌ 사용자 로케일 조회 중 오류:", error);
// 오류 시 브라우저 언어 사용
const browserLang = navigator.language.split("-")[0];
// 브라우저 언어를 그대로 사용 (매핑 없음)
if (["ko", "en", "ja", "zh"].includes(browserLang)) {
setUserLang(browserLang);
globalUserLang = browserLang;
}
}
};
fetchUserLocale();
}, []);
// 다국어 텍스트 가져오기 (배치 조회 방식)
const getText = async (menuCode: string, langKey: string, fallback?: string): Promise<string> => {
console.log(`🔍 다국어 텍스트 요청 (배치 방식):`, { menuCode, langKey, userLang, companyCode });
try {
// 배치 조회 API 사용
const response = await apiClient.post(
"/multilang/batch",
{
langKeys: [langKey],
},
{
params: {
companyCode,
menuCode,
userLang,
},
},
);
console.log(`📡 배치 API 응답 상태:`, response.status, response.statusText);
if (response.data.success && response.data.data && response.data.data[langKey]) {
// 번역 텍스트를 캐시에 저장
const cacheKey = `${menuCode}.${langKey}`;
const currentCache = (window as any).__TRANSLATION_CACHE || {};
currentCache[cacheKey] = response.data.data[langKey];
(window as any).__TRANSLATION_CACHE = currentCache;
return response.data.data[langKey];
}
// 실패 시 fallback 또는 키 반환
console.log(`🔄 배치 API 성공했지만 데이터 없음, fallback 반환:`, fallback || langKey);
return fallback || langKey;
} catch (error) {
console.error("❌ 다국어 텍스트 배치 조회 실패:", error);
console.log(`🔄 에러 시 fallback 반환:`, fallback || langKey);
return fallback || langKey;
}
};
// 언어 변경
const changeLang = async (newLang: string) => {
try {
// 백엔드에 사용자 로케일 설정 요청
const response = await apiClient.post("/admin/user-locale", {
locale: newLang,
});
if (response.data.success) {
setUserLang(newLang);
globalUserLang = newLang;
console.log("✅ 사용자 로케일 변경 성공:", newLang);
} else {
console.error("❌ 사용자 로케일 변경 실패:", response.data.message);
}
} catch (error) {
console.error("❌ 사용자 로케일 변경 중 오류:", error);
// 오류 시에도 로컬 상태는 변경
setUserLang(newLang);
globalUserLang = newLang;
}
};
// 전역 언어 상태 접근자
const getGlobalUserLang = () => globalUserLang;
const setGlobalChangeLangCallback = (callback: (lang: string) => void) => {
globalChangeLangCallback = callback;
};
return {
userLang,
getText,
changeLang,
companyCode,
getGlobalUserLang,
setGlobalChangeLangCallback,
};
};