feat: 修改语言

This commit is contained in:
2026-06-03 13:14:12 +08:00
parent 1c80ba9fbc
commit bcb04aedd7
7 changed files with 90 additions and 96 deletions

View File

@@ -146,7 +146,9 @@ export const getUserLanguage = (): Promise<ApiResponse> => {
}
// 设置语言
export const setUserLanguage = (language: string): Promise<ApiResponse> => {
export const setUserLanguage = (
language: 'ENGLISH' | 'CHINESE_SIMPLIFIED'
): Promise<ApiResponse> => {
return request({
url: '/buyer/profile/setLanguage',
method: 'post',

View File

@@ -83,7 +83,7 @@ export default {
avatarCrop: {
title: 'Crop Avatar',
confirm: 'Confirm',
processing: 'Processing...',
processing: 'Processing...'
},
security: {
title: 'Security',
@@ -159,8 +159,8 @@ export default {
other: 'Other'
},
languages: {
english: 'English',
chinese: 'Chinese'
ENGLISH: 'English',
CHINESE_SIMPLIFIED: 'Chinese Simplified'
},
regions: {
hongKongSar: 'Hong Kong SAR',
@@ -338,34 +338,41 @@ export default {
AddToCart: 'Add to Cart'
},
Home: {
IndexTitle: 'Were Seeking<br /><span>Fashion Voice</span><br /><span class="small">Worth Featuring.</span>',
IndexTip: 'Discover collections through the stories behind their creation. A curated space connecting designers, narratives, and fashion commerce.',
IndexTitle:
'Were Seeking<br /><span>Fashion Voice</span><br /><span class="small">Worth Featuring.</span>',
IndexTip:
'Discover collections through the stories behind their creation. A curated space connecting designers, narratives, and fashion commerce.',
DesignerTitle: 'Designer Community',
DesignerTip: 'Discover the designers shaping AiDAs creative landscape. <br />Each month, we will showcase a curated selection of their most distinguished works.',
DesignerTip:
'Discover the designers shaping AiDAs creative landscape. <br />Each month, we will showcase a curated selection of their most distinguished works.',
SearchBrands: 'Search Brands',
AidaTitle: 'Design with AiDA',
AidaTip: 'Each garment on this platform is where designer vision blooms through AiDA. A tool that nurtures your creativity, never overshadows it. Let your ideas flourish.',
AidaTip:
'Each garment on this platform is where designer vision blooms through AiDA. A tool that nurtures your creativity, never overshadows it. Let your ideas flourish.',
TryNow: 'Try Now',
DigitalItems: 'Digital Items',
DigitalItemsTip1: 'AiDA captures your boldest thoughts and transforms them into vivid<br/>digital visions—a virtual realm where creativity collides and evolves.',
DigitalItemsTip2: 'AiDA accelerates style innovation, shaping daily pieces that keep<br/>your wardrobe in sync with modern fashions rhythm.',
FooterTip: "Stylish Parade is a commerce platform for designers, serving as AiDA's commercial extension.",
FooterAidaTip: "Bloom your Creativity with AiDA!",
Help: "Help",
FAQ: "FAQ",
MyAccount: "My Account",
MyOrders: "My Orders",
PaymentInvoices: "Payment and Invoices",
CopyrightLicense: "Copyright Licence",
Polices: "Policies",
Legal: "Legal",
PrivacyPolicy: "Privacy Policy",
CookiesSettings: "Cookies Settings",
PurchaseConditions: "Purchase Conditions",
Company: "Company",
AboutUs: "About Us",
Offices: "Offices",
JoinWithUs: "Join with Us",
DigitalItemsTip1:
'AiDA captures your boldest thoughts and transforms them into vivid<br/>digital visions—a virtual realm where creativity collides and evolves.',
DigitalItemsTip2:
'AiDA accelerates style innovation, shaping daily pieces that keep<br/>your wardrobe in sync with modern fashions rhythm.',
FooterTip:
"Stylish Parade is a commerce platform for designers, serving as AiDA's commercial extension.",
FooterAidaTip: 'Bloom your Creativity with AiDA!',
Help: 'Help',
FAQ: 'FAQ',
MyAccount: 'My Account',
MyOrders: 'My Orders',
PaymentInvoices: 'Payment and Invoices',
CopyrightLicense: 'Copyright Licence',
Polices: 'Policies',
Legal: 'Legal',
PrivacyPolicy: 'Privacy Policy',
CookiesSettings: 'Cookies Settings',
PurchaseConditions: 'Purchase Conditions',
Company: 'Company',
AboutUs: 'About Us',
Offices: 'Offices',
JoinWithUs: 'Join with Us'
},
addShoppingCart: {
title: 'Added to your Shopping Cart',
@@ -394,18 +401,22 @@ export default {
OrderSummary: 'Order Summary',
PaymentDetails: 'Payment Details',
CreditDebitCard: 'Credit / Debit Card',
AgreementText: 'I agree to the <span onclick="{onTermsClick}">Terms & Conditions</span> and <span onclick="{onPrivacyClick}">Privacy Policy</span>. All digital item sales are final and non-refundable.',
AgreementText:
'I agree to the <span onclick="{onTermsClick}">Terms & Conditions</span> and <span onclick="{onPrivacyClick}">Privacy Policy</span>. All digital item sales are final and non-refundable.',
PayWithStripe: 'Pay with Stripe',
PayWith: 'Pay with',
Cancel: 'Cancel',
IHaveCompletedPayment: 'I Have Completed payment',
Back: 'Back',
PayTip1: "You'll be redirected to a Stripe popup to log in and confirm. No card details are shared with Stylish Parade — Stripe handles all payment security.",
PayTip2: "Please keep the window open until the payment is completed. If you are to open the payment window, please check your browser settings to see if pop-ups are being blocked. Points may be delayed after successful payment. Please wait 1-3 minutes and click the credits refresh button.",
PurchaseSuccessful: "Purchase Successful",
PurchaseSuccessfulTip: "Your digital items are now available and have been saved in Personal Center → My Wardrobe.",
DownloadAllAssets: "download all Assets",
ExportInvoice: "Export Invoice",
ContinueShopping: "Continue Shopping"
PayTip1:
"You'll be redirected to a Stripe popup to log in and confirm. No card details are shared with Stylish Parade — Stripe handles all payment security.",
PayTip2:
'Please keep the window open until the payment is completed. If you are to open the payment window, please check your browser settings to see if pop-ups are being blocked. Points may be delayed after successful payment. Please wait 1-3 minutes and click the credits refresh button.',
PurchaseSuccessful: 'Purchase Successful',
PurchaseSuccessfulTip:
'Your digital items are now available and have been saved in Personal Center → My Wardrobe.',
DownloadAllAssets: 'download all Assets',
ExportInvoice: 'Export Invoice',
ContinueShopping: 'Continue Shopping'
}
}

View File

@@ -78,7 +78,7 @@ export default {
avatarCrop: {
title: '裁剪头像',
confirm: '确认',
processing: '处理中...',
processing: '处理中...'
},
security: {
title: '安全',
@@ -154,8 +154,8 @@ export default {
other: '其他'
},
languages: {
english: '英文',
chinese: '中文'
ENGLISH: '英文',
CHINESE_SIMPLIFIED: '简体中文'
},
regions: {
hongKongSar: '中国香港特别行政区',
@@ -393,18 +393,21 @@ export default {
OrderSummary: '订单信息',
PaymentDetails: '支付详情',
CreditDebitCard: '信用卡/借记卡',
AgreementText: '我同意 <span onclick="{onTermsClick}">使用条款与条件</span> 和 <span onclick="{onPrivacyClick}">隐私政策</span>。所有数字资产销售均为最终销售,不可退款。',
AgreementText:
'我同意 <span onclick="{onTermsClick}">使用条款与条件</span> 和 <span onclick="{onPrivacyClick}">隐私政策</span>。所有数字资产销售均为最终销售,不可退款。',
PayWithStripe: '使用 Stripe 支付',
PayWith: '支付',
Cancel: '取消',
IHaveCompletedPayment: '我已完成支付',
Back: '返回',
PayTip1: "您将被重定向到 Stripe 弹窗以登录并确认支付。您的信用卡信息不会被 Stylish Parade 收集。Stripe 处理所有支付安全。",
PayTip2: "请保持窗口打开,直到支付完成。如果您打开支付窗口,请检查浏览器设置以查看是否已阻止弹窗。支付完成后,积分可能会有延迟。请等待 1-3 分钟并点击积分刷新按钮。",
PurchaseSuccessful: "购买成功",
PurchaseSuccessfulTip: "您的数字资产已保存在个人中心的我的衣橱中。",
DownloadAllAssets: "下载所有资产",
ExportInvoice: "导出发票",
ContinueShopping: "继续购物"
PayTip1:
'您将被重定向到 Stripe 弹窗以登录并确认支付。您的信用卡信息不会被 Stylish Parade 收集。Stripe 处理所有支付安全。',
PayTip2:
'请保持窗口打开,直到支付完成。如果您打开支付窗口,请检查浏览器设置以查看是否已阻止弹窗。支付完成后,积分可能会有延迟。请等待 1-3 分钟并点击积分刷新按钮。',
PurchaseSuccessful: '购买成功',
PurchaseSuccessfulTip: '您的数字资产已保存在个人中心的我的衣橱中。',
DownloadAllAssets: '下载所有资产',
ExportInvoice: '导出发票',
ContinueShopping: '继续购物'
}
}

View File

@@ -175,12 +175,11 @@
const onLanguageClick = () => {
locale.value = locale.value === 'ENGLISH' ? 'CHINESE_SIMPLIFIED' : 'ENGLISH'
localStorage.setItem('language', locale.value)
console.log(locale.value)
const localeMap: Record<string, string> = {
ENGLISH: 'en',
CHINESE_SIMPLIFIED: 'zh-CN'
}
setUserLanguage(localeMap[locale.value])
setUserLanguage(locale.value).then((res) => {
userInfoStore.setToken(res)
location.reload()
})
}
</script>

View File

@@ -119,9 +119,9 @@
loadUserProfile
} = useSettingsForm({ t, locale })
watch(locale, () => {
loadUserProfile()
})
// watch(locale, () => {
// loadUserProfile()
// })
onMounted(() => {
loadUserProfile()

View File

@@ -12,7 +12,7 @@ export const roleValues = [
'other'
] as const
export const languageValues = ['english', 'chinese'] as const
export const languageValues = ['ENGLISH', 'CHINESE_SIMPLIFIED'] as const
export type RoleValue = (typeof roleValues)[number]

View File

@@ -6,7 +6,8 @@ import {
type UserProfile,
updateUserProfile,
verifyEmailCode,
fetchVerifyCode
fetchVerifyCode,
setUserLanguage
} from '@/api/user'
import regionList from '@/utils/area'
import {
@@ -18,6 +19,9 @@ import {
type SettingsData
} from './types'
import { validateCase, validateLength, validateSpecial } from '@/views/login/tools'
import {useUserInfoStore} from '@/stores'
const userInfoStore = useUserInfoStore()
type Translate = (key: string, ...args: unknown[]) => string
@@ -26,24 +30,6 @@ interface UseSettingsFormOptions {
locale: Ref<string>
}
// 前端 UI 使用的语言值(用于下拉选择)
const languageLocaleMap: Record<LanguageValue, 'ENGLISH' | 'CHINESE_SIMPLIFIED'> = {
english: 'ENGLISH',
chinese: 'CHINESE_SIMPLIFIED'
}
// 后端 API 使用的语言值
const backendLanguageMap: Record<'ENGLISH' | 'CHINESE_SIMPLIFIED', 'en' | 'zh-CN'> = {
ENGLISH: 'en',
CHINESE_SIMPLIFIED: 'zh-CN'
}
// 后端语言值转换为前端语言值
const backendToFrontendLanguage: Record<'en' | 'zh-CN', LanguageValue> = {
en: 'english',
'zh-CN': 'chinese'
}
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
const isRoleValue = (value: string): value is RoleValue =>
@@ -75,15 +61,10 @@ const normalizeLanguage = (language: string | null | undefined): LanguageValue =
if (!language) {
return '' as LanguageValue
}
// 后端返回 'en' 或 'zh-CN'
const trimmed = language.trim()
if (trimmed === 'en') {
return 'english'
} else if (trimmed === 'zh-CN') {
return 'chinese'
if (trimmed === 'ENGLISH' || trimmed === 'CHINESE_SIMPLIFIED') {
return trimmed as LanguageValue
}
return '' as LanguageValue
}
@@ -182,9 +163,8 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
}
const syncAppLanguage = (language: LanguageValue) => {
const nextLocale = languageLocaleMap[language]
locale.value = nextLocale
localStorage.setItem('language', nextLocale)
locale.value = language
localStorage.setItem('language', language)
}
const loadUserProfile = async () => {
@@ -334,12 +314,8 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
return
}
// 前端语言值转换为后端格式
let backendLanguage = ''
if (draftData.value.language) {
const i18nLocale = languageLocaleMap[draftData.value.language as LanguageValue]
backendLanguage = backendLanguageMap[i18nLocale]
}
// 前端语言值直接作为后端格式
const backendLanguage = draftData.value.language || ''
const nextData: UserProfile = {
firstName: draftData.value.firstName.trim(),
@@ -370,10 +346,8 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
try {
await updateUserProfile(nextData)
// 后端返回的语言值转换为前端格式
const frontendLanguage = backendLanguage
? backendToFrontendLanguage[backendLanguage as 'en' | 'zh-CN']
: ''
// 后端返回的语言值直接作为前端格式
const frontendLanguage = backendLanguage as LanguageValue
const settingsData: SettingsData = {
firstName: nextData.firstName,
@@ -388,7 +362,12 @@ export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
console.log(nextData)
if (frontendLanguage && frontendLanguage !== previousLanguage) {
syncAppLanguage(frontendLanguage as LanguageValue)
// syncAppLanguage(frontendLanguage as LanguageValue)
setUserLanguage(frontendLanguage).then((res) => {
// console.log(res)
userInfoStore.setToken(res)
location.reload()
})
}
draftData.value = cloneSettingsData(sourceData.value)