Skip to content

Commit

Permalink
i18n
Browse files Browse the repository at this point in the history
  • Loading branch information
Slouchwind committed Jun 19, 2023
1 parent 418914a commit a0f9be9
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 40 deletions.
123 changes: 123 additions & 0 deletions components/i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
export type i18nContents = {
[x: string]: {
'zh-CN': string,
'zh-TW': string,
[x: string]: string,
}
}

export function fillBlank(i18n: string, ...fills: (string | undefined)[]): string {
let text = i18n;
fills.forEach((v, i) => text = text.replace(`$${i}`, v || ''));
return text;
}

export const info: i18nContents = {
title: {
'zh-CN': '学生信息',
'zh-TW': '學生信息',
},
student: {
'zh-CN': '学生',
'zh-TW': '學生',
},
allStudents: {
'zh-CN': '所有学生',
'zh-TW': '所有學生',
},
selectStudents: {
'zh-CN': '请选择学生。',
'zh-TW': '請選擇學生。',
},
}

export const chat: i18nContents = {
title: {
'zh-CN': '聊天编辑',
'zh-TW': '聊天編輯',
},
student: {
'zh-CN': '学生',
'zh-TW': '學生',
},
allStudents: {
'zh-CN': '所有学生',
'zh-TW': '所有學生',
},
selectStudents: {
'zh-CN': '请选择学生。',
'zh-TW': '請選擇學生。',
},
'+': {
'zh-CN': '添加',
'zh-TW': '添加',
},
'-': {
'zh-CN': '去除',
'zh-TW': '去除',
},
idPromptTitle: {
'zh-CN': '输入Id',
'zh-TW': '輸入Id',
},
idPromptInfo: {
'zh-CN': '请输入需要在列表$0的学生的Id',
'zh-TW': '請輸入需要在列表$0的學生的Id',
},
error: {
'zh-CN': '错误',
'zh-TW': '錯誤',
},
sameStudent: {
'zh-CN': '已有此学生',
'zh-TW': '已有此學生',
},
withoutStudent: {
'zh-CN': '列表中无此学生',
'zh-TW': '列表中無此學生',
},
sendMsgStudent: {
'zh-CN': '发送学生消息',
'zh-TW': '發送學生消息',
},
sendMsgSensei: {
'zh-CN': '发送老师消息',
'zh-TW': '發送老師消息',
},
sendMsgInfo: {
'zh-CN': '请输入需要发送$0$1的$2',
'zh-TW': '請輸入需要發送$0$1的$2',
},
sendMsgStudentInfo: {
'zh-CN': '的',
'zh-TW': '的',
},
sendMsgSenseiInfo: {
'zh-CN': '给',
'zh-TW': '給',
},
text: {
'zh-CN': '消息',
'zh-TW': '消息',
},
img: {
'zh-CN': '图片链接',
'zh-TW': '圖片鏈接',
},
undefinedStudent: {
'zh-CN': '$0的学生Id不存在',
'zh-TW': '$0的學生Id不存在',
},
up: {
'zh-CN': '上传',
'zh-TW': '上傳',
},
down: {
'zh-CN': '下载',
'zh-TW': '下載',
},
jsonFile: {
'zh-CN': 'JSON文件',
'zh-TW': 'JSON文件',
},
}
4 changes: 1 addition & 3 deletions components/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ export default function MainNode({ children }: { children: React.ReactNode }) {
<MomoTalkIcon />
<p className={styles.MTText}>MomoTalk</p>
</div>
<p id={styles.right} onClick={() => {

}}>X</p>
<p id={styles.right}>X</p>
</div>
<div id={styles.MTContents}>
<div id={styles.MTLeftBar}>
Expand Down
4 changes: 2 additions & 2 deletions components/students/studentsMethods.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { fileInfo, schaleInfo, studentsJson, studentInfo } from './students';

export async function getStudentsJson(): Promise<studentsJson> {
export async function getStudentsJson(locale:string): Promise<studentsJson> {
const fileJson: fileInfo[] = await fetch('../students.json').then(r => r.json());
const schaleJson: schaleInfo[] = await fetch('https://schale.gg/data/cn/students.min.json').then(r => r.json());
const schaleJson: schaleInfo[] = await fetch(`https://schale.gg/data/${locale.slice(3).toLowerCase()}/students.min.json`).then(r => r.json());
return { fileJson, schaleJson };
}

Expand Down
4 changes: 4 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ const nextConfig = {
sassOptions: {
includePaths: [path.join(__dirname, 'styles')],
},
i18n: {
locales: ['zh-CN', 'zh-TW'],
defaultLocale: 'zh-CN'
}
}

module.exports = nextConfig;
75 changes: 45 additions & 30 deletions pages/chat.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
//Components
import { NextSeo } from 'next-seo';
import { useRouter } from 'next/router';
import MainNode from '@/components/main';
import Student, { AllStudentsIcon } from '@/components/students/student';
import Repeat from '@/components/repeat';
import ImgCol from '@/components/imgCol';

//Styles
import styles from '@/styles/Chat.module.scss';
Expand All @@ -12,10 +15,9 @@ import getTitle from '@/components/title';
import { studentsJson } from '@/components/students/students';
import { getStudentInfo, getStudentsJson, getStuSenText } from '@/components/students/studentsMethods';
import Window, { AllWindows, AllWindow, getWindowFun } from '@/components/window';
import Repeat from '@/components/repeat';
import { setStateFun, getClassState } from '@/components/extraReact';
import ImgCol from '@/components/imgCol';
import { downloadFile, uploadFile } from '@/components/loadFile';
import { chat, fillBlank, i18nContents } from '@/components/i18n';

const StatesContext = createContext<{
allWindow: AllWindow;
Expand All @@ -34,6 +36,8 @@ const SendMessageFunContext = createContext<(
type?: MessageData['type'],
) => void>(() => { });

const loContext = createContext<string>('zh-CN');

interface MsgProps {
msg: MessageProps['msg'];
type: MessageData['type'];
Expand Down Expand Up @@ -128,11 +132,12 @@ interface SenderState {

function Sender({ id }: SenderState) {
const sendMessageFun = useContext(SendMessageFunContext);
const lo = useContext(loContext);
return (
<img
src={`/api/icon/chat?fill=${getStuSenText(id, '4c5a6e', '4a89ca')}`}
alt={`${id} send icon`}
title={getStuSenText(id, '发送学生消息', '发送老师消息')}
title={getStuSenText(id, chat.sendMsgStudent[lo], chat.sendMsgSensei[lo])}
onClick={() => sendMessageFun(id)}
onContextMenu={e => {
e.preventDefault();
Expand All @@ -148,14 +153,12 @@ interface LoaderState {

function Loader({ type }: LoaderState) {
const { chatState, setChatState } = useContext(StatesContext);
const lo = useContext(loContext);
return (
<img
src={`/api/icon/${type}load?fill=000`}
alt={`${type}load icon`}
title={{
'up': '上传',
'down': '下载'
}[type] + 'JSON文件'}
title={chat[type][lo] + chat.jsonFile[lo]}
onClick={() => {
if (type === 'up') uploadFile(e => {
const result = e.target?.result;
Expand Down Expand Up @@ -183,8 +186,9 @@ function ChatEditorBar() {

function Content() {
const { listState } = useContext(StatesContext);
const lo = useContext(loContext);
if (!listState.studentsJson) return null;
if (listState.student === 0) return (<p>请选择学生。</p>);
if (listState.student === 0) return (<p>{chat.selectStudents[lo]}</p>);
return (
<div id={styles.content}>
<MessagesGroup />
Expand Down Expand Up @@ -225,6 +229,8 @@ interface SendMessageArg {
}

export default function Info() {
const { locale, defaultLocale = 'zh-CN' } = useRouter();
const lo = locale || defaultLocale;
const [listState, setListState] = getClassState(useState<ListState>({
student: 0,
studentsList: [10000, 10002],
Expand Down Expand Up @@ -252,10 +258,10 @@ export default function Info() {
if (chat !== undefined) {
setChatState({ studentsChat: JSON.parse(chat) });
}
}, [])
}, []);

useEffect(() => {
getStudentsJson().then(r => setListState({ studentsJson: { data: r } }));
getStudentsJson(locale || defaultLocale).then(r => setListState({ studentsJson: { data: r } }));
}, []);

//Window
Expand All @@ -278,19 +284,18 @@ export default function Info() {
const SendMessage = new Window<SendMessageArg>('SendMessage');

useEffect(() => {
const IdPromptTypeText = { '+': '添加', '-': '去除' };
addNewWindow(IdPrompt, (zIndex, id, display, { studentsList, type }, all) => (
<IdPrompt.Component
title='输入Id'
title={chat.idPromptTitle[lo]}
closeWindow={() => closeWindow(all, id)}
element={close => (<>
<p>请输入需要在列表{IdPromptTypeText[type || '+']}的学生的Id</p>
<p>{fillBlank(chat.idPromptInfo[lo], chat[type || '+'][lo])}</p>
<input type='number' onChange={e => { idPromptInputRef.current = Number(e.target.value); }} />
<button
onClick={() => {
if (type === '+') {
if (studentsList?.includes(idPromptInputRef.current)) {
openWindow(all, TextAlert, { title: '错误', elem: '已有此学生' });
openWindow(all, TextAlert, { title: chat.error[lo], elem: chat.sameStudent[lo] });
}
else {
studentsList = studentsList?.concat(idPromptInputRef.current);
Expand All @@ -301,7 +306,7 @@ export default function Info() {
}
else if (type === '-') {
if (!studentsList?.includes(idPromptInputRef.current)) {
openWindow(all, TextAlert, { title: '错误', elem: '列表中无此学生' });
openWindow(all, TextAlert, { title: chat.error[lo], elem: chat.withoutStudent[lo] });
}
else {
const i = studentsList.indexOf(idPromptInputRef.current);
Expand All @@ -312,7 +317,7 @@ export default function Info() {
}
}
}}
>{IdPromptTypeText[type || '+']}</button>
>{chat[type || '+'][lo]}</button>
</>)}
zIndex={zIndex}
display={display}
Expand All @@ -330,20 +335,28 @@ export default function Info() {
display={display}
/>
));
const MsgInfoText = { 'text': '消息', 'img': '图片链接' };
addNewWindow(SendMessage, (zIndex, winId, display, { studentsJson, selId, studentsChat, id, type }, all) => (
<SendMessage.Component
title={getStuSenText(id, '发送学生消息', '发送老师消息')}
title={getStuSenText(id, chat.sendMsgStudent[lo], chat.sendMsgSensei[lo])}
closeWindow={() => closeWindow(all, winId)}
element={close => {
sendMessageInputRef.current = '';
return (<>
<p>请输入需要发送{getStuSenText(id, '的', '给')}{
getStudentInfo(
studentsJson?.data || {},
selId || 10000
).schale?.Name
}{MsgInfoText[type]}</p>
<p>
{fillBlank(
chat.sendMsgInfo[lo],
getStuSenText(
id,
chat.sendMsgStudentInfo[lo],
chat.sendMsgSenseiInfo[lo]
),
getStudentInfo(
studentsJson?.data || {},
selId || 10000
).schale?.Name,
chat[type][lo]
)}
</p>
{type === 'text' && <textarea onChange={e => sendMessageInputRef.current = e.target.value} />}
{type === 'img' && <input onChange={e => sendMessageInputRef.current = e.target.value} />}
<button
Expand All @@ -370,8 +383,8 @@ export default function Info() {
if (listState.studentsJson?.data.schaleJson === undefined) return;
if (getStudentInfo(listState.studentsJson.data, id).schale?.CollectionTexture !== undefined) return;
openWindow(allWindow.all, TextAlert, {
title: '错误',
elem: `${id}的学生Id不存在`,
title: chat.error[lo],
elem: fillBlank(chat.undefinedStudent[lo], String(id)),
fun() {
openWindow(allWindow.all, IdPrompt, {
studentsList: listState.studentsList,
Expand All @@ -388,12 +401,12 @@ export default function Info() {
return (
<MainNode>
<NextSeo
title={getTitle('聊天编辑')}
title={getTitle(chat.title[lo])}
/>
<AllWindows zIndex={999} allWindow={allWindow} />
<div id={styles.infoBar}>
<div id={styles.title}>
<p id={styles.left}>学生({listState.studentsList?.length})</p>
<p id={styles.left}>{chat.student[lo]}({listState.studentsList?.length})</p>
<div id={styles.right}>
<p onClick={_ => {
openWindow(allWindow.all, IdPrompt, {
Expand All @@ -412,7 +425,7 @@ export default function Info() {
<div style={{ height: 70 }} />
<div id={styles.all}>
<AllStudentsIcon />
<p>所有学生</p>
<p>{chat.allStudents[lo]}</p>
</div>
<div id='students'>
{listState.studentsJson && listState.studentsList &&
Expand Down Expand Up @@ -453,7 +466,9 @@ export default function Info() {
type,
});
}}>
<Content />
<loContext.Provider value={lo}>
<Content />
</loContext.Provider>
</SendMessageFunContext.Provider>
</StatesContext.Provider>
</div>
Expand Down
Loading

1 comment on commit a0f9be9

@vercel
Copy link

@vercel vercel bot commented on a0f9be9 Jun 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.