Merge commit '7e987212288688a9fae7d1ff18f6e315c5a08d94' into feature/20260130_cl_SWV-811

This commit is contained in:
clkim
2026-01-13 15:52:11 +09:00
10 changed files with 92 additions and 218 deletions

View File

@@ -1,6 +1,6 @@
<template>
<header class="header">
<BlocksStoveGnbNew class="min-h-[48px]" />
<BlocksStoveGnb class="min-h-[48px]" />
</header>
<section class="inspection-section">
<clientOnly>

View File

@@ -1,7 +1,6 @@
import type { LocaleObject, NuxtI18nOptions } from '@nuxtjs/i18n'
// const LANG_DIR: string = './i18n/locales'
const LANG_DIR: string = '../i18n/locales'
const DEFAULT_COVERAGES: string[] = ['ko', 'en', 'ja', 'zh-tw', 'zh-cn', 'th']
const DEFAULT_LOCALES: Record<string, LocaleObject> = {
ko: { code: 'ko', name: '한국어', iso: 'ko-KR', dir: 'ltr' },
@@ -40,12 +39,10 @@ const getI18n = (allowedLangCodes?: string[]): NuxtI18nOptions => {
defaultLocale: DEFAULT_LOCALE_CODE,
detectBrowserLanguage: {
fallbackLocale: DEFAULT_LOCALE_CODE,
useCookie: true,
cookieKey: 'LOCALE',
cookieDomain: process.env.BASE_DOMAIN,
useCookie: false,
redirectOn: 'root',
},
langDir: '../i18n/locales',
langDir: LANG_DIR,
compilation: {
strictMessage: false,
escapeHtml: false,

View File

@@ -1,72 +1,66 @@
<script setup lang="ts">
import { useGameDataStore } from '#layers/stores/useGameDataStore'
let cpHeader: any = null
const runtimeConfig = useRuntimeConfig()
const { locale, availableLocales } = useI18n()
const gameDataStore = useGameDataStore()
const { gameData } = storeToRefs(gameDataStore)
const stoveInflowPath = runtimeConfig.public.stoveInflowPath
const stoveGameNo = runtimeConfig.public.stoveGameNo
const stoveGnbData = gameData.value?.stove_gnb_json
const languageCodes = computed(() => {
if (Array.isArray(availableLocales)) {
return availableLocales.map(
(localeCode: any) => localeCode.code ?? localeCode
)
}
return [locale]
})
const loadGnb = (locale: string) => {
locale = locale.toLowerCase()
const gnbOption = {
wrapper: '#stove-wrap',
isResponsive: true,
skin: 'gnb-dark-mini',
widget: {
gameListAndService: false,
languageSelect: false,
notification: stoveGnbData?.notify_icon_visible ?? true,
stoveDownload: false,
},
global: {
userGds: true,
defaultSelectedLanguage: locale ?? 'en',
languageCoverages: languageCodes.value,
},
loginMethod: {
params: {
inflow_path: stoveInflowPath,
game_no: stoveGameNo,
show_play_button: stoveGnbData?.stove_install_button_visible ?? 'Y',
},
redirectCurrentPage: true,
windowTitle: undefined,
},
}
cpHeader = new (window as any).cp.Header(gnbOption)
cpHeader.render()
}
let mountedInstance: any = null
onMounted(() => {
loadGnb(locale.value)
const gameDataStore = useGameDataStore()
const { gameData } = storeToRefs(gameDataStore)
const langCodes = gameData.value?.lang_codes
const defaultLangCode = gameData.value?.default_lang_code
const stoveGnbData = gameData.value?.stove_gnb_json
const designTheme = gameData.value?.design_theme
const currentDomain =
window.location.protocol + '//' + window.location.hostname
if (typeof window !== 'undefined' && (window as any).StoveGnb) {
const stoveGnbOptions = {
logArea: currentDomain,
useLanguageCodeFromPath: true,
serviceTitle: {
pc: '',
mobile: '',
},
widget: {
notification: stoveGnbData?.notify_icon_visible ?? true,
stoveDownload: stoveGnbData?.stove_install_button_visible ?? true,
languageSelect: false,
themeSelect: false,
stoveMenu: {
active: false,
mobile: true,
},
},
global: {
languageCoverages: langCodes,
defaultSelectedLanguage: defaultLangCode ?? 'ko',
},
loginMethod: {
redirectCurrentPage: true,
},
mode: {
theme: {
support: designTheme === 1 ? ['light'] : ['dark'],
default: designTheme === 1 ? 'light' : 'dark',
},
mini: true,
layout: 'wide',
fixed: false,
},
}
mountedInstance = (window as any).StoveGnb.mount(
'#stove-wrap',
stoveGnbOptions
)
}
})
onBeforeUnmount(() => {
if (cpHeader && typeof cpHeader.destroy === 'function') {
cpHeader.destroy()
if (mountedInstance && typeof mountedInstance.destroy === 'function') {
mountedInstance.destroy()
}
cpHeader = null
mountedInstance = null
})
</script>
<template>
<div id="stove-wrap" class="relative z-[5]" />
<div id="stove-wrap" class="relative h-[48px] z-[5]" />
</template>

View File

@@ -1,79 +0,0 @@
<script setup lang="ts">
let mountedInstance: any = null
const runtimeConfig = useRuntimeConfig()
const baseDomain = `${runtimeConfig.public.baseDomain}`
onMounted(() => {
const gameDataStore = useGameDataStore()
const { gameData } = storeToRefs(gameDataStore)
const langCodes = gameData.value?.lang_codes
const defaultLangCode = gameData.value?.default_lang_code
const stoveGnbData = gameData.value?.stove_gnb_json
const designTheme = gameData.value?.design_theme
const currentDomain =
window.location.protocol + '//' + window.location.hostname
if (typeof window !== 'undefined' && (window as any).StoveGnb) {
const stoveGnbOptions = {
logArea: currentDomain,
useLanguageCodeFromPath: false,
serviceTitle: {
pc: '',
mobile: '',
},
widget: {
notification: stoveGnbData?.notify_icon_visible ?? true,
stoveDownload: stoveGnbData?.stove_install_button_visible ?? true,
languageSelect: false,
themeSelect: false,
stoveMenu: {
active: false,
mobile: true,
},
},
global: {
languageCoverages: langCodes,
defaultSelectedLanguage: defaultLangCode ?? 'en',
},
loginMethod: {
redirectCurrentPage: true,
},
mode: {
theme: {
support: designTheme === 1 ? ['light'] : ['dark'],
default: designTheme === 1 ? 'light' : 'dark',
},
mini: true,
layout: 'wide',
fixed: false,
},
}
mountedInstance = (window as any).StoveGnb.mount(
'#stove-wrap',
stoveGnbOptions
)
}
if (mountedInstance) {
//Stove GNB에서도 쿠키를 굽고 있어 소문자로 통일
//LOCALE 쿠키를 가져온 후 소문자로 변경해서 다시 LOCALE 쿠키를 설정
nextTick(() => {
const localeCookie = useCookie('LOCALE', {
domain: baseDomain,
path: '/',
maxAge: 60 * 60 * 24 * 365, // 1년 (초 단위)
})
localeCookie.value = localeCookie.value.toLowerCase()
})
}
})
onBeforeUnmount(() => {
if (mountedInstance && typeof mountedInstance.destroy === 'function') {
mountedInstance.destroy()
}
mountedInstance = null
})
</script>
<template>
<div id="stove-wrap" class="relative h-[48px] z-[5]" />
</template>

View File

@@ -180,7 +180,7 @@ onMounted(() => {
<template>
<header :class="['header', { 'empty-game': !gnbData }]">
<BlocksStoveGnbNew class="h-[48px]" />
<BlocksStoveGnb class="h-[48px]" />
<div
v-if="gnbData"
:class="['game-wrap', { 'is-fixed': isPassedStoveGnb }]"

View File

@@ -2,7 +2,7 @@
<template>
<header class="header">
<BlocksStoveGnbNew class="min-h-[48px]" />
<BlocksStoveGnb class="min-h-[48px]" />
</header>
</template>

View File

@@ -3,11 +3,11 @@ import { useTokenValidation } from '#layers/composables/useTokenValidation'
import { csrGoStoveLogin } from '#layers/utils/stoveUtil'
export const useCheckGameStart = () => {
const { tm } = useI18n()
const runtimeConfig = useRuntimeConfig()
const gameDataStore = useGameDataStore()
const modalStore = useModalStore()
const { handleTokenValidation } = useTokenValidation()
const { tm, locale } = useI18n()
const { gameData } = storeToRefs(gameDataStore)
@@ -21,6 +21,11 @@ export const useCheckGameStart = () => {
// 에러 처리
const errorHandler = (errorCode: number) => {
switch (errorCode) {
case -100: // Window OS에서만 실행 가능
modalStore.handleOpenAlert({
contentText: tm('Alert_Client_Window'),
})
break
case 601: // PC 클라이언트 미설치
break
case 40101: // 로그인 정보 확인 중 오류가 발생했습니다. 재로그인 후 다시 이용해 주세요.
@@ -117,7 +122,7 @@ export const useCheckGameStart = () => {
const accessTokenSub = csrGetAccessToken()
const stoveGameId = gameData.value?.game_id || ''
const nationCookie = useCookie('NNTO').value
const localeCookie = useCookie('LOCALE').value
const localeCode = locale.value.toUpperCase() || 'KO'
window.stoveJsService = window.stoveJsService || {}
@@ -138,7 +143,7 @@ export const useCheckGameStart = () => {
.run({
gameId: stoveGameId,
nation: nationCookie,
lang: localeCookie,
lang: localeCode,
isSkipMaintenance: true,
})
.then(() => {
@@ -166,9 +171,7 @@ export const useCheckGameStart = () => {
const isWindowsOS = checkWindowsOS()
if (!isWindowsOS) {
modalStore.handleOpenAlert({
contentText: tm('Alert_Client_Window'),
})
errorHandler(-100)
return
}

View File

@@ -19,12 +19,7 @@ export default defineNuxtRouteMiddleware(async to => {
// const stoveMaintenanceApiUrl = `${runtimeConfig.public.stoveMaintenanceApiUrl}`
const stoveGameId = gameData.value.game_id
/* const localeCookie = useCookie('LOCALE', {
domain: baseDomain
}) */
const finalLocale = csrGetFinalLocale(to.path, gameData.value.lang_codes)
// localeCookie.value = finalLocale.toUpperCase()
// 웹 점검 -----
const { isWebInspection, getInspectionDataExternal } =

View File

@@ -1,5 +1,5 @@
import { LRUCache } from 'lru-cache'
import { defineEventHandler, createError, setCookie, type H3Event } from 'h3'
import { defineEventHandler, createError, type H3Event } from 'h3'
import {
getGameDomain,
getPathLocale,
@@ -71,25 +71,6 @@ const cache = new LRUCache<string, WebInspectionData>({
ttl: 1000 * 30, // 30초 동안 캐시 유지
})
/**
* 최종 언어 쿠키 세팅
*
* @param event - 이벤트 객체
* @param finalLocale - 최종 언어
* @param baseDomain - 기본 도메인
*/
function setFinalLocaleCookie(
event: H3Event,
finalLocale: string,
baseDomain: string
) {
setCookie(event, 'LOCALE', finalLocale.toLowerCase(), {
domain: baseDomain,
path: '/',
maxAge: 60 * 60 * 24 * 365, // 1년 (초 단위)
})
}
/**
* Locale Middleware 역할 함수
*
@@ -201,20 +182,7 @@ export default defineEventHandler(async event => {
// 1-1. 정적 파일 패스
if (isStaticFile(event.path)) return
// 1-2. /inspection 패스
if (fullPath.includes('/inspection')) {
// 리턴 되기 전 언어 쿠키 세팅
const finalLocale = ssrGetFinalLocale(
event?.node.req.url,
event.node.req.headers,
gameDataLangCodes,
gameDataDefaultLocale
)
setFinalLocaleCookie(event, finalLocale, baseDomain)
return
}
// 1-3. 특정 경로 패스 (API, 리소스)
// 1-2. 특정 경로 패스 (API, 리소스)
if (shouldSkipPath(fullPath)) return
// 캐시 키 생성 (게임 ID 포함하여 충돌 방지)
@@ -229,7 +197,6 @@ export default defineEventHandler(async event => {
gameDataLangCodes,
gameDataDefaultLocale
)
setFinalLocaleCookie(event, finalLocale, baseDomain)
// 초기화
let inspectionData

View File

@@ -38,15 +38,6 @@ export const csrGetFinalLocale = (path = '', coveragesLocales: string[]) => {
let finalLocale = DEFAULT_LOCALE_CODE // 기본값 설정
// coveragesLocales가 빈 배열이거나 유효하지 않은 경우 기본 언어 반환
if (
!coveragesLocales ||
!Array.isArray(coveragesLocales) ||
coveragesLocales.length === 0
) {
return finalLocale
}
// 1. URL 패스에 포함된 언어
if (path && path !== '' && path.split('/').length > 1) {
// 쿼리스트링 제거한 순수 path 검사
@@ -56,7 +47,11 @@ export const csrGetFinalLocale = (path = '', coveragesLocales: string[]) => {
const pathLocale = `${path.split('/')[1]}`.toLowerCase()
// URL 패스에 포함된 언어가 지원하는 언어인지 체크
if (pathLocale && pathLocale !== '') {
if (
pathLocale &&
pathLocale !== '' &&
coveragesLocales.includes(pathLocale)
) {
finalLocale = pathLocale
return finalLocale
}
@@ -66,23 +61,25 @@ export const csrGetFinalLocale = (path = '', coveragesLocales: string[]) => {
// 2. LOCALE 쿠키 언어
const cookieLanguage =
`${useCookie('LOCALE', { domain: baseDomain }).value}`.toLowerCase()
if (cookieLanguage && cookieLanguage !== '') {
if (
cookieLanguage &&
cookieLanguage !== '' &&
coveragesLocales.includes(cookieLanguage)
) {
finalLocale = cookieLanguage
return finalLocale
}
// 3. 브라우저 언어
if (import.meta.client) {
const browserLanguage =
`${navigator.language || navigator.languages[0]}`.toLowerCase()
if (
browserLanguage &&
browserLanguage !== '' &&
coveragesLocales.includes(browserLanguage)
) {
finalLocale = browserLanguage
return finalLocale
}
const browserLanguage =
`${navigator.language || navigator.languages[0]}`.toLowerCase()
if (
browserLanguage &&
browserLanguage !== '' &&
coveragesLocales.includes(browserLanguage)
) {
finalLocale = browserLanguage
return finalLocale
}
// 3. 서비스 기본 언어
@@ -98,7 +95,7 @@ export const csrGetFinalLocale = (path = '', coveragesLocales: string[]) => {
* @param {any} headers - 요청 헤더
*/
export const ssrGetFinalLocale = (
path,
path = '',
headers: any,
coveragesLocales: string[],
defaultLocale: string