From 551b5ef77d796c411845856921d3a1c9976c0e97 Mon Sep 17 00:00:00 2001 From: Arina Yakovenko Date: Thu, 2 Apr 2026 11:41:44 +0200 Subject: [PATCH] fix: translations --- bo/src/components/admin/ProductDetailView.vue | 2 +- .../inner/CountryCurrencySwitch.vue | 44 ++--- bo/src/components/inner/LangSwitch.vue | 48 +++-- bo/src/layouts/default.vue | 117 ++++++------ bo/src/stores/product.ts | 178 +++++------------- 5 files changed, 157 insertions(+), 232 deletions(-) diff --git a/bo/src/components/admin/ProductDetailView.vue b/bo/src/components/admin/ProductDetailView.vue index f94ee32..9932b82 100644 --- a/bo/src/components/admin/ProductDetailView.vue +++ b/bo/src/components/admin/ProductDetailView.vue @@ -41,7 +41,7 @@ }" color="primary" class="text-white bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) px-12!"> Cancel - Save diff --git a/bo/src/components/inner/CountryCurrencySwitch.vue b/bo/src/components/inner/CountryCurrencySwitch.vue index cb15e33..f51746c 100644 --- a/bo/src/components/inner/CountryCurrencySwitch.vue +++ b/bo/src/components/inner/CountryCurrencySwitch.vue @@ -1,34 +1,34 @@ - - diff --git a/bo/src/stores/product.ts b/bo/src/stores/product.ts index a400bd2..134a988 100644 --- a/bo/src/stores/product.ts +++ b/bo/src/stores/product.ts @@ -45,6 +45,7 @@ export const useProductStore = defineStore('product', () => { } } + const translat = ref() const settingStore = useSettingsStore() async function translateProductDescription(productID: number, toLangId: number, model: string = 'Google') { loading.value = true @@ -53,6 +54,7 @@ export const useProductStore = defineStore('product', () => { try { const response = await useFetchJson(`/api/v1/restricted/product-translation/translate-product-description?productID=${productID}&productFromLangID=${settingStore.shopDefaultLanguage}&productToLangID=${toLangId}&model=${model}`) productDescription.value = response.items + saveProductDescription(productID, toLangId) return response.items } catch (e: any) { error.value = e?.message || 'Failed to translate product description' @@ -62,16 +64,46 @@ export const useProductStore = defineStore('product', () => { } } + function fixHtml(html: string) { + return html + // 1. fix img + .replace(/]*?)>/g, '') - function stripHtml(html: string) { - const div = document.createElement('div') - div.innerHTML = html - return div.textContent || div.innerText || '' + // 2. escape text only + .replace(/>([^<]+) { + const escaped = text + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/'/g, ''') + + return `>${escaped}<` + }) } - async function saveProductDescription(productID?: number, langId?: number) { + function fixAll(obj: any): any { + if (typeof obj === 'string') { + return fixHtml(obj) + } + + if (Array.isArray(obj)) { + return obj.map(fixAll) + } + + if (typeof obj === 'object' && obj !== null) { + const result: any = {} + for (const [key, value] of Object.entries(obj)) { + result[key] = fixAll(value) + } + return result + } + + return obj + } + + async function saveProductDescription(productID?: number, langId?: number | null) { const id = productID || 1 const lang = langId || 1 + try { const data = await useFetchJson( `/api/v1/restricted/product-translation/save-product-description?productID=${id}&productLangID=${lang}`, @@ -81,14 +113,14 @@ export const useProductStore = defineStore('product', () => { 'Content-Type': 'application/json' }, body: JSON.stringify({ - name: stripHtml(productDescription.value?.name || ''), - description: stripHtml(productDescription.value?.description || ''), - description_short: stripHtml(productDescription.value?.description_short || ''), - meta_title: stripHtml(productDescription.value?.meta_title || ''), - meta_description: stripHtml(productDescription.value?.meta_description || ''), - available_now: stripHtml(productDescription.value?.available_now || ''), - available_later: stripHtml(productDescription.value?.available_later || ''), - usage: stripHtml(productDescription.value?.usage || ''), + name: productDescription.value?.name || '', + description: productDescription.value?.description || '', + description_short: productDescription.value?.description_short || '', + meta_title: productDescription.value?.meta_title || '', + meta_description: productDescription.value?.meta_description || '', + available_now: productDescription.value?.available_now || '', + available_later: productDescription.value?.available_later || '', + usage: productDescription.value?.usage || '', // delivery_in_stock: stripHtml(productDescription.value?.delivery_in_stock || '') }) } @@ -103,126 +135,10 @@ export const useProductStore = defineStore('product', () => { productDescription, loading, error, + translat, translateProductDescription, getProductDescription, saveProductDescription } -}) - - - -// import { defineStore } from 'pinia' -// import { ref } from 'vue' -// import { useFetchJson } from '@/composable/useFetchJson' -// import type { ProductDescription } from '@/types/product' -// import { useSettingsStore } from './settings' - -// export interface Product { -// id: number -// image: string -// name: string -// code: string -// inStock: boolean -// priceFrom: number -// priceTo: number -// count: number -// description?: string -// howToUse?: string -// productDetails?: string -// } - -// export interface ProductResponse { -// items: Product[] -// items_count: number -// } - -// export const useProductStore = defineStore('product', () => { -// const productDescription = ref() -// const currentProduct = ref(null) -// const loading = ref(false) -// const error = ref(null) - -// async function getProductDescription(langId = 1, productID: number) { -// loading.value = true -// error.value = null - -// try { -// const response = await useFetchJson( -// `/api/v1/restricted/product-translation/get-product-description?productID=${productID}&productLangID=${langId}` -// ) -// productDescription.value = response.items -// console.log(productDescription, 'dfsfsdf'); - -// } catch (e: unknown) { -// error.value = e instanceof Error ? e.message : 'Failed to load product description' -// } finally { -// loading.value = false -// } -// } -// function stripHtml(html: string) { -// const div = document.createElement('div') -// div.innerHTML = html -// return div.textContent || div.innerText || '' -// } -// async function saveProductDescription(productID?: number, langId?: number) { -// const id = productID || 1 -// const lang = langId || 1 -// try { -// const data = await useFetchJson( -// `/api/v1/restricted/product-translation/save-product-description?productID=${id}&productLangID=${lang}`, -// { -// method: 'POST', -// headers: { -// 'Content-Type': 'application/json' -// }, -// body: JSON.stringify({ -// name: stripHtml(productDescription.value?.name || ''), -// description: stripHtml(productDescription.value?.description || ''), -// description_short: stripHtml(productDescription.value?.description_short || ''), -// meta_title: stripHtml(productDescription.value?.meta_title || ''), -// meta_description: stripHtml(productDescription.value?.meta_description || ''), -// available_now: stripHtml(productDescription.value?.available_now || ''), -// available_later: stripHtml(productDescription.value?.available_later || ''), -// usage: stripHtml(productDescription.value?.usage || '') -// }) -// } -// ) -// return data -// } catch (e) { -// console.error(e) -// } -// } - -// const defaultLangId = ref(1) -// async function translateProductDescription(productID: number, fromLangId: number, defaultLangId: number, model: string = 'OpenAI') { -// loading.value = true -// error.value = null - -// try { -// const response = await useFetchJson(`/api/v1/restricted/product-translation/translate-product-description?productID=${productID}&productFromLangID=${fromLangId}&productToLangID=${defaultLangId}&model=${model}`) -// productDescription.value = response.items -// return response.items -// } catch (e: any) { -// error.value = e?.message || 'Failed to translate product description' -// console.error('Failed to translate product description:', e) -// } finally { -// loading.value = false -// } -// } - -// function clearCurrentProduct() { -// currentProduct.value = null -// } - -// return { -// productDescription, -// currentProduct, -// loading, -// error, -// getProductDescription, -// clearCurrentProduct, -// saveProductDescription, -// translateProductDescription, -// } -// }) \ No newline at end of file +}) \ No newline at end of file