feat: login i18n

This commit is contained in:
KUN1007 2023-09-24 01:05:48 +08:00
parent 506788fc76
commit e11054ed0d
9 changed files with 225 additions and 135 deletions

View file

@ -6,6 +6,10 @@ import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
import { useKUNGalgameMessageStore } from '@/store/modules/message'
const info = useKUNGalgameMessageStore()
// i18n
import { useI18n } from 'vue-i18n'
const { tm } = useI18n()
//
const props = defineProps<{
email: string
@ -37,16 +41,14 @@ const sendCode = () => {
//
useKUNGalgameUserStore().sendCode(props.email)
info.info(
'验证码已发送,您可以在邮箱中查看,注意查看垃圾邮件,如果未收到邮件,您可以在 30 秒后尝试重新发送邮箱验证码'
)
info.info(tm('AlertInfo.code.code'))
}
}
</script>
<template>
<button @click="sendCode" :disabled="isSending">
{{ isSending ? countdown : '发送验证码' }}
{{ isSending ? countdown : $tm('login.register.send') }}
</button>
</template>

View file

@ -168,6 +168,7 @@ export default {
publish: 'Confirm Publish',
draft: 'Save Draft',
},
login: {
login: {
loginTitle: 'Login',
forget: 'Forgot your password? Click here to send reset email',
@ -175,6 +176,30 @@ export default {
loginPassword: 'Password',
capture: 'Click to proceed with the human verification process',
},
overlay: {
title: 'Welcome to KUN Visual Novel Registration',
world: `The World's`,
moe: 'Cutest',
forum: 'Galgame Forum',
login: 'Login',
home: 'Welcome Back',
kun: 'KUN Visual Novel Gives You',
hug: 'The Warmest Hug',
register: 'Register',
},
register: {
title: 'Register',
name: 'username',
email: 'email',
password: 'password',
code: 'Email verification code',
send: 'Send code',
click: 'Clicking Register means you have agreed to our',
agreement: 'User Agreement',
and: 'and',
privacy: 'Privacy Policy',
},
},
// 非页面组件这里统一用大驼峰
ComponentAlert: {
confirm: 'OK',
@ -189,8 +214,6 @@ export default {
},
login: {
success: 'Login Successfully! Welcome to KUN Visual Novel ~ ',
emptyUsername: 'Username cannot be empty',
emptyPassword: 'Password cannot be empty',
invalidUsername:
'Invalid username. Username should be 1 to 17 characters long and can include: Chinese characters, English letters, numbers, underscore, and tilde (~)',
invalidPassword:
@ -206,5 +229,8 @@ export default {
hint4: `Za~~~ko~♡ zako~♡ Just you wait, you'll regret it in the end`,
answer: 'Answer',
},
code: {
code: `The verification code has been sent. You can check it in your email. Please check your spam folder. If you haven't received the email, you can try to resend the email verification code after 30 seconds.`,
},
},
}

View file

@ -167,6 +167,7 @@ export default {
publish: '确认发布',
draft: '保存草稿',
},
login: {
login: {
loginTitle: '登录',
forget: '忘记密码? 点击发送重置邮件',
@ -174,6 +175,30 @@ export default {
loginPassword: '密码',
capture: '点击进行人机身份验证',
},
overlay: {
title: '欢迎注册 KUNgalgame',
world: `世界上最`,
moe: '萌',
forum: '的 Galgame 论坛',
login: '登录',
home: '欢迎回家',
kun: 'KUNgalgame 给你',
hug: '最温暖的拥抱',
register: '注册',
},
register: {
title: '注册',
name: '用户名',
email: '邮箱',
password: '密码',
code: '邮箱验证码',
send: '发送验证码',
click: '点击注册表示您已经同意我们的',
agreement: '用户协议',
and: '和',
privacy: '隐私政策',
},
},
// 非页面组件这里统一用大驼峰
ComponentAlert: {
confirm: '确定',
@ -188,8 +213,6 @@ export default {
},
login: {
login: '登陆成功!欢迎来到 鲲 Galgame ~ ',
emptyUsername: '用户名不可为空',
emptyPassword: '密码不可为空',
invalidUsername:
'非法的用户名,用户名为 1 到 17 位,可以包含:中文、英文、数字、下划线、波浪线',
invalidPassword:
@ -205,5 +228,8 @@ export default {
hint4: '杂~~~鱼~♡杂鱼~♡你就看吧,最后害的还是你自己',
answer: '答案',
},
code: {
code: '验证码已发送,您可以在邮箱中查看,注意查看垃圾邮件,如果未收到邮件,您可以在 30 秒后尝试重新发送邮箱验证码',
},
},
}

View file

@ -36,6 +36,7 @@
width: 100%;
/* 头部的颜色 */
background-color: var(--kungalgame-trans-blue-0);
border-radius: 7px 7px 0 0;
align-items: center;
span:nth-child(1) {
font-family: serif;

View file

@ -70,6 +70,7 @@ const navBar: nav[] = [
height: 100%;
width: 120px;
background-color: var(--kungalgame-trans-pink-0);
border-radius: 0 0 0 7px;
border-right: 1px solid var(--kungalgame-blue-4);
box-sizing: border-box;
display: flex;

View file

@ -38,19 +38,28 @@ const handleClickRegister = () => {
<div class="overlay">
<div class="panel left">
<h2>
欢迎注册 KUNgalgame <br /><br /> 世界上最<span></span>
galgame 论坛
{{ $tm('login.overlay.title') }}<br /><br />
{{ $tm('login.overlay.world') }}
<span>{{ $tm('login.overlay.moe') }}</span>
{{ $tm('login.overlay.forum') }}
</h2>
<br />
<button class="btn" @click="handleClickSignIn">登陆</button>
<button class="btn" @click="handleClickSignIn">
{{ $tm('login.overlay.login') }}
</button>
</div>
<div class="panel right">
<h2>
欢迎回家 <br />
{{ $tm('login.overlay.home') }}
<br />
KUNgalgame 给你最温暖的拥抱
<br />
{{ $tm('login.overlay.kun') }}
<br />
{{ $tm('login.overlay.hug') }}
</h2>
<button class="btn" @click="handleClickRegister">注册</button>
<button class="btn" @click="handleClickRegister">
{{ $tm('login.overlay.register') }}
</button>
</div>
</div>
</div>
@ -98,45 +107,29 @@ const handleClickRegister = () => {
width: 100%;
}
.container.active .login {
.container.active {
.login {
transform: translateX(100%);
}
.container.active .register {
.register {
animation: show 0.6s;
opacity: 1;
transform: translateX(100%);
z-index: 5;
}
@keyframes show {
0%,
49.99% {
opacity: 0;
z-index: 1;
}
50%,
100% {
opacity: 1;
z-index: 5;
}
}
.container.active .container-overlay {
.container-overlay {
transform: translateX(-100%);
}
.container.active .overlay {
.overlay {
transform: translateX(50%);
}
.container.active .left {
.left {
transform: translateX(0);
}
.container.active .right {
.right {
transform: translateX(20%);
}
}
.container-overlay {
height: 100%;
@ -155,55 +148,6 @@ const handleClickRegister = () => {
transform: translateX(0);
transition: transform 0.6s ease-in-out;
width: 200%;
}
.btn {
position: absolute;
bottom: 7%;
border-radius: 50px;
background-color: var(--kungalgame-trans-white-5);
border: 1px solid var(--kungalgame-blue-4);
color: var(--kungalgame-blue-4);
cursor: pointer;
font-size: 0.9em;
letter-spacing: 0.1rem;
padding: 0.6rem 4rem;
text-transform: uppercase;
transition: transform 80ms ease-in;
overflow: hidden;
white-space: nowrap;
}
.btn:hover {
background-color: var(--kungalgame-blue-4);
color: var(--kungalgame-white);
}
/* 交互页面的盒子 */
.panel {
align-items: center;
display: flex;
flex-direction: column;
height: 100%;
justify-content: space-between;
position: absolute;
text-align: center;
top: 0;
transform: translateX(0);
transition: transform 0.6s ease-in-out;
width: 50%;
background-color: var(--kungalgame-trans-white-5);
}
.btn {
/* 红色按钮距离底部的距离 */
position: absolute;
bottom: 7%;
background-color: var(--kungalgame-red-0);
border: 1px solid var(--kungalgame-red-4);
color: var(--kungalgame-red-4);
}
.btn:hover {
background-color: var(--kungalgame-red-4);
color: var(--kungalgame-white);
}
h2 {
margin-top: 150px;
@ -225,12 +169,64 @@ h2 span {
right: 0;
transform: translateX(0);
}
}
.btn:active {
/* 交互页面的盒子 */
.panel {
align-items: center;
display: flex;
flex-direction: column;
height: 100%;
justify-content: space-between;
position: absolute;
text-align: center;
top: 0;
transform: translateX(0);
transition: transform 0.6s ease-in-out;
width: 50%;
background-color: var(--kungalgame-trans-white-5);
}
.btn {
width: 150px;
position: absolute;
border-radius: 50px;
cursor: pointer;
font-size: 15px;
letter-spacing: 2px;
padding: 7px 0px;
text-transform: uppercase;
transition: all 0.2s;
overflow: hidden;
white-space: nowrap;
/* 红色按钮距离底部的距离 */
position: absolute;
bottom: 10%;
background-color: var(--kungalgame-red-0);
border: 1px solid var(--kungalgame-red-4);
color: var(--kungalgame-red-4);
&:hover {
background-color: var(--kungalgame-red-4);
color: var(--kungalgame-white);
}
&:active {
transform: scale(0.95);
}
}
.btn:focus {
outline: none;
@keyframes show {
0%,
49.99% {
opacity: 0;
z-index: 1;
}
50%,
100% {
opacity: 1;
z-index: 5;
}
}
</style>

View file

@ -4,6 +4,8 @@ import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
import { useRouter } from 'vue-router'
// 使
import { useKUNGalgameMessageStore } from '@/store/modules/message'
//
import message from '@/components/alert/Message'
//
const Capture = defineAsyncComponent(
@ -38,7 +40,6 @@ const handleVerify = (result: boolean) => {
if (result) {
//
isShowValidate.value = false
info.info(tm('AlertInfo.capture.success'))
isCaptureComplete.value = true
}
}
@ -47,11 +48,11 @@ const isEmptyInput = (): boolean => {
//
if (!loginForm.name.trim()) {
//
info.info(tm('AlertInfo.login.emptyUsername'))
message('Username cannot be empty', '用户名不可为空', 'warn')
return false
} else if (!loginForm.password.trim()) {
//
info.info(tm('AlertInfo.login.emptyPassword'))
message('Password cannot be empty', '密码不可为空', 'warn')
return false
} else {
return true
@ -86,7 +87,11 @@ const handleLogin = () => {
}
//
if (!isCaptureComplete.value) {
info.info(tm('AlertInfo.capture.click'))
message(
'Please click above to complete the human verification',
'请点击上方完成人机身份验证',
'warn'
)
return
}
//
@ -110,29 +115,29 @@ const handleLogin = () => {
:isShowValidate="isShowValidate"
/>
<div class="form">
<h2 class="title">{{ $tm('login.loginTitle') }}</h2>
<h2 class="title">{{ $tm('login.login.loginTitle') }}</h2>
<input
v-model="loginForm.name"
type="text"
:placeholder="($tm('login.loginUsername') as string)"
:placeholder="($tm('login.login.loginUsername') as string)"
class="input"
/>
<input
v-model="loginForm.password"
type="password"
:placeholder="($tm('login.loginPassword') as string)"
:placeholder="($tm('login.login.loginPassword') as string)"
class="input"
/>
<!-- 忘记密码 -->
<span class="forget">{{ $tm('login.forget') }}</span>
<span class="forget">{{ $tm('login.login.forget') }}</span>
<span @click="isShowValidate = true" class="capture">{{
$tm('login.capture')
$tm('login.login.capture')
}}</span>
<!-- 点击登录 -->
<button @click="handleLogin" class="btn" type="submit">
{{ $tm('login.loginTitle') }}
{{ $tm('login.login.loginTitle') }}
</button>
</div>
</div>
@ -199,6 +204,7 @@ const handleLogin = () => {
}
.btn {
width: 150px;
position: absolute;
bottom: 10%;
border-radius: 50px;
@ -208,7 +214,7 @@ const handleLogin = () => {
cursor: pointer;
font-size: 15px;
letter-spacing: 2px;
padding: 7px 50px;
padding: 7px 0px;
text-transform: uppercase;
transition: all 0.2s;
overflow: hidden;

View file

@ -1,9 +1,8 @@
<!--
TODO: 注册表单未完成注册逻辑未完成发送验证码的逻辑未完成i18n 未完成
-->
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
// 使
import { useKUNGalgameMessageStore } from '@/store/modules/message'
//
import message from '@/components/alert/Message'
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
@ -16,6 +15,11 @@ import {
import Code from '@/components/verification-code/Code.vue'
import Capture from '@/components/capture/Capture.vue'
// i18n
import { useI18n } from 'vue-i18n'
const { tm } = useI18n()
const info = useKUNGalgameMessageStore()
const router = useRouter()
const isShowValidate = ref(false)
const isCaptureComplete = ref(false)
@ -83,6 +87,7 @@ const isValidInput = (): boolean => {
const handleSendCode = () => {
//
if (!isValidInput()) {
message('Form cannot be empty', '表单不可为空', 'warn')
return
}
@ -99,10 +104,20 @@ const handleSendCode = () => {
const handleRegister = () => {
if (!isSendCode.value) {
message(
'Need to send an email verification code',
'需要发送邮箱验证码',
'warn'
)
return
}
if (!registerForm.code.trim()) {
message(
'Email verification code cannot be empty',
'邮箱验证码不可为空',
'warn'
)
return
}
@ -124,6 +139,7 @@ const handleRegister = () => {
if (res.code === 200) {
router.push('/')
message('Register successfully!', '注册成功!', 'success')
info.info(tm('AlertInfo.login.success'))
} else {
}
})
@ -146,13 +162,13 @@ const handleRegister = () => {
<!-- 注册表单 -->
<div class="form">
<!-- 标题 -->
<h2 class="title">注册</h2>
<h2 class="title">{{ $tm('login.register.title') }}</h2>
<div class="container" v-for="item in registerFormItem" :key="item.index">
<input
v-model="registerForm[item.value]"
:type="item.type"
:placeholder="item.placeholder"
:placeholder="`${$tm(`login.register.${item.placeholder}`)}`"
:class="item.class"
/>
</div>
@ -165,14 +181,24 @@ const handleRegister = () => {
/>
<!-- 注册按钮 -->
<button @click="handleRegister" class="btn" type="submit">注册</button>
<button @click="handleRegister" class="btn" type="submit">
{{ $tm('login.register.title') }}
</button>
<!-- 用户协议提示等 -->
<span class="user-agreement">
点击注册表示您已经同意我们的
<router-link to="/licence"><span>用户协议</span></router-link>
<router-link to="/privacy"><span>隐私政策</span></router-link>
{{ $tm('login.register.click') }}
<!-- 用户协议和隐私政策 -->
<div class="licence">
<router-link to="/licence">
<span>{{ $tm('login.register.agreement') }}</span>
</router-link>
{{ $tm('login.register.and') }}
<router-link to="/privacy">
<span>{{ $tm('login.register.privacy') }}</span>
</router-link>
</div>
</span>
</div>
</div>
@ -246,9 +272,15 @@ const handleRegister = () => {
color: var(--kungalgame-red-4);
font-style: oblique;
}
.licence {
display: flex;
justify-content: center;
}
}
.btn {
width: 150px;
position: absolute;
bottom: 10%;
border-radius: 50px;
@ -258,7 +290,7 @@ const handleRegister = () => {
cursor: pointer;
font-size: 15px;
letter-spacing: 2px;
padding: 7px 50px;
padding: 7px 0;
text-transform: uppercase;
transition: all 0.2s;
margin-top: 30px;

View file

@ -11,28 +11,28 @@ export const registerFormItem: RegisterFormItem[] = [
index: 1,
value: 'name',
type: 'text',
placeholder: '用户名',
placeholder: 'name',
class: 'input',
},
{
index: 2,
value: 'email',
type: 'email',
placeholder: '邮箱',
placeholder: 'email',
class: 'input',
},
{
index: 3,
value: 'password',
type: 'text',
placeholder: '密码',
placeholder: 'password',
class: 'input',
},
{
index: 4,
value: 'code',
type: 'text',
placeholder: '邮箱验证码',
placeholder: 'code',
class: 'input',
},
]