Skip to content

Commit 0dcf334

Browse files
authored
refactor: rewrite onboarding writer to avoid break words in i18n (#12179)
* refactor: rewrite onboarding writer to avoid break words in i18n * fix: run codegen --------- Co-authored-by: Jack-Works <[email protected]>
1 parent cdfb1d2 commit 0dcf334

File tree

14 files changed

+405
-174
lines changed

14 files changed

+405
-174
lines changed
Lines changed: 61 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import { sum } from 'lodash-es'
2-
import { useState, useMemo, useEffect } from 'react'
1+
import { useState, useMemo, useEffect, type JSX } from 'react'
32
import { makeStyles } from '@masknet/theme'
43
import { Typography } from '@mui/material'
5-
import { useRenderPhraseCallbackOnDepsChange } from '@masknet/shared-base-ui'
4+
import { isNonNull } from '@masknet/kit'
65

76
const useStyles = makeStyles()((theme) => ({
87
typed: {
@@ -13,75 +12,82 @@ const useStyles = makeStyles()((theme) => ({
1312
color: theme.palette.maskColor.highlight,
1413
},
1514
},
16-
endTyping: {
15+
typing: {
1716
opacity: 0.5,
1817
},
1918
}))
2019

2120
interface OnboardingWriterProps extends withClasses<'typed' | 'endTyping'> {
22-
sentence: Array<string[] | undefined>
21+
sentence: Array<string | undefined>
2322
}
24-
let segmenter: Intl.Segmenter
2523
export function OnboardingWriter({ sentence, ...props }: OnboardingWriterProps) {
2624
const { classes, cx } = useStyles(undefined, { props })
25+
const typing = cx(classes.typing, classes.typed)
26+
const [jsx, setJsx] = useState<JSX.Element | undefined>(undefined)
2727

28-
const allChars = useMemo(() => sentence.flat().filter(Boolean).join(''), [sentence])
29-
const allCharsSegmented = useMemo(() => {
30-
return [...(segmenter ||= new Intl.Segmenter()).segment(allChars)].map((x) => x.segment)
31-
}, [allChars])
32-
const segmentCount = allCharsSegmented.length
33-
34-
const [codePointIndex, setCodePointIndex] = useState(0)
35-
const [segmentIndex, setSegmentIndex] = useState(0)
36-
useRenderPhraseCallbackOnDepsChange(() => {
37-
setCodePointIndex(0)
38-
setSegmentIndex(0)
39-
}, [sentence])
28+
const writer = useMemo(() => onBoardingWriter({ typed: classes.typed, typing }, sentence), [sentence])
4029
useEffect(() => {
4130
const timer = setInterval(() => {
42-
setSegmentIndex((segmentIndex) => {
43-
const nextSegmentIndex = segmentIndex + 1
44-
if (segmentIndex > segmentCount) {
45-
clearInterval(timer)
46-
return segmentIndex
47-
}
48-
setCodePointIndex(allCharsSegmented.slice(0, nextSegmentIndex).join('').length)
49-
return nextSegmentIndex
50-
})
31+
const next = writer.next()
32+
if (next.done) {
33+
clearInterval(timer)
34+
} else {
35+
setJsx(next.value)
36+
}
5137
}, 50)
5238

5339
return () => {
5440
clearInterval(timer)
5541
}
56-
}, [allCharsSegmented, segmentCount])
42+
}, [writer])
5743

58-
const jsx = useMemo(() => {
59-
const newJsx = []
60-
let remain = codePointIndex
61-
for (const fragment of sentence) {
62-
if (!fragment) continue
63-
if (remain <= 0) break
64-
const size = sum(fragment.map((x) => x.length))
65-
const take = Math.min(size, remain)
66-
67-
remain -= take
68-
69-
const [text, strongText] = fragment
44+
return jsx
45+
}
46+
let segmenter: Intl.Segmenter
47+
function* onBoardingWriter(className: { typed: string; typing: string }, sentences: Array<string | undefined>) {
48+
segmenter ||= new Intl.Segmenter()
49+
const previousLines: JSX.Element[] = []
50+
const currentLine: Array<{ type: 'bold' | 'normal'; text: string }> = [{ type: 'normal', text: '' }]
7051

71-
const className = cx(classes.typed, remain !== 0 ? classes.endTyping : undefined)
72-
// the trailing space gets trimmed by i18n marco
73-
if (take <= text.length) newJsx.push(<Typography className={className}>{text.slice(0, take)}</Typography>)
74-
else
75-
newJsx.push(
76-
<Typography className={className}>
77-
{text}
78-
<strong key={size}> {strongText.slice(0, take - text.length)}</strong>
79-
</Typography>,
80-
)
52+
for (const sentence of sentences.filter(isNonNull)) {
53+
const chars = [...segmenter.segment(sentence)]
54+
let currentLineJSX: JSX.Element | undefined
55+
for (let index = 0; index < chars.length; index += 1) {
56+
const char = chars[index].segment
57+
const lastPiece = currentLine.at(-1)!
58+
if (char === '*') {
59+
const nextChar = chars[index + 1]?.segment
60+
if (nextChar === '*') {
61+
currentLine.push({ type: lastPiece.type === 'normal' ? 'bold' : 'normal', text: '' })
62+
index += 1
63+
continue
64+
}
65+
}
66+
lastPiece.text += char
67+
const children = currentLine.map((x, index) =>
68+
x.type === 'normal' ? x.text : <strong key={index}>{x.text}</strong>,
69+
)
70+
currentLineJSX = (
71+
<Typography className={className.typed} key={sentence}>
72+
{children}
73+
</Typography>
74+
)
75+
yield (
76+
<>
77+
{previousLines}
78+
{
79+
<Typography className={className.typing} key={sentence}>
80+
{children}
81+
</Typography>
82+
}
83+
</>
84+
)
8185
}
82-
83-
return newJsx
84-
}, [sentence, codePointIndex])
85-
86-
return <>{jsx}</>
86+
if (currentLineJSX) {
87+
previousLines.push(currentLineJSX)
88+
currentLine.length = 0
89+
currentLine.push({ type: 'normal', text: '' })
90+
}
91+
yield <>{previousLines}</>
92+
}
8793
}

packages/mask/dashboard/pages/CreateMaskWallet/Onboarding/index.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,14 @@ export const Component = memo(function Onboarding() {
7474
window.close()
7575
}, [])
7676

77-
const sentence: string[][] = useMemo(() => {
77+
const sentence: string[] = useMemo(() => {
7878
return [
79-
[t`Creating your `, t`wallet`],
80-
[t`Generating your `, t`accounts`],
81-
[t`Encrypting your `, t`data`],
82-
[t`Your Wallet is on `, t`ready 🚀`],
79+
t`Creating your **wallet**`,
80+
t`Generating your **accounts**`,
81+
t`Encrypting your **data**`,
82+
t`Your Wallet is on **ready 🚀**`,
8383
]
84-
}, [])
84+
}, [t])
8585

8686
return (
8787
<>

packages/mask/dashboard/pages/SetupPersona/Onboarding/index.tsx

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -115,24 +115,21 @@ export const Component = memo(function Onboarding() {
115115
})
116116
}, [retry])
117117

118-
const sentence: Array<string[] | undefined> = useMemo(() => {
118+
const sentence: Array<string | undefined> = useMemo(() => {
119119
const count = params.get('count')
120120
return [
121-
[t`Creating your `, t`identity`],
122-
[t`Generating your `, t`accounts`],
123-
[t`Encrypting your `, t`data`],
124-
[t`Your Persona is on `, t`ready 🚀`],
121+
t`Creating your **identity**`,
122+
t`Generating your **accounts**`,
123+
t`Encrypting your **data**`,
124+
t`Your Persona is on **ready 🚀**`,
125125
count && !isZero(count) ?
126-
[
127-
t`You have recovered `,
128-
plural(count, {
129-
one: '# Wallet 🚀',
130-
other: '# Wallets 🚀',
131-
}),
132-
]
126+
plural(count, {
127+
one: 'You have recovered **# Wallet 🚀**',
128+
other: 'You have recovered **# Wallets 🚀**',
129+
})
133130
: undefined,
134131
]
135-
}, [])
132+
}, [t, count])
136133

137134
return (
138135
<>

packages/mask/dashboard/pages/SetupPersona/PermissionOnboarding/index.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,11 @@ export const Component = memo(function Onboarding() {
100100
window.close()
101101
}, [])
102102

103-
const sentence: string[][] = useMemo(() => {
103+
const sentence: string[] = useMemo(() => {
104104
return [
105-
[
106-
t`We are pleased to inform you that the update for X (formerly named Twitter) website has been completed. You can now continue to enjoy all the features of Mask Network as usual. Thank you for your continuous support!`,
107-
],
105+
t`We are pleased to inform you that the update for X (formerly named Twitter) website has been completed. You can now continue to enjoy all the features of Mask Network as usual. Thank you for your continuous support!`,
108106
]
109-
}, [])
107+
}, [t])
110108

111109
return (
112110
<>

packages/mask/shared-ui/locale/en-US.json

Lines changed: 17 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)