Files
2026-04-01 10:30:52 +09:00

114 lines
3.5 KiB
TypeScript

/**
* TranslationContext.tsx
*
* 컴포넌트에서 다국어 번역 기능에 접근할 수 있도록 React Context를 제공합니다.
* useTranslation 훅을 통해 컴포넌트 내부에서 직접 번역 키를 사용할 수 있습니다.
*/
import React, { createContext, useContext, useMemo } from 'react';
import { TranslationEngine, TranslationContext as ITranslationContext } from './TranslationEngine';
import { createLogger } from '../utils/Logger';
const logger = createLogger('TranslationContext');
/**
* Translation Context 값 인터페이스
*/
interface TranslationContextValue {
/** TranslationEngine 인스턴스 */
translationEngine: TranslationEngine | null;
/** 번역 컨텍스트 (templateId, locale) */
translationContext: ITranslationContext | null;
/**
* 번역 함수
* @param key 번역 키 (예: 'common.confirm')
* @param params 번역 파라미터 (예: { count: 5 })
* @returns 번역된 문자열
*/
t: (key: string, params?: Record<string, string | number>) => string;
}
/**
* React Context 생성
*/
export const TranslationReactContext = createContext<TranslationContextValue | null>(null);
/**
* TranslationProvider Props
*/
interface TranslationProviderProps {
children: React.ReactNode;
translationEngine: TranslationEngine;
translationContext: ITranslationContext;
}
/**
* TranslationProvider 컴포넌트
*
* 템플릿 엔진의 최상위에서 TranslationEngine과 TranslationContext를 제공합니다.
* 하위 컴포넌트에서 useTranslation 훅을 통해 번역 기능에 접근할 수 있습니다.
*/
export const TranslationProvider: React.FC<TranslationProviderProps> = ({
children,
translationEngine,
translationContext,
}) => {
/**
* 번역 함수 메모이제이션
*/
const t = useMemo(() => {
return (key: string, params?: Record<string, string | number>): string => {
if (params) {
// 파라미터를 TranslationEngine 형식으로 변환 (|key=value|key2=value2)
const paramsStr = '|' + Object.entries(params).map(([k, v]) => `${k}=${v}`).join('|');
return translationEngine.translate(key, translationContext, paramsStr);
}
return translationEngine.translate(key, translationContext);
};
}, [translationEngine, translationContext]);
const value = useMemo<TranslationContextValue>(() => ({
translationEngine,
translationContext,
t,
}), [translationEngine, translationContext, t]);
return (
<TranslationReactContext.Provider value={value}>
{children}
</TranslationReactContext.Provider>
);
};
/**
* useTranslation 훅
*
* 컴포넌트에서 다국어 번역 기능에 접근합니다.
*
* @example
* ```tsx
* const { t } = useTranslation();
* const confirmText = t('common.confirm');
* const message = t('admin.users.pagination_info', { from: 1, to: 10, total: 100 });
* ```
*
* @returns TranslationContextValue (t 함수 포함)
*/
export const useTranslation = (): TranslationContextValue => {
const context = useContext(TranslationReactContext);
if (!context) {
// Context 외부에서 사용 시 폴백 (키 자체 반환)
// 이 경우는 테스트 환경이나 Context 없이 컴포넌트를 단독 사용할 때 발생
logger.warn('TranslationProvider 외부에서 호출되었습니다. 키를 그대로 반환합니다.');
return {
t: (key: string) => key,
translationEngine: null,
translationContext: null,
};
}
return context;
};
export default TranslationProvider;