diff --git a/app/package.json b/app/package.json index c44e96f..642ad6b 100644 --- a/app/package.json +++ b/app/package.json @@ -26,6 +26,7 @@ "socket.io-client": "^4.7.1", "validator": "^13.11.0", "vue": "^3.3.4", + "vue-i18n": "11.3.0", "vue-router": "^4.2.4", "vue-toastification": "^2.0.0-rc.5", "vue3-lottie": "^3.2.0", diff --git a/app/src/i18n/index.ts b/app/src/i18n/index.ts new file mode 100644 index 0000000..4a9cc80 --- /dev/null +++ b/app/src/i18n/index.ts @@ -0,0 +1,41 @@ +import { createI18n } from 'vue-i18n' +import en from './locales/en.json' +import zhTW from './locales/zh-TW.json' + +export const supportedLocales = ['zh-TW', 'en'] as const + +export type SupportedLocale = (typeof supportedLocales)[number] + +function isSupportedLocale(locale: string): locale is SupportedLocale { + return supportedLocales.includes(locale as SupportedLocale) +} + +function getInitialLocale(): SupportedLocale { + const savedLocale = localStorage.getItem('locale') + + if (savedLocale && isSupportedLocale(savedLocale)) { + return savedLocale + } + + return navigator.language.startsWith('zh') ? 'zh-TW' : 'en' +} + +const initialLocale = getInitialLocale() + +document.documentElement.lang = initialLocale + +export const i18n = createI18n({ + legacy: false, + locale: initialLocale, + fallbackLocale: 'zh-TW', + messages: { + 'zh-TW': zhTW, + en, + }, +}) + +export function setLocale(locale: SupportedLocale) { + i18n.global.locale.value = locale + localStorage.setItem('locale', locale) + document.documentElement.lang = locale +} diff --git a/app/src/i18n/locales/en.json b/app/src/i18n/locales/en.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/app/src/i18n/locales/en.json @@ -0,0 +1 @@ +{} diff --git a/app/src/i18n/locales/zh-TW.json b/app/src/i18n/locales/zh-TW.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/app/src/i18n/locales/zh-TW.json @@ -0,0 +1 @@ +{} diff --git a/app/src/main.ts b/app/src/main.ts index 6e918ff..a0a869d 100644 --- a/app/src/main.ts +++ b/app/src/main.ts @@ -1,18 +1,15 @@ import { createApp } from 'vue' import { createPinia } from 'pinia' - -import './style.css' -/* import font awesome icon component */ -import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' -import './library' -/* import Vue Toastification */ -import Toast, { POSITION } from 'vue-toastification' -/* import Vue Lottie */ -import Vue3Lottie from 'vue3-lottie' +import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' // import font awesome icon component +import { i18n } from './i18n' +import Toast, { POSITION } from 'vue-toastification' // import Vue Toastification +import Vue3Lottie from 'vue3-lottie' // import Vue Lottie import 'vue-toastification/dist/index.css' import App from './App.vue' import router from './router' import formbricks from './utils/formbricks' +import './style.css' +import './library' const app = createApp(App) const pinia = createPinia() @@ -21,6 +18,7 @@ app.component('font-awesome-icon', FontAwesomeIcon) app.use(pinia) app.use(router) +app.use(i18n) router.afterEach(() => { if (typeof formbricks !== 'undefined') { diff --git a/yarn.lock b/yarn.lock index ee06019..42bd41c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1306,6 +1306,36 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@intlify/core-base@11.3.0": + version "11.3.0" + resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-11.3.0.tgz#55e612501f08b564011cb16d9f4a08e9a05df3cb" + integrity sha512-NNX5jIwF4TJBe7RtSKDMOA6JD9mp2mRcBHAwt2X+Q8PvnZub0yj5YYXlFu2AcESdgQpEv/5Yx2uOCV/yh7YkZg== + dependencies: + "@intlify/devtools-types" "11.3.0" + "@intlify/message-compiler" "11.3.0" + "@intlify/shared" "11.3.0" + +"@intlify/devtools-types@11.3.0": + version "11.3.0" + resolved "https://registry.yarnpkg.com/@intlify/devtools-types/-/devtools-types-11.3.0.tgz#2670ac6a786ff56ac7b84f9af472771c7bc954fa" + integrity sha512-G9CNL4WpANWVdUjubOIIS7/D2j/0j+1KJmhBJxHilWNKr9mmt3IjFV3Hq4JoBP23uOoC5ynxz/FHZ42M+YxfGw== + dependencies: + "@intlify/core-base" "11.3.0" + "@intlify/shared" "11.3.0" + +"@intlify/message-compiler@11.3.0": + version "11.3.0" + resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-11.3.0.tgz#84c5d2af4a2119f836c5f6835b4b88e5d4076d4b" + integrity sha512-RAJp3TMsqohg/Wa7bVF3cChRhecSYBLrTCQSj7j0UtWVFLP+6iEJoE2zb7GU5fp+fmG5kCbUdzhmlAUCWXiUJw== + dependencies: + "@intlify/shared" "11.3.0" + source-map-js "^1.0.2" + +"@intlify/shared@11.3.0": + version "11.3.0" + resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-11.3.0.tgz#7abb22f05e502f3c6bf64dc771c448cdaa81d864" + integrity sha512-LC6P/uay7rXL5zZ5+5iRJfLs/iUN8apu9tm8YqQVmW3Uq3X4A0dOFUIDuAmB7gAC29wTHOS3EiN/IosNSz0eNQ== + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz" @@ -9726,6 +9756,16 @@ vue-eslint-parser@^9.4.2: lodash "^4.17.21" semver "^7.3.6" +vue-i18n@11.3.0: + version "11.3.0" + resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-11.3.0.tgz#acb92847017f90b0fd96541cb3b08fdef50dc49c" + integrity sha512-1J+xDfDJTLhDxElkd3+XUhT7FYSZd2b8pa7IRKGxhWH/8yt6PTvi3xmWhGwhYT5EaXdatui11pF2R6tL73/zPA== + dependencies: + "@intlify/core-base" "11.3.0" + "@intlify/devtools-types" "11.3.0" + "@intlify/shared" "11.3.0" + "@vue/devtools-api" "^6.5.0" + vue-router@^4.2.4: version "4.3.0" resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.3.0.tgz"