适配语言

This commit is contained in:
2026-02-04 17:00:58 +08:00
parent 4a1c4885ef
commit 01ea6169c9
17 changed files with 217 additions and 99 deletions

View File

@@ -5,10 +5,22 @@
<script setup lang="ts">
import RouteCache from '@/components/RouteCache.vue'
import { useRouter } from 'vue-router'
import { computed } from 'vue'
import { useGlobalStore } from '@/stores'
const router = useRouter()
const globalStore = useGlobalStore()
const loading = computed(() => globalStore.state.loading || globalStore.state.view_loading)
window['onClickPrivacy'] = () => {
// window.event?.preventDefault()
console.log('onClickPrivacy')
}
window['onClickLogin'] = () => {
router.push({ name: 'login' })
}
window['onClickRegister'] = () => {
router.push({ name: 'register' })
}
</script>
<style lang="less">

View File

@@ -1,5 +1,60 @@
export default {
Login: {},
Login: {
Login: 'Log in',
SignUp: 'Sign up',
LoginTo: 'Log on to',
LoginTitle: 'A multi-agent canvas for rapid, trend driven design iteration.',
name: 'Name',
email: 'Email',
password: 'Password',
enterName: 'Enter your name',
enterEmail: 'Enter your email',
enterPassword: 'Enter your password',
forgetPassword: 'Forget password?',
pleaseInputName: 'Please input the name',
nameLengthError: 'Name length must be between {min} and {max} characters',
pleaseInputEmail: 'Please input the email',
emailFormatError: 'Please input the email again',
pleaseInputPassword: 'Please input the password',
passwordLengthError: 'Password length must be between {min} and {max} characters',
pleaseTermsPolicy: 'Please agree to the Terms, Policy and Fees',
agreeTermsPolicy: 'I agree to the <span onclick="onClickPrivacy()">Terms, Policy</span> and Fees.',
noAccountToSignUp: `Don't have an account? <span onclick="onClickRegister()">Sign up</span>`,
registerFor: 'Register for',
registerTip: 'A multi-agent canvas for rapid, trend driven design iteration.',
havenAccountToLogin: `Already have an account? <span onclick="onClickLogin()">Log in</span>`,
verifyEmail: 'Verify your email address',
verifyCodeHasSent: 'A verification code has been sent to <span>{email}</span>',
verify: 'Verify',
resendCode: 'Resend Code',
resendCodeIn: 'Resend Code in {time}',
orContinueWith: 'or continue with',
googleLogin: 'Sign in with Google',
wechatLogin: 'Sign in with Wechat',
},
Nuic: {
hiName: 'Hi, {name}.',
nuic1Title: `Help Fiphant discover the <b>'YOU'</b> in your space.`,
nuic1Tip: `Let's set up your profile. A few quick details will help Fiphant understand<br />your needs and find exactly what you're looking for.`,
letsGo: 'Lets go, Fiphant!',
skip: 'Skip',
next: 'Next',
nuic2Title: `What's your dream <b>home vibe</b> ?`,
loadMore: 'Load more',
nuic3Title: `Where <b>are you based</b>? What do you <b>do</b> ?`,
basedIn: 'Based in',
role: 'Role',
allSet: 'All set!',
},
Home:{
creditsNum: 'Credits: {num}',
newProject: 'New Project',
home: 'Home',
history: 'History',
today: 'Today',
yesterday: 'Yesterday',
earlierChat: 'Earlier Chat',
},
Input: {
placeholder: 'Please input',
selectPlaceholder: 'Please select',

View File

@@ -4,9 +4,11 @@ import { createI18n } from 'vue-i18n'
// element-plus 中的语言配置
import elementEnLocale from './en'
import elementZhLocale from './zh-cn'
// 自己的语言配置
import enLocale from './en'
import zhLocale from './zh-cn'
// 语言配置整合
const messages = {
@@ -14,10 +16,10 @@ const messages = {
...enLocale,
...elementEnLocale
},
// 'CHINESE_SIMPLIFIED':{
// ...zhLocale,
// ...elementZhLocale
// },
'CHINESE_SIMPLIFIED':{
...zhLocale,
...elementZhLocale
},
}
// 创建 i18n

View File

@@ -1,6 +1,60 @@
export default {
Login: {
Login: '登录',
SignUp: '注册',
LoginTo: '登录到',
LoginTitle: '一个多智能体画布,用于快速、趋势驱动的设计迭代。',
name: '姓名',
email: '邮箱',
password: '密码',
enterName: '请输入姓名',
enterEmail: '请输入邮箱',
enterPassword: '请输入密码',
forgetPassword: '忘记密码?',
pleaseInputName: '请输入姓名',
nameLengthError: '姓名长度必须在 {min} 到 {max} 个字符之间',
pleaseInputEmail: '请输入邮箱',
emailFormatError: '请输入正确的邮箱',
pleaseInputPassword: '请输入密码',
passwordLengthError: '密码长度必须在 {min} 到 {max} 个字符之间',
pleaseTermsPolicy: '请同意条款、政策和费用',
agreeTermsPolicy: '我同意 <span onclick="onClickPrivacy()">条款、政策</span> 和费用。',
noAccountToSignUp: `还没有账号? <span onclick="onClickRegister()">注册</span>`,
registerFor: '注册账号',
registerTip: '一个多智能体画布,用于快速、趋势驱动的设计迭代。',
havenAccountToLogin: `已经有账号? <span onclick="onClickLogin()">登录</span>`,
verifyEmail: '验证您的邮箱地址',
verifyCodeHasSent: '已发送验证码到 <span>{email}</span>',
verifyCode: '请输入验证码',
verify: '验证',
resendCode: '重新发送验证码',
resendCodeIn: '重新发送验证码倒计时 {time}',
orContinueWith: '或者使用',
googleLogin: '使用 Google 登录',
wechatLogin: '使用微信登录',
},
Nuic: {
hiName: '你好,{name}。',
nuic1Title: `帮助 Fiphant 发现您空间中的 <b>'YOU'</b>。`,
nuic1Tip: `让我们设置您的个人资料。几个快速的细节将帮助 Fiphant 理解您的需求并找到您正在寻找的内容。`,
letsGo: '让我们开始Fiphant',
skip: '跳过',
next: '下一步',
nuic2Title: `您理想中 <b>家的氛围</b> 是什么?`,
loadMore: '加载更多',
nuic3Title: `您在哪里 <b>工作</b> ?您从事什么 <b>工作</b> `,
basedIn: '公司',
role: '角色',
allSet: '准备好了!',
},
Home: {
creditsNum: '积分: {num}',
newProject: '新建项目',
home: '首页',
history: '历史记录',
today: '今天',
yesterday: '昨天',
earlierChat: '更早的',
},
Input: {
placeholder: '请输入',

View File

@@ -146,8 +146,8 @@
color: #666666;
font-weight: 400;
}
.register > .right > .box > .el-form::v-deep .privacy .el-checkbox__label > span,
.login > .right > .box > .el-form::v-deep .privacy .el-checkbox__label > span {
.register > .right > .box > .el-form::v-deep .privacy .el-checkbox__label > div > span,
.login > .right > .box > .el-form::v-deep .privacy .el-checkbox__label > div > span {
text-decoration: underline;
cursor: pointer;
}
@@ -172,8 +172,8 @@
font-size: 1.6rem;
color: #666;
}
.register > .right > .box > .tip-2 > span,
.login > .right > .box > .tip-2 > span {
.register > .right > .box > .tip-2::v-deep > span,
.login > .right > .box > .tip-2::v-deep > span {
text-decoration: underline;
color: #FF7A50;
cursor: pointer;

View File

@@ -9,15 +9,15 @@
</div>
<button class="create-btn">
<span class="icon"><svg-icon name="add" size="16" /></span>
<span v-show="!isCollapse" class="text">New Project</span>
<span v-show="!isCollapse" class="text">{{ $t('Home.newProject') }}</span>
</button>
<!-- <div class="menu-item" @click="onHome">
<span class="icon"><svg-icon name="home" size="24" /></span>
<span class="title" v-show="!isCollapse">Home</span>
<span class="title" v-show="!isCollapse">{{ $t('Home.home') }}</span>
</div> -->
<div class="menu-item" @click="onHistory" :class="{ active: showHistory }">
<span class="icon"><svg-icon name="history" size="24" /></span>
<span class="title" v-show="!isCollapse">History</span>
<span class="title" v-show="!isCollapse">{{ $t('Home.history') }}</span>
<span class="icon jiantou" v-show="!isCollapse"
><svg-icon name="arrow-right" size="14" />
</span>
@@ -45,6 +45,8 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
const { t: $t } = useI18n()
const route = useRoute()
const router = useRouter()
import { useGlobalStore } from '@/stores'
@@ -57,7 +59,7 @@
const historyList = ref([
{
title: true,
name: 'Today'
name: $t('Home.today')
},
{
name: 'Conversation Item 1'
@@ -67,14 +69,14 @@
},
{
title: true,
name: 'Yesterday'
name: $t('Home.yesterday')
},
{
name: 'Conversation Item 3'
},
{
title: true,
name: 'Earlier Chat'
name: $t('Home.earlierChat')
},
{
name: 'Conversation Item 4'

View File

@@ -5,7 +5,7 @@
</span>
<p class="division"></p>
<div class="credits-box">
<span class="credits">Credits: 6000</span>
<span class="credits">{{ $t('Home.creditsNum', { num: 6000 }) }}</span>
<span class="icon" @click="onRefresh" :class="{ loading }">
<svg-icon name="refresh" size="21" />
</span>

View File

@@ -2,8 +2,8 @@
<div class="index background-pink">
<div class="header">
<p class="split"></p>
<button class="login" @click="onLogin">Log in</button>
<button class="register" @click="onRegister">Sign up</button>
<button class="login" @click="onLogin">{{ $t('Login.Login') }}</button>
<button class="register" @click="onRegister">{{ $t('Login.SignUp') }}</button>
</div>
</div>
</template>

View File

@@ -17,38 +17,42 @@
<img src="@/assets/images/login/elephant.png" />
<template v-if="!isVisible">
<div class="title">
<span>Log on to</span>
<span>{{ $t('Login.LoginTo') }}</span>
<img src="@/assets/images/logo-2.png" />
</div>
<div class="tip">A multi-agent canvas for rapid, trend driven design iteration.</div>
<div class="tip">{{ $t('Login.LoginTitle') }}</div>
<el-form :model="formData" :rules="ruleForm" label-position="top" ref="formRef">
<el-form-item label="Email" prop="email">
<el-input v-model="formData.email" placeholder="Enter your email" name="email" />
<el-form-item :label="$t('Login.email')" prop="email">
<el-input
v-model="formData.email"
:placeholder="$t('Login.enterEmail')"
name="email"
/>
</el-form-item>
<el-form-item label="Password" prop="password">
<el-form-item :label="$t('Login.password')" prop="password">
<el-input
v-model="formData.password"
placeholder="Enter your password"
:placeholder="$t('Login.enterPassword')"
type="password"
show-password
name="password"
/>
</el-form-item>
<div class="forgetPassword">
<span>forget password?</span>
<span>{{ $t('Login.forgetPassword') }}</span>
</div>
<el-form-item prop="privacy" class="privacy">
<el-checkbox v-model="formData.privacy">
I agree to the <span @click.prevent="onClickPrivacy">Terms, Policy</span> and Fees.
<div v-html="$t('Login.agreeTermsPolicy')"></div>
</el-checkbox>
</el-form-item>
<el-form-item>
<el-button class="submit" type="primary" @click="onSubmit">Log in</el-button>
<el-button class="submit" type="primary" @click="onSubmit">{{
$t('Login.Login')
}}</el-button>
</el-form-item>
</el-form>
<div class="tip-2">
Don't have an account? <span @click.prevent="onClickRegister">Sign up</span>
</div>
<div class="tip-2" v-html="$t('Login.noAccountToSignUp')"></div>
</template>
<visible-code v-else :email="formData.email" @submit="onVerifyCode" />
<other-login />
@@ -97,10 +101,6 @@
console.log(code)
router.push({ name: 'home' })
}
const onClickPrivacy = () => {}
const onClickRegister = () => {
router.push({ name: 'register' })
}
</script>
<style lang="less" scoped>

View File

@@ -1,14 +1,14 @@
<template>
<div class="other-login">
<div class="title">or continue with</div>
<div class="title">{{ $t('Login.orContinueWith') }}</div>
<div class="btns">
<el-button class="submit" @click="onGoogle">
<img src="@/assets/images/login/google.png" />
Sign in with Google
{{ $t('Login.googleLogin') }}
</el-button>
<el-button class="submit" @click="onWechat">
<img src="@/assets/images/login/wechat.png" />
Sign in with Wechat
{{ $t('Login.wechatLogin') }}
</el-button>
</div>
</div>

View File

@@ -17,38 +17,40 @@
<img src="@/assets/images/login/elephant.png" />
<template v-if="!isVisible">
<div class="title">
<span>Register for</span>
<span>{{ $t('Login.registerFor') }}</span>
<img src="@/assets/images/logo-2.png" />
</div>
<div class="tip">A multi-agent canvas for rapid, trend driven design iteration.</div>
<div class="tip">{{ $t('Login.registerTip') }}</div>
<el-form :model="formData" :rules="ruleForm" label-position="top" ref="formRef">
<el-form-item label="Name" prop="name">
<el-input name="name" v-model="formData.name" placeholder="Enter your name" />
<el-form-item :label="$t('Login.name')" prop="name">
<el-input name="name" v-model="formData.name" :placeholder="$t('Login.enterName')" />
</el-form-item>
<el-form-item label="Password" prop="password">
<el-form-item :label="$t('Login.password')" prop="password">
<el-input
name="password"
v-model="formData.password"
placeholder="Enter your password"
:placeholder="$t('Login.enterPassword')"
type="password"
show-password
/>
</el-form-item>
<el-form-item label="Email" prop="email">
<el-input name="email" v-model="formData.email" placeholder="Enter your email" />
<el-form-item :label="$t('Login.email')" prop="email">
<el-input
name="email"
v-model="formData.email"
:placeholder="$t('Login.enterEmail')"
/>
</el-form-item>
<el-form-item prop="privacy" class="privacy">
<el-checkbox v-model="formData.privacy">
I agree to the <span @click.prevent="onClickPrivacy">Terms, Policy</span> and Fees.
<div v-html="$t('Login.agreeTermsPolicy')"></div>
</el-checkbox>
</el-form-item>
<el-form-item>
<el-button class="submit" type="primary" @click="onSubmit">Register</el-button>
<el-button class="submit" type="primary" @click="onSubmit">{{ $t('Login.register') }}</el-button>
</el-form-item>
</el-form>
<div class="tip-2">
Already have an account? <span @click.prevent="onClickLogin">Log in</span>
</div>
<div class="tip-2" v-html="$t('Login.havenAccountToLogin')"></div>
</template>
<visible-code v-else :email="formData.email" @submit="onVerifyCode" />
<other-login />
@@ -99,10 +101,6 @@
console.log(code)
router.push({ name: 'nuic' })
}
const onClickPrivacy = () => {}
const onClickLogin = () => {
router.push({ name: 'login' })
}
</script>
<style lang="less" scoped>

View File

@@ -143,9 +143,11 @@
color: #666666;
font-weight: 400;
>span {
text-decoration: underline;
cursor: pointer;
>div {
>span {
text-decoration: underline;
cursor: pointer;
}
}
}
}
@@ -172,7 +174,7 @@
font-size: 1.6rem;
color: #666;
>span {
&::v-deep>span {
text-decoration: underline;
color: #FF7A50;
cursor: pointer;

View File

@@ -1,9 +1,11 @@
import i18n from '@/lang'
const t = i18n.global.t
export const validateName = (rule, value, callback) => {
var str = ""
if (!value) {
str = 'Please input the name'
str = t('Login.pleaseInputName')
} else if (value.length < 2 || value.length > 20) {
str = 'Name length must be between 2 and 20 characters'
str = t('Login.nameLengthError', { min: 2, max: 20 })
}
callback(str ? new Error(str) : undefined)
}
@@ -11,24 +13,24 @@ export const validateEmail = (rule, value, callback) => {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?$/
var str = ''
if (!value) {
str = 'Please input the email'
str = t('Login.pleaseInputEmail')
} else if (!emailRegex.test(value)) {
str = 'Please input the email again'
str = t('Login.emailFormatError')
}
callback(str ? new Error(str) : undefined)
}
export const validatePass = (rule, value, callback) => {
var str = ''
if (!value) {
str = 'Please input the password'
str = t('Login.pleaseInputPassword')
} else if (value.length < 6 || value.length > 20) {
str = 'Password length must be between 6 and 20 characters'
str = t('Login.passwordLengthError', { min: 6, max: 20 })
}
callback(str ? new Error(str) : undefined)
}
export const validatePrivacy = (rule, value, callback) => {
if (!value) {
callback(new Error('Please agree to the Terms, Policy and Fees'))
callback(new Error(t('Login.pleaseTermsPolicy')))
} else {
callback()
}

View File

@@ -1,13 +1,12 @@
<template>
<div class="visible-code">
<div class="title">Verify your email address</div>
<div class="tip">
A verification code has been sent to <span>{{ email }}</span>
</div>
<div class="title">{{ $t('Login.verifyEmail') }}</div>
<div class="tip" v-html="$t('Login.verifyCodeHasSent', { email: props.email })"></div>
<input-code @submit="onVerify" v-model="code" />
<el-button class="verify" @click="onVerify">Verify</el-button>
<p class="time" v-if="time > -1">
<span @click="onResend">Resend Code </span> in {{ timeStr }}
<el-button class="verify" @click="onVerify">{{ $t('Login.verify') }}</el-button>
<p class="time" v-if="time > 0">{{ $t('Login.resendCodeIn', { time: timeStr }) }}</p>
<p class="time" v-if="time === 0">
<span @click="onResend">{{ $t('Login.resendCode') }}</span>
</p>
</div>
</template>
@@ -45,7 +44,7 @@
clearTime()
})
onMounted(() => {
setTime()
setTime(5)
})
const onResend = () => {
if (time.value > 0) return

View File

@@ -1,16 +1,12 @@
<template>
<div class="nuic-1">
<img src="@/assets/images/nuic/nuic-1-bg.png" />
<p class="hi">Hi, Aaa.</p>
<p class="title">Help Fiphant discover the <b>'YOU'</b> in your space.</p>
<p class="tip">
Let's set up your profile. A few quick details will help Fiphant understand
<br />
your needs and find exactly what you're looking for.
</p>
<p class="hi">{{ $t('Nuic.hiName', { name: 'Aaa' }) }}</p>
<p class="title" v-html="$t('Nuic.nuic1Title')"></p>
<p class="tip" v-html="$t('Nuic.nuic1Tip')"></p>
<div class="btns">
<button class="next" @click="emit('next')">Lets go, Fiphant!</button>
<button class="skip" @click="onSkip">Skip</button>
<button class="next" @click="emit('next')">{{ $t('Nuic.letsGo') }}</button>
<button class="skip" @click="onSkip">{{ $t('Nuic.skip') }}</button>
</div>
</div>
</template>
@@ -41,7 +37,7 @@
font-weight: 500;
font-size: 4rem;
margin-bottom: 2rem;
> b {
&::v-deep > b {
font-size: 4.8rem;
}
}

View File

@@ -1,21 +1,20 @@
<template>
<div class="nuic-2">
<!-- <img src="@/assets/images/nuic/nuic-1-bg.png" /> -->
<p class="title">What's your dream <b>home vibe</b> ?</p>
<p class="title" v-html="$t('Nuic.nuic2Title')"></p>
<div class="list">
<div v-for="v in list" :key="v.id" @click="v.active = !v.active">
<img :src="v.url" draggable="false" />
<div class="active" v-show="v.active">
<span>Constructivism</span>
<span>这是一段文字</span>
</div>
</div>
</div>
<div class="btns">
<button class="more" @click="onLoadMore">
<span>Load more</span>
<span>{{ $t('Nuic.loadMore') }}</span>
<div><svg-icon name="refresh-single" size="24" /></div>
</button>
<button class="next" @click="emit('next')">Next</button>
<button class="next" @click="emit('next')">{{ $t('Nuic.next') }}</button>
</div>
</div>
</template>
@@ -35,9 +34,7 @@
{ id: 7, url: '/image/nuic/style-7.png', active: false },
{ id: 8, url: '/image/nuic/style-8.png', active: false }
])
const onLoadMore = () => {
}
const onLoadMore = () => {}
</script>
<style lang="less" scoped>
@@ -46,7 +43,7 @@
font-weight: 500;
font-size: 4rem;
margin-bottom: 6rem;
> b {
&::v-deep > b {
font-size: 4.8rem;
}
}
@@ -97,10 +94,9 @@
display: flex;
align-items: center;
justify-content: center;
>span{
> span {
margin-right: 1.2rem;
}
}
}
}

View File

@@ -1,21 +1,21 @@
<template>
<div class="nuic-3">
<p class="title"><b>Where</b> are you based? What do you <b>do</b> ?</p>
<p class="title" v-html="$t('Nuic.nuic3Title')"></p>
<div class="select-item">
<div class="title">Based in</div>
<div class="title">{{ $t('Nuic.basedIn') }}</div>
<el-select v-model="data.based">
<el-option v-for="v in data.basedList" :key="v.value" :label="v.label" :value="v.value" />
</el-select>
</div>
<div class="select-item">
<div class="title">Role</div>
<div class="title">{{ $t('Nuic.role') }}</div>
<el-select v-model="data.role">
<el-option v-for="v in data.roleList" :key="v.value" :label="v.label" :value="v.value" />
</el-select>
</div>
<div class="btns">
<button class="next" @click="emit('next')">All set!</button>
<button class="next" @click="emit('next')">{{ $t('Nuic.allSet') }}</button>
</div>
</div>
</template>