import { DEFAULT_LOCALE_CODE, ISO_LANGUAGE_CODES } from '@/i18n.config' import { csrGetFinalLocale } from '#layers/utils/localeUtil' import { parseUrl, isExternalUrl } from '#layers/utils/urlUtil' let pending: Promise | null = null export default defineNuxtRouteMiddleware(async to => { // server에서는 실행X (서버 미들웨어에서 이미 처리) ----- if (import.meta.server) return // error 페이지와 inspection 페이지는 미들웨어 실행 제외 if (to.path.includes('/error') || to.path.includes('/inspection')) { return } const gameDataStore = useGameDataStore() const { langCodes, defaultLangCode, intro, currentLangCode, gameData } = storeToRefs(gameDataStore) // 게임 데이터 스토어가 초기화되지 않았으면 대기 if (!langCodes.value || !defaultLangCode.value || !intro.value) { return } const fullPath = to.fullPath || to.path || '' // 최종 로케일 결정 const finalLocale = csrGetFinalLocale(fullPath, langCodes.value, defaultLangCode.value) || defaultLangCode.value || DEFAULT_LOCALE_CODE // parseUrl을 사용하여 최종 경로 계산 const introPageUrl = intro.value?.page_url || '' const finalPath = parseUrl( fullPath, finalLocale, langCodes.value, ISO_LANGUAGE_CODES, introPageUrl ) // 현재 경로와 최종 경로가 같으면 리다이렉트 불필요 if (fullPath.split('?')[0] === finalPath.split('?')[0]) { // gameData가 없으면(초기 진입 등) 여기서 강제 호출하지 않음 if (!gameData.value) return // 초기 hydration에서 currentLangCode가 비어있으면 현재 로케일로 동기화만 if (!currentLangCode.value) { gameDataStore.setCurrentLangCode(finalLocale) return } // 로케일이 같으면 불필요한 재호출 방지 if ( `${currentLangCode.value}`.toLowerCase() === `${finalLocale}`.toLowerCase() ) { return } // 동시에 여러 번 호출되는 것 방지 (라우트 훅/미들웨어 중복 등) if (pending) return pending const { loadGameData } = useGameDataLoader() pending = loadGameData(finalLocale).finally(() => { pending = null }) return pending } // 현재 언어 코드 설정 gameDataStore.setCurrentLangCode(finalLocale) // 외부 URL인지 확인 const isExternal = isExternalUrl(finalPath) // 리다이렉트 수행 return navigateTo(finalPath, { external: isExternal }) })