0722-editor-ja-lang

This commit is contained in:
feie9454 2025-07-22 16:51:20 +08:00
parent 6ae842176f
commit 298d1bdc7b
40 changed files with 139 additions and 49 deletions

View File

@ -1,5 +1,5 @@
<!doctype html>
<html lang="en">
<html>
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />

View File

@ -5,9 +5,10 @@ import imgs from './assets/imgs'
import { DimensionColors, DimensionName, findAllTraitByDimension, getRandomDimensionRating, getRandomTraitRating, TraitName } from './config';
import Game from './views/Game.vue';
import { computed, Ref, ref } from 'vue';
import { computed, Ref, ref, watch } from 'vue';
import Result from './views/Result.vue';
import { useI18n } from 'vue-i18n'
import { setHtmlLang } from './utils'
const pIndex = ref(0)
const result: Ref<Record<DimensionName, number>> = ref(getRandomDimensionRating())
@ -30,10 +31,16 @@ function finishGame(r: Record<DimensionName, number>, t: Record<TraitName, numbe
trait.value = t
}
import lang from './locates'
import lang, { MessageSchema } from './locates'
import Report from './views/Report.vue';
import PersonalInfo from './views/PersonalInfo.vue';
import ReportMask from './views/ReportMask.vue';
const { locale } = useI18n<{ message: MessageSchema }>({ useScope: 'global' })
// localeHTML lang
watch(locale, (newLocale) => {
setHtmlLang(newLocale)
}, { immediate: true })
const GraphDimensions = computed(() => {
const average = Object.values(result.value).reduce((acc, cur) => acc + cur, 0) / 5;
@ -43,8 +50,12 @@ const GraphDimensions = computed(() => {
const newScores = Object.entries(result.value).map(([dimName, score]) => {
const mean = average
const newScore = Math.max(8, score + sign(score - mean) * Math.abs(score - mean) ** p)
const currentLang = lang[locale.value as keyof typeof lang] ?? lang.en
return {
name_zh: lang.zh_CN.questionData.DimensionName[dimName as DimensionName],
name_zh: currentLang.questionData.DimensionName[dimName as DimensionName],
name_en: lang.en.questionData.DimensionName[dimName as DimensionName],
value: newScore,
color: DimensionColors[dimName as DimensionName],
@ -85,7 +96,7 @@ const topFiveTraits = computed(() => {
const gender = ref('_gender_')
const username = ref('_username_')
const username = ref('_userna_')
const age = ref(0)
function submitUserInfo(data: { gender: string, username: string, age: number }) {
@ -95,18 +106,24 @@ function submitUserInfo(data: { gender: string, username: string, age: number })
pIndex.value = 3
}
const showDebug = ref(1)
const showDebug = ref(-5)
</script>
<template>
<div class="main">
<div class="debug" v-if="showDebug > 0 ">
<button v-for="i in [0, 1, 2, 3, 4,5]" @click="pIndex = i">qIndex = {{ i
}}</button>
<div class="debug" v-if="showDebug > 0">
<span>Debug {{ showDebug }}</span>
<button v-for="i in [0, 1, 2, 3, 4, 5]" @click="pIndex = i">qIndex = {{ i
}}</button>
<button
@click="result = getRandomDimensionRating(); trait = getRandomTraitRating()">RandomResult</button>
<button @click="$i18n.locale = $i18n.locale === 'en' ? 'zh' : 'en'">Lang:
{{ $i18n.locale }}</button>
<span>lang: {{ $i18n.locale }}</span>
<button @click="$i18n.locale = 'zh_CN'">zh_CN </button>
<button @click="$i18n.locale = 'zh_TW'">zh_TW</button>
<button @click="$i18n.locale = 'en'">en</button>
<button @click="$i18n.locale = 'ja'">ja</button>
<button @click="$i18n.locale = 'ko'">ko</button>
</div>
<TransitionGroup name="fade">
<Home key="home" v-if="pIndex == 0" @next="pIndex = 1" />
@ -119,10 +136,12 @@ const showDebug = ref(1)
:graph="GraphDimensions" @retry="resetGame" :rarity="rarity" />
<Report key="report" v-if="pIndex == 4" :result="result" :trait="trait"
:top-five-traits="topFiveTraits" :username="username"
:graph="GraphDimensions" @retry="resetGame" :rarity="rarity" @next="pIndex++" />
<ReportMask key="report-mask" v-if="pIndex == 5" :result="result" :trait="trait"
:top-five-traits="topFiveTraits" :username="username"
:graph="GraphDimensions" @retry="resetGame" :rarity="rarity"@back="pIndex--" />
:graph="GraphDimensions" @retry="resetGame" :rarity="rarity"
@next="pIndex++" />
<ReportMask key="report-mask" v-if="pIndex == 5" :result="result"
:trait="trait" :top-five-traits="topFiveTraits" :username="username"
:graph="GraphDimensions" @retry="resetGame" :rarity="rarity"
@back="pIndex--" />
</TransitionGroup>
<img :src="imgs.logo" alt="" class="logo" @click="showDebug++"
v-if="pIndex == 0 || pIndex == 1 || pIndex == 2"

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -106,7 +106,11 @@ defineProps<{
font-size: 0.9rem;
}
}
&:lang(ja) ,&:lang(ko){
.content {
font-size: 0.7rem;
}
}
span {
height: 0;
display: block;

View File

@ -558,7 +558,6 @@ const ko: typeof zh_CN = {
button: new URL("@/assets/imgs/home/button_ko.png", import.meta.url).href,
intro: new URL("@/assets/imgs/home/intro_ko.png", import.meta.url).href,
},
// 以下為您提供的譯文,已修正格式
game: {
agree: "매우 그렇다",
disagree: "매우 그렇지 않다",
@ -622,7 +621,7 @@ const ko: typeof zh_CN = {
"Emotion_Management_Master": "감정기복 ZERO",
"Future_Prophet": "미래 각도기",
"Helmsman": "8톤트럭 운전수",
"Helmsman": "항해사", // Original had "8톤트럭 운전수", but source text had "항해사"
"Owner": "책임감 MAX",
"Strategic_Leader": "전략가 타입",
"Perfectionist": "완벽주의 ON",
@ -645,12 +644,12 @@ const ko: typeof zh_CN = {
male: "남성",
female: "여성",
},
error: { // 參照 placeholder 補全
error: {
username: "닉네임을 입력하세요",
age: "나이를 입력하세요",
gender: "성별을 선택하세요",
},
submit: new URL("@/assets/imgs/personalInfo/submit_ko.png", import.meta.url).href,
submit: new URL("@/assets/imgs/personalInfo/submit_en.png", import.meta.url).href,
},
result: {
title: "당신의 다섯가지 잠재력 (5 Potentials) 점수",
@ -674,25 +673,31 @@ const ko: typeof zh_CN = {
report: {
title: "님의 핵심 잠재력은",
dimDescription: {
Learning_Agility: dedent`
Learning_Agility: `
, . , .
. , . , .
`,
Resilience: dedent`
Resilience: `
, . .
, . , 믿 .
`,
Empathy: dedent`
Empathy: `
, . '마인드 헌터', .
, . , . 믿.
`,
Ambition: dedent`
Ambition: `
, '감히 도전하고 한계를 뛰어넘는' .
, .
, . , . , 믿.
`,
Judgement: dedent`
Judgement: `
, . .
, . , .
`
},
@ -823,22 +828,27 @@ const ja: typeof zh_CN = {
dimDescription: {
Learning_Agility: dedent`
`,
Resilience: dedent`
姿
姿
`,
Empathy: dedent`
`,
Ambition: dedent`
`,
Judgement: dedent`
`
},

View File

@ -3,6 +3,7 @@ import './assets/fonts/stylesheet.css'
import './style.scss'
import App from './App.vue'
import { createI18n } from 'vue-i18n';
import { setHtmlLang } from './utils'
import lang from './locates'
@ -32,6 +33,9 @@ if (userLang) {
console.log("Selected language:", language);
// 初始设置HTML lang
setHtmlLang(language);
const i18n = createI18n<[MessageSchema], 'en' | 'zh_CN' | 'zh_TW' | 'ja' | 'ko'>({
locale: language,
fallbackLocale: 'en',

View File

@ -6,6 +6,21 @@
* @author feie9454
*/
/**
* HTML文档的lang属性
* @param locale - i18n的locale值 ( 'zh_CN', 'en', 'ja' )
*/
export function setHtmlLang(locale: string): void {
const langMap: Record<string, string> = {
'zh_CN': 'zh-CN',
'zh_TW': 'zh-TW',
'ja': 'ja',
'ko': 'ko',
'en': 'en'
};
document.documentElement.lang = langMap[locale] || 'en';
}
/**
* Darkens a hex color by a given percentage
* @param hex - Hex color code (e.g. '#00D78D' or '00D78D')

View File

@ -149,15 +149,15 @@ function nextQuestion(i: number) {
.title {
position: absolute;
left: 10%;
top: 32%;
top: 30%;
width: 80%;
&:lang(en) {
&:lang(en),&:lang(ja),&:lang(ko) {
top: 25%;
.q-title {
width: 95%;
font-size: 1.75rem;
font-size: 1.5rem;
}
}

View File

@ -153,7 +153,7 @@ onUnmounted(() => {
@include abs-pos(85%, 4.2%);
position: relative;
cursor: pointer;
width:20%;
width:23%;
z-index: 1000;
}
@ -161,8 +161,8 @@ onUnmounted(() => {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 8px 12px;
gap: 4px;
padding: 8px 8px;
background: transparent;
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.6);

View File

@ -121,6 +121,12 @@ function submit() {
&:lang(en) {
font-size: 1.9rem;
}
&:lang(ja) {
font-size: 1.5rem;
}
&:lang(ko) {
font-size: 1.5rem;
}
}
.inputs {

View File

@ -51,12 +51,12 @@ const topFiveTraits = computed(() => {
return sortedTraits.slice(0, 5) as [[TraitName, number], ...[TraitName, number][]]
})
function jumpZh() {
/* function jumpZh() {
window.location.href = 'weixin://dl/business/?appid=wxe6d33a608a6fd9a5&path=pages/brandstorm/index&query=promotionId=9'
}
function jumpEn() {
window.location.href = 'https://brandstorm.loreal.com'
}
} */
</script>
<template>
@ -77,7 +77,7 @@ function jumpEn() {
</div>
<div class="left-title">
<img :src="imgs.icons[topDimension]" alt="">
<span v-if="$i18n.locale === 'zh'" class="zh-title"
<span v-if="$i18n.locale !== 'zh'" class="zh-title"
v-for="c in lang.zh_CN.questionData.DimensionName[topDimension].split('')">
{{ c }}</span>
<span v-if="$i18n.locale === 'en'" class="en-title">
@ -100,8 +100,6 @@ function jumpEn() {
:border-color="DimensionColors[topDimension]"
:rarity="rarity" />
<div class="imgs">
<img class="left" :src="t('report.bottomLeft')" alt=""
@click="$i18n.locale == 'zh' ? jumpZh() : jumpEn()">
<div class="right" @click="$emit('next')">
<img :src="t('report.bottomRight')" alt="" class="botton" />
@ -176,13 +174,21 @@ function jumpEn() {
text-indent: 2em;
text-wrap: pretty;
&:lang(zh) {
&[lang="zh_CN"], &[lang="zh_TW"] {
@include font(.80rem, 1.45, pre-wrap);
}
&:lang(en) {
&[lang="en"] {
@include font(.80rem, 1.43, pre-wrap);
}
&[lang="ko"] {
@include font(.75rem, 1.43, pre-wrap);
}
&[lang="ja"] {
@include font(.75rem, 1.43, pre-wrap);
}
}
}

View File

@ -175,13 +175,21 @@ function jumpEn() {
text-indent: 2em;
text-wrap: pretty;
&:lang(zh) {
&[lang="zh_CN"], &[lang="zh_TW"] {
@include font(.80rem, 1.45, pre-wrap);
}
&:lang(en) {
&[lang="en"] {
@include font(.80rem, 1.43, pre-wrap);
}
&[lang="ko"] {
@include font(.75rem, 1.43, pre-wrap);
}
&[lang="ja"] {
@include font(.75rem, 1.43, pre-wrap);
}
}
}

View File

@ -117,7 +117,8 @@ const lightProps = [{
<LightGrow class="bg" :shapes="lightProps" :animation-duration="4"
:blur-amount="60" background="#000" />
<div class="top">
<div class="title-container" :style="{ opacity: opacityDuration }" :lang="$i18n.locale">
<div class="title-container" :style="{ opacity: opacityDuration }"
:lang="$i18n.locale">
<span class="title" v-html="t('result.title')"></span>
<span class="subtitle">{{ t('result.subtitle') }}</span>
</div>
@ -125,10 +126,11 @@ const lightProps = [{
:title="`THE 5 L'Oréal DIMENSIONS`" :score-radio="1"
:subtitle="'OF POTENTIAL'" />
<Tags class="tags" :top-five-traits="topFiveTraits" :username="t('you')"
border-color="#ffffff" :style="{ opacity: opacityDuration }"
:rarity="rarity" />
<div class="slide-down" :style="{ opacity: opacityDuration }">
<Tags class="tags" :top-five-traits="topFiveTraits"
:username="t('you')" border-color="#ffffff"
:style="{ opacity: opacityDuration }" :rarity="rarity" />
<div class="slide-down" :style="{ opacity: opacityDuration }"
:lang="$i18n.locale">
<span v-html="t('result.slideDown')"></span>
<img :src="imgs.slideDown" alt="">
</div>
@ -140,9 +142,9 @@ const lightProps = [{
<img :src="t('result.slideUp')" alt="" class="slide-up-notice">
<img :src="t('result.ratingExplanation')" alt=""
class="rating-explaination" draggable="false">
<div class="actions" :lang="$i18n.locale">
<div class="actions" :lang="$i18n.locale">
<button @click="$emit('retry')">{{ t('result.actions.tryAgain')
}}</button>
}}</button>
<button @click="$emit('next')">{{
t('result.actions.generateReport') }}</button>
</div>
@ -186,11 +188,13 @@ const lightProps = [{
justify-content: space-around;
align-items: center;
gap: 1em;
&:lang(en) {
button {
font-size: .85em;
}
}
button {
text-transform: uppercase;
flex: 1;
@ -241,13 +245,20 @@ const lightProps = [{
justify-content: center;
flex-direction: column;
gap: .5em;
&:lang(en) {
font-size: .85rem;
}
&:lang(ja) {
font-size: .75rem;
}
.title {
@include font(2.2em, 1, pre-wrap, center);
text-transform: uppercase;
width: max-content;
max-width: 80vw;
}
.subtitle {
@ -264,7 +275,7 @@ const lightProps = [{
.slide-down {
@include abs-pos(50%, -2%);
@include font(1.1em, 1.4, pre-wrap, center);
display: flex;
align-items: center;
@ -273,9 +284,16 @@ const lightProps = [{
gap: 1.25em;
width: max-content;
text-transform: uppercase;
img {
width: 4em;
animation: slide-down 1.5s ease-in-out infinite;
}
&:lang(ja),
&:lang(ko) {
font-size: 0.7em;
}
}
</style>