Nuxt 3 프로젝트에서 URL을 통한 다국어 설정하기

MochaChoco·2023년 10월 19일
0
post-thumbnail

서론

이전 포스트 [Nuxt 3 프로젝트에서 서브도메인 처리하기]에서 서브도메인을 처리하는 방법을 작성했다. 이번 포스트에서는 이 코드를 기반으로 url로 다국어 처리를 하는 방법을 작성하고자 한다.

다국어 프레임워크 중에서 가장 압도적으로 많이 사용되는 것이 i18n 라이브러리다. i18n은 React, Vue, Angula 뿐만 아니라 Android, IOS, PHP까지도 지원한다. 다만, 동시에 여러 프레임워크들을 지원하다보니 각각의 업데이트가 조금 느린 편이다.
예를 들어, Nuxt의 i18n은 최신 버전에서 Nuxt 3를 지원하지만, 정식 릴리즈된 버전은 아직까지 Nuxt 2만 지원하는 상태이다. 심지어 마지막 업데이트 날짜도 9개월 전이라 그대로 쓰는건 리스크가 있다고 판단했다.

그래서 고민한 결과, 이번 프로젝트에서는 비교적 업데이트가 빠른 vue-i18n를 이용하여 다국어를 진행하기로 결정했다. 실제로 nuxtjs/i18n도 vue-i18n을 기반으로 제작되는 것이라 적용에 큰 문제가 없었다.

설정 방법

Nuxt 3는 이전 포스트에서 언급했듯이 파일 시스템 라우팅을 지원한다. 단순히 라우팅 뿐만 아니라 Vue용 플러그인도 별도의 설정없이 손쉽게 불러올 수 있다. 라우팅은 pages 폴더를 기반으로 자동 생성되었다면, 플러그인은 plugins 폴더의 파일들이 자동으로 등록이 된다.

프로젝트의 root에 plugins 폴더를 만들고 안에 i18n.ts 파일을 아래의 코드처럼 작성한다.

//  plugins/i18n.ts
import { createI18n } from 'vue-i18n'; 

export default defineNuxtPlugin((nuxtApp) => {
  const i18n = createI18n({
    locale: 'ko',
    legacy: false, // Composition API에서 사용하기 위해선 false 값을 주어야함
    messages: {
      ko: {
        index: "메인 페이지",
        detail: "상세 페이지",
        go: "상세 페이지로 이동",
        back: "뒤로 가기",
        error: "에러",
      },
      en: {
        index: "main page",
        detail: "detail page",
        go: "go to detail page",
        back: "go back",
        error: "error",
      },
    },
  });

  nuxtApp.vueApp.use(i18n);
  nuxtApp.provide('i18n', i18n);	// 다른 plugin에서 사용하기 위함
});

한글일 경우, locale값은 'ko', 영문일 경우 locale값은 'en'이다. 이번 프로젝트는 기본 locale 값을 'ko'로 지정해줄 것이다. legacy는 Nuxt3의 Composition API에서 사용하기 위한 옵션이다. 기존처럼 Options API를 사용한다면 true로 줘도 무방하다. messages는 실제로 번역될 데이터들이 담길 부분이다. 이번 프로젝트는 한글, 영어를 지원할 것이므로, 번역할 'ko', 'en' 값을 넣어준다.

// app/router.options.ts
if (routesDirectory) {
  newRoutes = _routes
    .filter((route: any) => {
    // routesDirectory가 pc면 pc 경로만, mobile이면 mobile 경로만 가져옴
    return checkIsUnderDirectory(route.path, routesDirectory);
  })
    .map((route: any) => {
    // 접근가능한 route 경로 재설정
    return {
      ...route,
      path:
      "/:locale(en|)?" +
      route.path.substr(routesDirectory.length + 1) || "/",
      name: route.name || "index",
    };
  });

  // console.log("_routes", _routes);
  // console.log("newRoutes", newRoutes);
  return newRoutes;
}

대부분 사이트가 default locale일 경우 url에서 언어값이 생략되는 경우가 많으므로, locale값이 'ko' 일때 '/detail', 'en'일때 /en/detail과 같은 형식으로 url이 나타나야 한다. 따라서 라우터 옵션을 수정해야 하는데, 기존에 생성한 app/router.options.ts 파일에서 route를 리턴하는 부분의 path 값에 '/:locale(en|)?'를 추가한다. 저것은 path prefix(접두사)를 'en' 아니면 값을 생략하겠다는 뜻이다. 이외의 값을 입력하면 Nuxt 라우터에서 404 에러를 반환한다.

또한 입력받은 url의 locale값에 따라 i18n의 locale 값도 바꿔주는 과정도 필요한데 plugins/route.ts 파일을 만들고 아래처럼 작성한다.

// plugins/route.ts
import { useRouter } from "vue-router";

export default defineNuxtPlugin((nuxtApp) => {
  const router = useRouter();
  router.beforeEach(async (to, from) => {
    // url에서 locale 읽어서 설정함
    let locale = to.params.locale;
    if (!locale) {
      locale = "ko";
    }
 
    nuxtApp.$i18n.global.locale.value = locale;
  });
});

위의 코드는 router의 navigation이 트리거되면 동작한다. 다시 말해 주소가 변경되기 전에 호출되는 코드이다. 주소창에서 입력받은 url의 locale값을 확인한 후, router.options.ts에서 provide 처리한 i18n에 입력받은 locale값을 집어넣어야 locale에 따른 언어가 정상적으로 출력된다.

//pages/pc/index.vue
<script setup lang="ts">
import { useI18n } from "vue-i18n";

const { t } = useI18n();
</script>

<template>
  <div>
    <p>{{ t("title") }}</p>
  </div>
</template>

결과 확인

다국어를 출력할 페이지 파일을 만들고 주소창에 아래와 같이 주소를 입력해보면 다음과 같은 결과가 나타난다.

  1. http://localhost:3000/ --> 메인 페이지
  2. http://localhost:3000/en --> main page
  3. http://localhost:3000/fr --> 404 에러

도메인 뒤에 locale값이 붙으면 해당 locale에 따라 잘 출력되는 것을 볼 수 있다.

※ 유의사항

해당 방법을 사용하면 주소창에 url을 직접 입력했을때만 locale 변경이 잘 되고, NuxtLink 컴포넌트나 router.push 함수를 사용하여 페이지를 이동할때 locale값이 제대로 변경되지 않을 것이다.

<NuxtLink
	:to="{
      path: '/detail',
      params: { locale: 'en' },
    }"
>detail 페이지로 이동</NuxtLink>

그 예시로, 위의 버튼을 누르면 locale값이 'en'인 상세 페이지로 이동할 것 같지만, 실제로는 locale값이 'ko'인 상세 페이지로 이동된다. 그와 동시에 콘솔에서도 아래와 같은 경고문이 출력된다.

Vue router 공식 문서를 찾아보니 path 대신에 name을 사용하라는 것이었다.

 <NuxtLink
    :to="{
      name: 'pc-detail',
      params: { locale: 'en' },
    }"
    >detail 페이지로 이동</NuxtLink
  >

그래서 코드를 다음과 같이 고치니 locale이 유지되면서 정상적으로 경로가 변경되었다.

샘플코드

git 저장소 이동 (https://github.com/MochaChoco/locale-test)

참고자료

Vue I18n 공식 문서
Named Routes | Vue Router

profile
길고 가늘게

0개의 댓글