[vue3] 다국어 적용

depdep·2024년 3월 20일
1

vue

목록 보기
2/3

설치

  • 설치 모듈로 이동
// 이동
$ cd (프로젝트명 or 모듈명)/

// 설치
$ npm i vue-i18n

언어 파일 생성

  • src/locale 안에 나라별 언어 json 파일로 생성
    -> locale 폴더 생성
  • 샘플 -> 1.메뉴별, 2.용도로 분리
// ko.json
{
  "common": {
    "text": {
      "title": "제목",
      "subTitle": "제목 - {0}"
    },
    "button": {
      "search": "검색",
      "save": "저장",
      "update": "수정",
      "delete": "삭제"
    }
  },
  "menu1": {
    "text": {
      "title": "메뉴1",
      "subTitle": "메뉴1 - {0}"
    },
    "button": {
      "search": "메뉴1 검색"
    }
  }
}

// en.json
{
  "common": {
    "text": {
      "title": "title",
      "subTitle": "title - {0}"
    },
    "button": {
      "search": "search",
      "save": "save",
      "update": "update",
      "delete": "delete"
    }
  },
  "menu1": {
    "text": {
      "title": "menu1",
      "subTitle": "menu1 - {0}"
    },
    "button": {
      "search": "menu1 search"
    }
  }
}

main.js

  • 플러그인 등록
  • i18n 생성 파일 분리
    -> 동일한 인스턴스로 js 파일에서 사용하기 위해
// i18n.js ===
import { createI18n } from 'vue-i18n';
import enUS from "@/locales/en.json";
import koKR from "@/locales/ko.json";

const i18n = createI18n({
    // options
    locale: 'ko',
    fallbackLocale: 'ko', // 다국어 작동안될 시 사용 언어
    legacy: false, // script에서 사용할 경우 false
    messages: {
        en: enUS,
        ko: koKR
    }
});

export default i18n;


// main.js ===
import i18n from "@/utils/i18n"

const app = createApp(App)

// 등록
app.use(i18n)

app.mount('#app')

컴포넌트 사용

// script 사용시
import { useI18n } from 'vue-i18n';

const { t } = useI18n();

// 템플릿 변수가 배열인 경우 -> vue-i18n 9.x 버전 -> 배열입력
let str = t('common.text.subTitle',['굿'])

// 템플릿 변수가 오브젝트인 경우 -> vue-i18n 8.x 이하 버전 -> 문자열 변수와 동일하게 입력
let str = t('common.text.subTitle',{0:'굿'})

// template 사용시
<button>{{ $t('common.button.search') }}</button>

// plain js 사용시
import i18n from "@/utils/i18n"

// vue3 기준 legacy 가 false인 경우
i18n.global.t('common.text.subTitle',['굿'])

// vue3 기준 legacy 가 true인 경우
i18n.t('common.text.subTitle',['굿'])

언어 변경

  • locale은 반응성(reactive)을 가지고있어 locale.value로 변경 해줘야함
  • v-model 양방향 바인딩도 가능
import { useI18n } from 'vue-i18n';

const { t, locale } = useI18n();

// 직접 변경
locale.value = 'en'

// v-model
<select v-model="locale">
  <option value="ko">한국어</option>
  <option value="en">영어</option>
</select>

날짜 포맷

  • dayjs 사용
// 설치
$ npm install dayjs
  • 공통 함수로 사용
// common.js === 
import i18n from "@/utils/i18n"
import dayjs from 'dayjs'

fnLocaleFormatDate(date, type) {

  const locale = i18n.global.locale.value;

  const formatMap = {
    'short': {
      'ko': 'YYYY-MM-DD',
      'en': 'MMM D, YYYY'
    },
    'long': {
      'ko': 'YYYY-MM-DD HH:mm:ss',
      'en': 'MMM D, YYYY h:mm A'
    }
  };

  const formatType = formatMap[type] || formatMap['short'];
  const format = formatType[locale] || 'YYYY-MM-DD';
  return dayjs(date).format(format);
}

// 컴포넌트 ===
import {Common} from "@/utils/common";

// 타입 : short, long
Common.fnLocaleFormatDate('2022-12-31 12:00:00', 'short')

언어 변경에 따른 전역 변수 변경

  • 쿼리스트링(lang) 변경시 언어 변경
  • 라우터가 준비된 후에 앱을 마운트
// main.js ===
router.isReady().then(() => {
    langUrlSwitcher(app)
    app.mount('#app')
})

// langUrlSwitcher.js ===
import {ref, watch} from 'vue'
import i18n from './i18n.js'
import router from "@/router";

const urlKo = 'ko url'
const urlEn = 'en url'
const url = ref(urlKo)

// 언어 및 언어별 url 변경
const switchLang = (lang = 'ko') => {
    i18n.global.locale.value = lang
    switch (lang) {
        case 'ko':
            url.value = urlKo
            break
        case 'en':
            url.value = urlEn
            break
    }
}

// 쿼리스트링에서 lang 값을 추출하고 switchLang 함수를 호출
const handleQueryStringChange = (newQuery) => {
    console.log('Query string has changed')
    const lang = newQuery.lang
    switchLang(lang)
}

// 언어별 url provide (router.isReady() 이후 진행)
export function langUrlSwitcher(app) {
    const lang = router.currentRoute.value.query.lang
    switchLang(lang)

    // URL 전역 등록
    app.provide('url', url)

  	// 쿼리 스트링 변경 체크
    watch(() => router.currentRoute.value.query, handleQueryStringChange)
}
profile
depdepdepdepdepdepdepdepdepdepdepdep

0개의 댓글