Nuxt에서 Langsys 사용하기
패턴은 어디서나 같습니다. 서버가 카탈로그를 한 번 가져오고(쓰기 키는 서버에만 보관), 클라이언트는 그 시드로 읽기 전용 키를 사용해 langsys-js-vue를 초기화합니다. 중복 요청은 없습니다. 번역 자체는 브라우저에서 이루어집니다. 서버가 보내는 HTML은 기본 언어로 되어 있고 검색 엔진도 이를 색인하며, 페이지는 로드되면서 방문자의 언어로 전환됩니다.
1 · 서버 라우트가 카탈로그를 프록시합니다
Nitro 라우트가 카탈로그를 가져오므로 쓰기 키는 비공개 런타임 설정에 그대로 보관됩니다. 브라우저는 항상 사용자의 /api 라우트와만 통신합니다. 쓰기 키는 서버에만 있고, 클라이언트는 읽기 전용 키를 받습니다. 양쪽 모두 동일한 카탈로그를 사용하며, 클라이언트는 초기 가져오기만 건너뜁니다.
// server/api/langsys.get.ts
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig();
const locale = (getQuery(event).locale as string) ?? 'en-US';
const res = await $fetch<{ data: unknown }>(
`https://api.langsys.dev/api/projects/${config.langsysProjectId}/translations`,
{ query: { locale }, headers: { 'x-Authorization': config.langsysApiKey } }
);
return { locale, translations: res.data };
}); 2 · SSR 중에 시드를 주입하고, 클라이언트에서 초기화하기
useAsyncData는 서버에서 데이터를 가져와 페이로드를 페이지에 직렬화하므로, 클라이언트는 다시 가져오지 않고 이를 바탕으로 초기화합니다. 초기화는 onMounted에서 실행됩니다. SDK는 브라우저용 SDK이며, Nuxt의 서버 쪽은 데이터만 제공합니다.
<!-- app.vue -->
<script setup lang="ts">
import { LangsysApp, createLocaleStore } from 'langsys-js-vue';
import type { iCategories } from 'langsys-js-vue';
const { data } = await useAsyncData('langsys', () =>
$fetch('/api/langsys', { query: { locale: 'en-US' } })
);
const store = createLocaleStore(data.value!.locale);
onMounted(() => {
LangsysApp.init({
projectid: useRuntimeConfig().public.langsysProjectId,
key: useRuntimeConfig().public.langsysApiKey, // read-only
UserLocaleStore: store,
initialTranslations: data.value!.translations as iCategories,
initialTranslationsLocale: data.value!.locale,
ssrTokenStrategy: 'client',
});
});
</script>
<template>
<NuxtPage />
</template> 3 · 아래 어디서나 사용하기
여기서부터는 일반 Vue SDK와 같습니다. 모든 컴포넌트에서 useT()를 사용하고, 로케일을 전환하려면 store.set()을 사용하세요. 앱이 이미 ref(Pinia, useState)에서 로케일을 관리하고 있다면, createLocaleStore로 마이그레이션하는 대신 Vue 바인딩의 refToLocaleSource로 연결하세요.
<script setup>
import { useT } from 'langsys-js-vue';
const t = useT();
</script>
<template>
<h1>{{ t('Welcome to our store', 'Home') }}</h1>
</template>