Features: 1) Add Pinia stores for language, company, and cart management; 2) Implement new i18n plugin with dynamic locale detection and improved setup; 3) Enhance routing logic with locale-aware redirects;
Fixes: 1) Replace usage of `vue-router` with `window.location.href` for redirects across multiple composables; 2) Ensure proper locale switching in authentication flows; Extra: 1) Update `package-lock.json` with dependencies for Apollo, Vue I18n, and styling; 2) Remove unused `i18n.config.js` to streamline i18n setup; 3) General composables refactoring to improve code maintainability;
This commit is contained in:
parent
8a8a1605ea
commit
fd8774b817
22 changed files with 1758 additions and 140 deletions
|
|
@ -1,9 +1,42 @@
|
||||||
// @ts-check
|
import node from '@astrojs/node';
|
||||||
import { defineConfig } from 'astro/config';
|
import { defineConfig } from 'astro/config';
|
||||||
|
|
||||||
import vue from '@astrojs/vue';
|
import vue from '@astrojs/vue';
|
||||||
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [vue()]
|
integrations: [
|
||||||
|
vue({
|
||||||
|
appEntrypoint: '/src/plugins/index.js',
|
||||||
|
devtools: { launchEditor: "webstorm" }
|
||||||
|
})
|
||||||
|
],
|
||||||
|
output: 'server',
|
||||||
|
adapter: node({
|
||||||
|
mode: 'standalone'
|
||||||
|
}),
|
||||||
|
vite: {
|
||||||
|
envDir: '../',
|
||||||
|
envPrefix: 'EVIBES_',
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||||
|
'@core': fileURLToPath(new URL('./src/core', import.meta.url)),
|
||||||
|
'@graphql': fileURLToPath(new URL('./src/graphql', import.meta.url)),
|
||||||
|
'@styles': fileURLToPath(new URL('./src/assets/styles', import.meta.url)),
|
||||||
|
'@icons': fileURLToPath(new URL('./src/assets/icons', import.meta.url)),
|
||||||
|
'@images': fileURLToPath(new URL('./src/assets/images', import.meta.url)),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
preprocessorOptions: {
|
||||||
|
scss: {
|
||||||
|
additionalData: `
|
||||||
|
@use "@/assets/styles/global/variables.scss" as *;
|
||||||
|
@use "@/assets/styles/global/mixins.scss" as *;
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
});
|
});
|
||||||
1438
storefront/package-lock.json
generated
1438
storefront/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "evibes",
|
"name": "evibes-storefront",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
@ -9,8 +9,24 @@
|
||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@apollo/client": "^3.13.8",
|
||||||
|
"@astrojs/node": "^9.2.2",
|
||||||
"@astrojs/vue": "^5.1.0",
|
"@astrojs/vue": "^5.1.0",
|
||||||
|
"@vue/apollo-composable": "^4.2.2",
|
||||||
|
"@vueuse/core": "^13.2.0",
|
||||||
"astro": "^5.8.1",
|
"astro": "^5.8.1",
|
||||||
"vue": "^3.5.16"
|
"element-plus": "^2.9.11",
|
||||||
|
"graphql": "^16.11.0",
|
||||||
|
"graphql-tag": "^2.12.6",
|
||||||
|
"pinia": "^3.0.1",
|
||||||
|
"primeicons": "^7.0.0",
|
||||||
|
"swiper": "^11.2.8",
|
||||||
|
"vue": "^3.5.16",
|
||||||
|
"vue-i18n": "^11.1.4",
|
||||||
|
"vue3-marquee-slider": "^1.0.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"sass": "^1.83.0",
|
||||||
|
"sass-loader": "^16.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,8 @@
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import HeaderSearchSkeleton from "@/components/skeletons/header/header-search-skeleton.vue";
|
import HeaderSearchSkeleton from "@/components/skeletons/header/header-search-skeleton.vue";
|
||||||
import { useSearchUI } from "@/composables/search";
|
import { useSearchUI } from "@/composables/search";
|
||||||
import {useRouter} from "vue-router";
|
|
||||||
|
|
||||||
const {t} = useI18n();
|
const {t} = useI18n();
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
query,
|
query,
|
||||||
|
|
@ -83,10 +81,7 @@ const {
|
||||||
|
|
||||||
function submitSearch() {
|
function submitSearch() {
|
||||||
if (query.value) {
|
if (query.value) {
|
||||||
router.push({
|
window.location.href = `/search?q=${encodeURIComponent(query.value)}`;
|
||||||
name: 'search',
|
|
||||||
query: { q: query.value }
|
|
||||||
});
|
|
||||||
|
|
||||||
toggleSearch(false);
|
toggleSearch(false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,10 @@ import {
|
||||||
LOCALE_STORAGE_LOCALE_KEY,
|
LOCALE_STORAGE_LOCALE_KEY,
|
||||||
LOCALE_STORAGE_REFRESH_TOKEN_KEY,
|
LOCALE_STORAGE_REFRESH_TOKEN_KEY,
|
||||||
} from "@/config/index.js";
|
} from "@/config/index.js";
|
||||||
import {useRoute, useRouter} from "vue-router";
|
|
||||||
import {usePendingOrder} from "@/composables/orders";
|
import {usePendingOrder} from "@/composables/orders";
|
||||||
import {useWishlist} from "@/composables/wishlist";
|
import {useWishlist} from "@/composables/wishlist";
|
||||||
|
|
||||||
export function useLogin() {
|
export function useLogin() {
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const {t} = useI18n();
|
const {t} = useI18n();
|
||||||
|
|
||||||
|
|
@ -55,19 +52,17 @@ export function useLogin() {
|
||||||
type: 'success'
|
type: 'success'
|
||||||
})
|
})
|
||||||
|
|
||||||
await router.push({
|
let locale = localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY) || DEFAULT_LOCALE;
|
||||||
name: 'home',
|
|
||||||
params: {
|
|
||||||
locale: localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY) || DEFAULT_LOCALE
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (response.data.obtainJwtToken.user.language !== translations.currentLocale) {
|
if (response.data.obtainJwtToken.user.language !== translations.currentLocale) {
|
||||||
translations.switchLanguage(response.data.obtainJwtToken.user.language, router, route)
|
translations.switchLanguage(response.data.obtainJwtToken.user.language);
|
||||||
|
locale = response.data.obtainJwtToken.user.language;
|
||||||
}
|
}
|
||||||
|
|
||||||
await getPendingOrder(response.data.obtainJwtToken.user.email);
|
await getPendingOrder(response.data.obtainJwtToken.user.email);
|
||||||
await getWishlist();
|
await getWishlist();
|
||||||
|
|
||||||
|
window.location.href = `/${locale}/`;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("useLogin error:", error);
|
console.error("useLogin error:", error);
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,9 @@ import {
|
||||||
LOCALE_STORAGE_LOCALE_KEY,
|
LOCALE_STORAGE_LOCALE_KEY,
|
||||||
LOCALE_STORAGE_REFRESH_TOKEN_KEY
|
LOCALE_STORAGE_REFRESH_TOKEN_KEY
|
||||||
} from "@/config/index.js";
|
} from "@/config/index.js";
|
||||||
import {useRouter} from "vue-router";
|
|
||||||
|
|
||||||
export function useLogout() {
|
export function useLogout() {
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
async function logout() {
|
async function logout() {
|
||||||
userStore.setUser({
|
userStore.setUser({
|
||||||
|
|
@ -19,12 +17,9 @@ export function useLogout() {
|
||||||
localStorage.removeItem(LOCALE_STORAGE_REFRESH_TOKEN_KEY)
|
localStorage.removeItem(LOCALE_STORAGE_REFRESH_TOKEN_KEY)
|
||||||
localStorage.removeItem(LOCALE_STORAGE_ACCESS_TOKEN_KEY)
|
localStorage.removeItem(LOCALE_STORAGE_ACCESS_TOKEN_KEY)
|
||||||
|
|
||||||
await router.push({
|
const locale = localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY) || DEFAULT_LOCALE;
|
||||||
name: 'home',
|
|
||||||
params: {
|
window.location.href = `/${locale}/`;
|
||||||
locale: localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY) || DEFAULT_LOCALE
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,10 @@ import {NEW_PASSWORD} from "@/graphql/mutations/auth.js";
|
||||||
import {computed, ref} from "vue";
|
import {computed, ref} from "vue";
|
||||||
import {ElNotification} from "element-plus";
|
import {ElNotification} from "element-plus";
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import {useRoute, useRouter} from "vue-router";
|
|
||||||
import {DEFAULT_LOCALE, LOCALE_STORAGE_LOCALE_KEY} from "@/config/index.js";
|
import {DEFAULT_LOCALE, LOCALE_STORAGE_LOCALE_KEY} from "@/config/index.js";
|
||||||
|
|
||||||
export function useNewPassword() {
|
export function useNewPassword() {
|
||||||
const {t} = useI18n();
|
const {t} = useI18n();
|
||||||
const route = useRoute();
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const { mutate: newPasswordMutation } = useMutation(NEW_PASSWORD);
|
const { mutate: newPasswordMutation } = useMutation(NEW_PASSWORD);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,11 @@ import {ElNotification} from "element-plus";
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import {useUserStore} from "@/stores/user.js";
|
import {useUserStore} from "@/stores/user.js";
|
||||||
import {LOCALE_STORAGE_REFRESH_TOKEN_KEY} from "@/config/index.js";
|
import {LOCALE_STORAGE_REFRESH_TOKEN_KEY} from "@/config/index.js";
|
||||||
import {useRoute, useRouter} from "vue-router";
|
|
||||||
import translations from "@/core/helpers/translations.js";
|
import translations from "@/core/helpers/translations.js";
|
||||||
import {usePendingOrder} from "@/composables/orders";
|
import {usePendingOrder} from "@/composables/orders";
|
||||||
import {useWishlist} from "@/composables/wishlist";
|
import {useWishlist} from "@/composables/wishlist";
|
||||||
|
|
||||||
export function useRefresh() {
|
export function useRefresh() {
|
||||||
const router = useRouter()
|
|
||||||
const route = useRoute()
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const {t} = useI18n();
|
const {t} = useI18n();
|
||||||
|
|
||||||
|
|
@ -42,7 +39,7 @@ export function useRefresh() {
|
||||||
})
|
})
|
||||||
|
|
||||||
if (response.data.refreshJwtToken.user.language !== translations.currentLocale) {
|
if (response.data.refreshJwtToken.user.language !== translations.currentLocale) {
|
||||||
translations.switchLanguage(response.data.refreshJwtToken.user.language, router, route)
|
translations.switchLanguage(response.data.refreshJwtToken.user.language)
|
||||||
}
|
}
|
||||||
|
|
||||||
localStorage.setItem(LOCALE_STORAGE_REFRESH_TOKEN_KEY, response.data.refreshJwtToken.refreshToken)
|
localStorage.setItem(LOCALE_STORAGE_REFRESH_TOKEN_KEY, response.data.refreshJwtToken.refreshToken)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ export const APP_NAME_KEY = APP_NAME.toLowerCase()
|
||||||
|
|
||||||
// LOCALES
|
// LOCALES
|
||||||
|
|
||||||
export const SUPPORTED_LOCALES = [
|
export const SUPPORTED_LOCALES = [
|
||||||
{
|
{
|
||||||
code: 'en-gb',
|
code: 'en-gb',
|
||||||
default: true
|
default: true
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ export async function loadLocaleMessages(locale) {
|
||||||
const messages = await import(`../locales/${locale}.json`)
|
const messages = await import(`../locales/${locale}.json`)
|
||||||
return messages.default || messages
|
return messages.default || messages
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Не удалось загрузить локаль: ${locale}`, error)
|
console.error(`Failed to load locale: ${locale}`, error)
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -21,7 +21,7 @@ export async function loadAllLocaleMessages(supportedLocales) {
|
||||||
const localeMessages = await import(`../../locales/${locale.code}.json`)
|
const localeMessages = await import(`../../locales/${locale.code}.json`)
|
||||||
messages[locale.code] = localeMessages.default || localeMessages
|
messages[locale.code] = localeMessages.default || localeMessages
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Не удалось загрузить локаль: ${locale.code}`, error)
|
console.error(`Failed to load locale: ${locale.code}`, error)
|
||||||
messages[locale.code] = {}
|
messages[locale.code] = {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,26 @@
|
||||||
import i18n from '@/core/plugins/i18n.config';
|
import i18n from '@/plugins/i18n.js';
|
||||||
import {DEFAULT_LOCALE, LOCALE_STORAGE_LOCALE_KEY, SUPPORTED_LOCALES} from "@/config/index.js";
|
import {DEFAULT_LOCALE, LOCALE_STORAGE_LOCALE_KEY, SUPPORTED_LOCALES} from "@/config/index.js";
|
||||||
|
|
||||||
const translations = {
|
const translations = {
|
||||||
get currentLocale() {
|
get currentLocale() {
|
||||||
return i18n.global.locale.value
|
return i18n.global?.locale?.value || DEFAULT_LOCALE.code;
|
||||||
},
|
},
|
||||||
|
|
||||||
set currentLocale(newLocale) {
|
set currentLocale(newLocale) {
|
||||||
i18n.global.locale.value = newLocale
|
if (i18n.global?.locale) {
|
||||||
|
i18n.global.locale.value = newLocale;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
switchLanguage(newLocale, router = null, route = null) {
|
switchLanguage(newLocale) {
|
||||||
translations.currentLocale = newLocale
|
translations.currentLocale = newLocale;
|
||||||
|
|
||||||
document.querySelector('html').setAttribute('lang', newLocale)
|
if (typeof document !== 'undefined') {
|
||||||
|
document.querySelector('html')?.setAttribute('lang', newLocale);
|
||||||
|
}
|
||||||
|
|
||||||
localStorage.setItem(LOCALE_STORAGE_LOCALE_KEY, newLocale)
|
if (typeof localStorage !== 'undefined') {
|
||||||
|
localStorage.setItem(LOCALE_STORAGE_LOCALE_KEY, newLocale);
|
||||||
if (router && route) {
|
|
||||||
const newRoute = {
|
|
||||||
...route,
|
|
||||||
params: {
|
|
||||||
...route.params,
|
|
||||||
locale: newLocale
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
router.push(newRoute).catch(err => {
|
|
||||||
if (err.name !== 'NavigationDuplicated') {
|
|
||||||
console.error('Navigation error:', err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -38,70 +28,95 @@ const translations = {
|
||||||
if (locale) {
|
if (locale) {
|
||||||
return SUPPORTED_LOCALES.some(supportedLocale => supportedLocale.code === locale);
|
return SUPPORTED_LOCALES.some(supportedLocale => supportedLocale.code === locale);
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
getUserLocale() {
|
getUserLocale() {
|
||||||
const locale =
|
if (typeof window === 'undefined') {
|
||||||
window.navigator.language ||
|
return {
|
||||||
DEFAULT_LOCALE.code
|
locale: DEFAULT_LOCALE.code,
|
||||||
|
localeNoRegion: DEFAULT_LOCALE.code.split('-')[0]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const locale = window.navigator.language || DEFAULT_LOCALE.code;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
locale: locale,
|
locale: locale,
|
||||||
localeNoRegion: locale.split('-')[0]
|
localeNoRegion: locale.split('-')[0]
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
getPersistedLocale() {
|
getPersistedLocale() {
|
||||||
const persistedLocale = localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY)
|
if (typeof localStorage === 'undefined') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const persistedLocale = localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY);
|
||||||
|
|
||||||
if (translations.isLocaleSupported(persistedLocale)) {
|
if (translations.isLocaleSupported(persistedLocale)) {
|
||||||
return persistedLocale
|
return persistedLocale;
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
guessDefaultLocale() {
|
guessDefaultLocale() {
|
||||||
const userPersistedLocale = translations.getPersistedLocale()
|
const userPersistedLocale = translations.getPersistedLocale();
|
||||||
if (userPersistedLocale) {
|
if (userPersistedLocale) {
|
||||||
return userPersistedLocale
|
return userPersistedLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userPreferredLocale = translations.getUserLocale()
|
if (typeof window !== 'undefined') {
|
||||||
|
const userPreferredLocale = translations.getUserLocale();
|
||||||
|
|
||||||
if (translations.isLocaleSupported(userPreferredLocale.locale)) {
|
if (translations.isLocaleSupported(userPreferredLocale.locale)) {
|
||||||
return userPreferredLocale.locale
|
return userPreferredLocale.locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (translations.isLocaleSupported(userPreferredLocale.localeNoRegion)) {
|
if (translations.isLocaleSupported(userPreferredLocale.localeNoRegion)) {
|
||||||
return userPreferredLocale.localeNoRegion
|
return userPreferredLocale.localeNoRegion;
|
||||||
}
|
|
||||||
|
|
||||||
return DEFAULT_LOCALE.code
|
|
||||||
},
|
|
||||||
|
|
||||||
async routeMiddleware(to, _from, next) {
|
|
||||||
const paramLocale = to.params.locale
|
|
||||||
|
|
||||||
if (!translations.isLocaleSupported(paramLocale)) {
|
|
||||||
return next(translations.guessDefaultLocale())
|
|
||||||
}
|
|
||||||
|
|
||||||
await translations.switchLanguage(paramLocale)
|
|
||||||
|
|
||||||
return next()
|
|
||||||
},
|
|
||||||
|
|
||||||
i18nRoute(to) {
|
|
||||||
return {
|
|
||||||
...to,
|
|
||||||
params: {
|
|
||||||
locale: translations.currentLocale,
|
|
||||||
...to.params
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default translations
|
return DEFAULT_LOCALE.code;
|
||||||
|
},
|
||||||
|
|
||||||
|
getLocaleFromUrl(url) {
|
||||||
|
const pathParts = new URL(url).pathname.split('/').filter(Boolean);
|
||||||
|
if (pathParts.length > 0) {
|
||||||
|
const possibleLocale = pathParts[0];
|
||||||
|
if (translations.isLocaleSupported(possibleLocale)) {
|
||||||
|
return possibleLocale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DEFAULT_LOCALE.code;
|
||||||
|
},
|
||||||
|
|
||||||
|
getLocaleFromRequest(request) {
|
||||||
|
if (request?.headers) {
|
||||||
|
const acceptLanguage = request.headers.get('accept-language');
|
||||||
|
if (acceptLanguage) {
|
||||||
|
const preferredLocales = acceptLanguage.split(',')
|
||||||
|
.map(lang => {
|
||||||
|
const [locale, priority = 'q=1.0'] = lang.trim().split(';');
|
||||||
|
return {
|
||||||
|
locale: locale.split('-')[0],
|
||||||
|
priority: parseFloat(priority.split('=')[1])
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => b.priority - a.priority);
|
||||||
|
|
||||||
|
for (const { locale } of preferredLocales) {
|
||||||
|
if (translations.isLocaleSupported(locale)) {
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEFAULT_LOCALE.code;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default translations;
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
import { createI18n } from 'vue-i18n'
|
|
||||||
import {DEFAULT_LOCALE, LOCALE_STORAGE_LOCALE_KEY, SUPPORTED_LOCALES} from "@/config/index.js";
|
|
||||||
import {loadAllLocaleMessages} from "@/core/helpers/i18n-utils.js";
|
|
||||||
|
|
||||||
const savedLocale = localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY)
|
|
||||||
const currentLocale = savedLocale && SUPPORTED_LOCALES.some(locale => locale.code === savedLocale)
|
|
||||||
? savedLocale
|
|
||||||
: DEFAULT_LOCALE
|
|
||||||
|
|
||||||
if (!savedLocale) {
|
|
||||||
localStorage.setItem(LOCALE_STORAGE_LOCALE_KEY, DEFAULT_LOCALE)
|
|
||||||
}
|
|
||||||
|
|
||||||
const i18n = createI18n({
|
|
||||||
locale: currentLocale,
|
|
||||||
fallbackLocale: DEFAULT_LOCALE,
|
|
||||||
allowComposition: true,
|
|
||||||
legacy: false,
|
|
||||||
globalInjection: true,
|
|
||||||
messages: {}
|
|
||||||
})
|
|
||||||
|
|
||||||
export async function setupI18n() {
|
|
||||||
const messages = await loadAllLocaleMessages(SUPPORTED_LOCALES)
|
|
||||||
|
|
||||||
Object.keys(messages).forEach(locale => {
|
|
||||||
i18n.global.setLocaleMessage(locale, messages[locale])
|
|
||||||
})
|
|
||||||
|
|
||||||
return i18n
|
|
||||||
}
|
|
||||||
|
|
||||||
export default i18n
|
|
||||||
31
storefront/src/layouts/default-layout.astro
Normal file
31
storefront/src/layouts/default-layout.astro
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
import {useRefresh} from "@/composables/auth";
|
||||||
|
import {useCompanyInfo} from "@/composables/company";
|
||||||
|
import {useLanguages} from "@/composables/languages/index.js";
|
||||||
|
import BaseHeader from "@/components/base/header/base-header.vue";
|
||||||
|
import BaseFooter from "@/components/base/base-footer.vue";
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
const { refresh } = useRefresh();
|
||||||
|
const { getCompanyInfo } = useCompanyInfo();
|
||||||
|
const { getLanguages } = useLanguages();
|
||||||
|
|
||||||
|
await refresh();
|
||||||
|
await getCompanyInfo();
|
||||||
|
await getLanguages();
|
||||||
|
|
||||||
|
setInterval(async () => {
|
||||||
|
await refresh();
|
||||||
|
}, 600000);
|
||||||
|
});
|
||||||
|
---
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<BaseHeader client:load />
|
||||||
|
<slot />
|
||||||
|
<BaseFooter client:load />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
|
import DefaultLayout from '../layouts/default-layout.astro';
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
<title>Astro</title>
|
<title>Astro</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Astro</h1>
|
<DefaultLayout>
|
||||||
|
<h1>Astro</h1>
|
||||||
|
</DefaultLayout>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
61
storefront/src/plugins/i18n.js
Normal file
61
storefront/src/plugins/i18n.js
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { createI18n } from 'vue-i18n'
|
||||||
|
import { DEFAULT_LOCALE, LOCALE_STORAGE_LOCALE_KEY, SUPPORTED_LOCALES } from "../config/index.js";
|
||||||
|
import { loadAllLocaleMessages } from "../core/helpers/i18n-utils.js";
|
||||||
|
|
||||||
|
export async function setupI18n() {
|
||||||
|
const i18n = createI18n({
|
||||||
|
locale: DEFAULT_LOCALE,
|
||||||
|
fallbackLocale: DEFAULT_LOCALE,
|
||||||
|
messages: {},
|
||||||
|
allowComposition: true,
|
||||||
|
legacy: false,
|
||||||
|
globalInjection: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const messages = await loadAllLocaleMessages(SUPPORTED_LOCALES);
|
||||||
|
|
||||||
|
Object.keys(messages).forEach(locale => {
|
||||||
|
i18n.global.setLocaleMessage(locale, messages[locale]);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const savedLocale = localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY);
|
||||||
|
const validLocale = savedLocale &&
|
||||||
|
SUPPORTED_LOCALES.some(locale => locale.code === savedLocale)
|
||||||
|
? savedLocale
|
||||||
|
: DEFAULT_LOCALE;
|
||||||
|
|
||||||
|
i18n.global.locale.value = validLocale;
|
||||||
|
|
||||||
|
if (!savedLocale) {
|
||||||
|
localStorage.setItem(LOCALE_STORAGE_LOCALE_KEY, DEFAULT_LOCALE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i18n;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCurrentLocale(request) {
|
||||||
|
if (typeof window === 'undefined' && request) {
|
||||||
|
const acceptLanguageHeader = request.headers.get('accept-language');
|
||||||
|
if (acceptLanguageHeader) {
|
||||||
|
const preferredLocale = acceptLanguageHeader.split(',')[0].trim().split('-')[0];
|
||||||
|
const supportedLocale = SUPPORTED_LOCALES.find(locale =>
|
||||||
|
locale.code.startsWith(preferredLocale)
|
||||||
|
);
|
||||||
|
if (supportedLocale) {
|
||||||
|
return supportedLocale.code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DEFAULT_LOCALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const savedLocale = localStorage.getItem(LOCALE_STORAGE_LOCALE_KEY);
|
||||||
|
return savedLocale && SUPPORTED_LOCALES.some(locale => locale.code === savedLocale)
|
||||||
|
? savedLocale
|
||||||
|
: DEFAULT_LOCALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEFAULT_LOCALE;
|
||||||
|
}
|
||||||
10
storefront/src/plugins/index.js
Normal file
10
storefront/src/plugins/index.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { setupI18n } from './i18n.js'
|
||||||
|
import { pinia } from "../stores/index.js";
|
||||||
|
|
||||||
|
export default function (app) {
|
||||||
|
app.use(pinia)
|
||||||
|
|
||||||
|
setupI18n().then(i18n => {
|
||||||
|
app.use(i18n)
|
||||||
|
})
|
||||||
|
}
|
||||||
14
storefront/src/stores/cart.js
Normal file
14
storefront/src/stores/cart.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import {defineStore} from "pinia";
|
||||||
|
import {ref} from "vue";
|
||||||
|
|
||||||
|
export const useCartStore = defineStore('cart', () => {
|
||||||
|
const currentOrder = ref({});
|
||||||
|
const setCurrentOrders = (order) => {
|
||||||
|
currentOrder.value = order
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentOrder,
|
||||||
|
setCurrentOrders
|
||||||
|
}
|
||||||
|
})
|
||||||
14
storefront/src/stores/company.js
Normal file
14
storefront/src/stores/company.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
export const useCompanyStore = defineStore('company', () => {
|
||||||
|
const companyInfo = ref([]);
|
||||||
|
const setCompanyInfo = (payload) => {
|
||||||
|
companyInfo.value = payload
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
companyInfo,
|
||||||
|
setCompanyInfo
|
||||||
|
}
|
||||||
|
})
|
||||||
3
storefront/src/stores/index.js
Normal file
3
storefront/src/stores/index.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { createPinia } from 'pinia'
|
||||||
|
|
||||||
|
export const pinia = createPinia()
|
||||||
14
storefront/src/stores/languages.js
Normal file
14
storefront/src/stores/languages.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
export const useLanguageStore = defineStore('language', () => {
|
||||||
|
const languages = ref([]);
|
||||||
|
const setLanguages = (payload) => {
|
||||||
|
languages.value = payload
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
languages,
|
||||||
|
setLanguages
|
||||||
|
}
|
||||||
|
})
|
||||||
11
storefront/src/stores/user.js
Normal file
11
storefront/src/stores/user.js
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import {defineStore} from "pinia";
|
||||||
|
import {ref} from "vue";
|
||||||
|
|
||||||
|
export const useUserStore = defineStore('user', () => {
|
||||||
|
const user = ref(null);
|
||||||
|
const setUser = (payload) => {
|
||||||
|
user.value = payload.user
|
||||||
|
}
|
||||||
|
|
||||||
|
return { user, setUser }
|
||||||
|
})
|
||||||
14
storefront/src/stores/wishlist.js
Normal file
14
storefront/src/stores/wishlist.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
export const useWishlistStore = defineStore('wishlist', () => {
|
||||||
|
const wishlist = ref({});
|
||||||
|
const setWishlist = (order) => {
|
||||||
|
wishlist.value = order
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
wishlist,
|
||||||
|
setWishlist
|
||||||
|
}
|
||||||
|
})
|
||||||
Loading…
Reference in a new issue