From eb6d9c2490b5939a5d4b2afb374005504e8356ca Mon Sep 17 00:00:00 2001 From: hexxa Date: Thu, 26 Aug 2021 15:20:41 +0800 Subject: [PATCH] feat(ui): enable i18n --- .../src/components/__test__/browser.test.tsx | 10 +- .../components/__test__/pane_login.test.tsx | 5 +- src/client/web/src/components/browser.tsx | 188 ++++++++++-------- src/client/web/src/components/core_state.ts | 19 +- src/client/web/src/components/pane_admin.tsx | 94 +++++---- src/client/web/src/components/pane_login.tsx | 29 +-- .../web/src/components/pane_settings.tsx | 59 ++---- src/client/web/src/components/panes.tsx | 28 +-- src/client/web/src/components/root_frame.tsx | 35 ++-- src/client/web/src/components/state_mgr.tsx | 11 +- .../web/src/components/state_updater.ts | 38 +++- src/client/web/src/components/topbar.tsx | 9 +- src/client/web/src/i18n/en_US.ts | 66 +++++- src/client/web/src/i18n/msger.ts | 4 +- src/client/web/src/i18n/zh_CN.ts | 65 +++++- 15 files changed, 408 insertions(+), 252 deletions(-) diff --git a/src/client/web/src/components/__test__/browser.test.tsx b/src/client/web/src/components/__test__/browser.test.tsx index 9cc2443..438724a 100644 --- a/src/client/web/src/components/__test__/browser.test.tsx +++ b/src/client/web/src/components/__test__/browser.test.tsx @@ -22,14 +22,8 @@ describe("Browser", () => { updater().setClients(usersCl, filesCl); const browser = new Browser({ - dirPath: coreState.browser.dirPath, - isSharing: coreState.browser.isSharing, - items: coreState.browser.items, - uploadings: coreState.browser.uploadings, - sharings: coreState.browser.sharings, - uploadFiles: coreState.browser.uploadFiles, - uploadValue: coreState.browser.uploadValue, - isVertical: coreState.browser.isVertical, + browser: coreState.browser, + msg: coreState.msg, update: (updater: (prevState: ICoreState) => ICoreState) => {}, }); diff --git a/src/client/web/src/components/__test__/pane_login.test.tsx b/src/client/web/src/components/__test__/pane_login.test.tsx index 44c876b..01e5ac3 100644 --- a/src/client/web/src/components/__test__/pane_login.test.tsx +++ b/src/client/web/src/components/__test__/pane_login.test.tsx @@ -16,9 +16,8 @@ describe("Login", () => { const coreState = newWithWorker(mockWorker); const pane = new AuthPane({ - userRole: coreState.login.userRole, - authed: coreState.login.authed, - captchaID: coreState.login.captchaID, + login: coreState.login, + msg: coreState.msg, update: (updater: (prevState: ICoreState) => ICoreState) => {}, }); diff --git a/src/client/web/src/components/browser.tsx b/src/client/web/src/components/browser.tsx index e4301a7..6bdc2bf 100644 --- a/src/client/web/src/components/browser.tsx +++ b/src/client/web/src/components/browser.tsx @@ -5,7 +5,7 @@ import FileSize from "filesize"; import { alertMsg, comfirmMsg } from "../common/env"; import { updater } from "./state_updater"; -import { ICoreState } from "./core_state"; +import { ICoreState, MsgProps } from "./core_state"; import { MetadataResp, UploadInfo } from "../client"; import { Up } from "../worker/upload_mgr"; import { UploadEntry } from "../worker/interface"; @@ -18,7 +18,7 @@ export interface Item { selected: boolean; } -export interface Props { +export interface BrowserProps { dirPath: List; isSharing: boolean; items: List; @@ -29,7 +29,11 @@ export interface Props { uploadValue: string; isVertical: boolean; +} +export interface Props { + browser: BrowserProps; + msg: MsgProps; update?: (updater: (prevState: ICoreState) => ICoreState) => void; } @@ -90,7 +94,7 @@ export class Browser extends React.Component { .deleteUpload(filePath) .then((ok: boolean) => { if (!ok) { - alertMsg(`Failed to delete uploading ${filePath}`); + alertMsg(this.props.msg.pkg.get("browser.upload.del.fail")); } return updater().refreshUploadings(); }) @@ -106,19 +110,19 @@ export class Browser extends React.Component { onMkDir = () => { if (this.state.inputValue === "") { - alertMsg("folder name can not be empty"); + alertMsg(this.props.msg.pkg.get("browser.folder.add.fail")); return; } const dirPath = getItemPath( - this.props.dirPath.join("/"), + this.props.browser.dirPath.join("/"), this.state.inputValue ); updater() .mkDir(dirPath) .then(() => { this.setState({ inputValue: "" }); - return updater().setItems(this.props.dirPath); + return updater().setItems(this.props.browser.dirPath); }) .then(() => { this.update(updater().updateBrowser); @@ -126,10 +130,10 @@ export class Browser extends React.Component { }; delete = () => { - if (this.props.dirPath.join("/") !== this.state.selectedSrc) { - alertMsg("please select file or folder to delete at first"); + if (this.props.browser.dirPath.join("/") !== this.state.selectedSrc) { + alertMsg(this.props.msg.pkg.get("browser.del.fail")); this.setState({ - selectedSrc: this.props.dirPath.join("/"), + selectedSrc: this.props.browser.dirPath.join("/"), selectedItems: Map(), }); return; @@ -141,7 +145,11 @@ export class Browser extends React.Component { } updater() - .delete(this.props.dirPath, this.props.items, this.state.selectedItems) + .delete( + this.props.browser.dirPath, + this.props.browser.items, + this.state.selectedItems + ) .then(() => { this.update(updater().updateBrowser); this.setState({ @@ -153,16 +161,16 @@ export class Browser extends React.Component { moveHere = () => { const oldDir = this.state.selectedSrc; - const newDir = this.props.dirPath.join("/"); + const newDir = this.props.browser.dirPath.join("/"); if (oldDir === newDir) { - alertMsg("source directory is same as destination directory"); + alertMsg(this.props.msg.pkg.get("browser.move.fail")); return; } updater() .moveHere( this.state.selectedSrc, - this.props.dirPath.join("/"), + this.props.browser.dirPath.join("/"), this.state.selectedItems ) .then(() => { @@ -175,11 +183,11 @@ export class Browser extends React.Component { }; gotoChild = (childDirName: string) => { - this.chdir(this.props.dirPath.push(childDirName)); + this.chdir(this.props.browser.dirPath.push(childDirName)); }; chdir = async (dirPath: List) => { - if (dirPath === this.props.dirPath) { + if (dirPath === this.props.browser.dirPath) { return; } @@ -199,7 +207,7 @@ export class Browser extends React.Component { updateProgress = (infos: Map) => { updater().setUploadings(infos); updater() - .setItems(this.props.dirPath) + .setItems(this.props.browser.dirPath) .then(() => { this.update(updater().updateBrowser); }); @@ -211,7 +219,7 @@ export class Browser extends React.Component { : this.state.selectedItems.set(itemName, true); this.setState({ - selectedSrc: this.props.dirPath.join("/"), + selectedSrc: this.props.browser.dirPath.join("/"), selectedItems: selectedItems, }); }; @@ -220,17 +228,17 @@ export class Browser extends React.Component { let newSelected = Map(); const someSelected = this.state.selectedItems.size === 0 ? true : false; if (someSelected) { - this.props.items.forEach((item) => { + this.props.browser.items.forEach((item) => { newSelected = newSelected.set(item.name, true); }); } else { - this.props.items.forEach((item) => { + this.props.browser.items.forEach((item) => { newSelected = newSelected.delete(item.name); }); } this.setState({ - selectedSrc: this.props.dirPath.join("/"), + selectedSrc: this.props.browser.dirPath.join("/"), selectedItems: newSelected, }); }; @@ -240,7 +248,7 @@ export class Browser extends React.Component { .addSharing() .then((ok) => { if (!ok) { - alertMsg("failed to enable sharing"); + alertMsg(this.props.msg.pkg.get("browser.share.add.fail")); } else { updater().setSharing(true); return this.listSharings(); @@ -256,7 +264,7 @@ export class Browser extends React.Component { .deleteSharing(dirPath) .then((ok) => { if (!ok) { - alertMsg("failed to disable sharing"); + alertMsg(this.props.msg.pkg.get("browser.share.del.fail")); } else { updater().setSharing(false); return this.listSharings(); @@ -278,13 +286,15 @@ export class Browser extends React.Component { }; render() { - const breadcrumb = this.props.dirPath.map( + const breadcrumb = this.props.browser.dirPath.map( (pathPart: string, key: number) => { return ( @@ -324,13 +338,13 @@ export class Browser extends React.Component { onClick={this.onClickUpload} className="green0-bg white-font" > - Upload Files + {this.props.msg.pkg.get("browser.upload")} @@ -345,24 +359,24 @@ export class Browser extends React.Component { onClick={() => this.delete()} className="red0-bg white-font margin-t-m margin-b-m margin-r-m" > - Delete Selected + {this.props.msg.pkg.get("browser.delete")} - {this.props.isSharing ? ( + {this.props.browser.isSharing ? ( ) : ( )} ); - const itemList = this.props.items.map((item: MetadataResp) => { + const itemList = this.props.browser.items.map((item: MetadataResp) => { const isSelected = this.state.selectedItems.has(item.name); - const dirPath = this.props.dirPath.join("/"); + const dirPath = this.props.browser.dirPath.join("/"); const itemPath = dirPath.endsWith("/") ? `${dirPath}${item.name}` : `${dirPath}/${item.name}`; @@ -404,7 +418,9 @@ export class Browser extends React.Component { className={`white-font ${isSelected ? "blue0-bg" : "grey1-bg"}`} style={{ width: "8rem", display: "inline-block" }} > - {isSelected ? "Deselect" : "Select"} + {isSelected + ? this.props.msg.pkg.get("browser.deselect") + : this.props.msg.pkg.get("browser.select")} @@ -435,7 +451,9 @@ export class Browser extends React.Component { className={`white-font ${isSelected ? "blue0-bg" : "grey1-bg"}`} style={{ width: "8rem", display: "inline-block" }} > - {isSelected ? "Deselect" : "Select"} + {isSelected + ? this.props.msg.pkg.get("browser.deselect") + : this.props.msg.pkg.get("browser.select")} @@ -443,43 +461,45 @@ export class Browser extends React.Component { ); }); - const uploadingList = this.props.uploadings.map((uploading: UploadInfo) => { - const pathParts = uploading.realFilePath.split("/"); - const fileName = pathParts[pathParts.length - 1]; + const uploadingList = this.props.browser.uploadings.map( + (uploading: UploadInfo) => { + const pathParts = uploading.realFilePath.split("/"); + const fileName = pathParts[pathParts.length - 1]; - return ( -
- - -
- {fileName} -
- {FileSize(uploading.uploaded, { round: 0 })} -  / {FileSize(uploading.size, { round: 0 })} + return ( +
+ + +
+ {fileName} +
+ {FileSize(uploading.uploaded, { round: 0 })} +  / {FileSize(uploading.size, { round: 0 })} +
-
- - -
- - -
-
-
- ); - }); + + +
+ + +
+
+
+ ); + } + ); - const sharingList = this.props.sharings.map((dirPath: string) => { + const sharingList = this.props.browser.sharings.map((dirPath: string) => { return (
@@ -501,7 +521,7 @@ export class Browser extends React.Component { }} className="grey1-bg white-font" > - Disable + {this.props.msg.pkg.get("browser.share.del")}
@@ -525,17 +545,17 @@ export class Browser extends React.Component { borderRadius: "0.5rem", }} > - Location: + {this.props.msg.pkg.get("browser.location")}
{breadcrumb}
- {this.props.uploadings.size === 0 ? null : ( + {this.props.browser.uploadings.size === 0 ? null : (
- Uploading Files + {this.props.msg.pkg.get("browser.upload.title")}
@@ -543,12 +563,12 @@ export class Browser extends React.Component {
)} - {this.props.sharings.size === 0 ? null : ( + {this.props.browser.sharings.size === 0 ? null : (
- Sharing Folders + {this.props.msg.pkg.get("browser.share.title")}
@@ -560,9 +580,7 @@ export class Browser extends React.Component {
- Name - {/* File Size - Mod Time */} + {this.props.msg.pkg.get("browser.item.title")}
diff --git a/src/client/web/src/components/core_state.ts b/src/client/web/src/components/core_state.ts index 2cd78e0..39fca7e 100644 --- a/src/client/web/src/components/core_state.ts +++ b/src/client/web/src/components/core_state.ts @@ -4,16 +4,20 @@ import BgWorker from "../worker/upload.bg.worker"; import { FgWorker } from "../worker/upload.fg.worker"; // import { Props as PanelProps } from "./root_frame"; -import { Props as BrowserProps } from "./browser"; -import { PanesProps as PanesProps } from "./panes"; -import { Props as LoginProps } from "./pane_login"; -import { Props as AdminProps } from "./pane_admin"; -import { Props as SettingsProps } from "./pane_settings"; +import { BrowserProps } from "./browser"; +import { PanesProps } from "./panes"; +import { LoginProps } from "./pane_login"; +import { AdminProps } from "./pane_admin"; +import { MsgPackage } from "../i18n/msger"; import { Item } from "./browser"; import { UploadInfo, User } from "../client"; import { initUploadMgr, IWorker } from "../worker/upload_mgr"; +export interface MsgProps { + lan: string; + pkg: Map; +} export interface ICoreState { // panel: PanelProps; isVertical: boolean; @@ -21,6 +25,7 @@ export interface ICoreState { panes: PanesProps; login: LoginProps; admin: AdminProps; + msg: MsgProps; // settings: SettingsProps; } @@ -62,6 +67,10 @@ export function initState(): ICoreState { users: Map(), roles: Set(), }, + msg: { + lan: "en_US", + pkg: MsgPackage.get("en_US"), + } }; } diff --git a/src/client/web/src/components/pane_admin.tsx b/src/client/web/src/components/pane_admin.tsx index aac4f60..3dcd800 100644 --- a/src/client/web/src/components/pane_admin.tsx +++ b/src/client/web/src/components/pane_admin.tsx @@ -1,13 +1,19 @@ import * as React from "react"; import { Map, Set } from "immutable"; -import { ICoreState } from "./core_state"; +import { alertMsg } from "../common/env"; +import { ICoreState, MsgProps } from "./core_state"; import { User, Quota } from "../client"; import { updater } from "./state_updater"; -export interface Props { +export interface AdminProps { users: Map; roles: Set; +} + +export interface Props { + admin: AdminProps; + msg: MsgProps; update?: (updater: (prevState: ICoreState) => ICoreState) => void; } @@ -18,6 +24,7 @@ export interface UserFormProps { role: string; quota: Quota; roles: Set; + msg: MsgProps; update?: (updater: (prevState: ICoreState) => ICoreState) => void; } @@ -90,7 +97,7 @@ export class UserForm extends React.Component< setPwd = () => { if (this.state.newPwd1 !== this.state.newPwd2) { - alert("2 passwords do not match, please check."); + alertMsg(this.props.msg.pkg.get("settings.pwd.notSame")); return; } @@ -98,9 +105,9 @@ export class UserForm extends React.Component< .forceSetPwd(this.state.id, this.state.newPwd1) .then((ok: boolean) => { if (ok) { - alert("password is updated"); + alertMsg(this.props.msg.pkg.get("update.ok")); } else { - alert("failed to update password"); + alertMsg(this.props.msg.pkg.get("update.fail")); } this.setState({ newPwd1: "", @@ -114,9 +121,9 @@ export class UserForm extends React.Component< .setUser(this.props.id, this.state.role, this.state.quota) .then((ok: boolean) => { if (!ok) { - alert("failed to set user"); + alertMsg(this.props.msg.pkg.get("update.fail")); } else { - alert("user is updated"); + alertMsg(this.props.msg.pkg.get("update.ok")); } return updater().listUsers(); }) @@ -130,7 +137,7 @@ export class UserForm extends React.Component< .delUser(this.state.id) .then((ok: boolean) => { if (!ok) { - alert("failed to delete user"); + alertMsg(this.props.msg.pkg.get("delete.fail")); } return updater().listUsers(); }) @@ -155,8 +162,12 @@ export class UserForm extends React.Component< }} className="bold item-name" > -
ID: {this.props.id}
-
Name: {this.props.name}
+
+ {this.props.msg.pkg.get("user.id")} {this.props.id} +
+
+ {this.props.msg.pkg.get("user.name")} {this.props.name} +
@@ -172,7 +183,7 @@ export class UserForm extends React.Component< onClick={this.delUser} className="grey1-bg white-font margin-r-m" > - Delete User + {this.props.msg.pkg.get("delete")} @@ -196,7 +207,7 @@ export class UserForm extends React.Component<
- Space Limit + {this.props.msg.pkg.get("spaceLimit")}
- Upload Speed Limit + {this.props.msg.pkg.get("uploadLimit")}
- Download Speed Limit + {this.props.msg.pkg.get("downloadLimit")}
- Update User + {this.props.msg.pkg.get("update")}
@@ -262,7 +273,7 @@ export class UserForm extends React.Component< onChange={this.changePwd1} value={this.state.newPwd1} className="black0-font margin-b-m" - placeholder="new password" + placeholder={this.props.msg.pkg.get("settings.pwd.new1")} /> @@ -279,7 +290,7 @@ export class UserForm extends React.Component< onClick={this.setPwd} className="grey1-bg white-font margin-r-m" > - Update + {this.props.msg.pkg.get("update")} @@ -328,7 +339,9 @@ export class AdminPane extends React.Component { .addRole(this.state.newRole) .then((ok: boolean) => { if (!ok) { - alert("failed to add role"); + alertMsg(this.props.msg.pkg.get("add.fail")); + } else { + alertMsg(this.props.msg.pkg.get("add.ok")); } return updater().listRoles(); }) @@ -340,7 +353,7 @@ export class AdminPane extends React.Component { delRole = (role: string) => { if ( !confirm( - "After deleting this role, some of users may not be able to login." + this.props.msg.pkg.get("role.delete.warning") // "After deleting this role, some of users may not be able to login." ) ) { return; @@ -350,7 +363,9 @@ export class AdminPane extends React.Component { .delRole(role) .then((ok: boolean) => { if (!ok) { - alert("failed to delete role"); + this.props.msg.pkg.get("delete.fail"); + } else { + this.props.msg.pkg.get("delete.ok"); } return updater().listRoles(); }) @@ -361,7 +376,7 @@ export class AdminPane extends React.Component { addUser = () => { if (this.state.newUserPwd1 !== this.state.newUserPwd2) { - alert("2 passwords do not match, please check."); + alertMsg(this.props.msg.pkg.get("settings.pwd.notSame")); return; } @@ -375,7 +390,9 @@ export class AdminPane extends React.Component { }) .then((ok: boolean) => { if (!ok) { - alert("failed to add user"); + alertMsg(this.props.msg.pkg.get("add.fail")); + } else { + alertMsg(this.props.msg.pkg.get("add.ok")); } this.setState({ newUserName: "", @@ -391,7 +408,7 @@ export class AdminPane extends React.Component { }; render() { - const userList = this.props.users.valueSeq().map((user: User) => { + const userList = this.props.admin.users.valueSeq().map((user: User) => { return (
{ name={user.name} role={user.role} quota={user.quota} - roles={this.props.roles} + roles={this.props.admin.roles} + msg={this.props.msg} update={this.props.update} />
); }); - const roleList = this.props.roles.valueSeq().map((role: string) => { + const roleList = this.props.admin.roles.valueSeq().map((role: string) => { return (
@@ -421,7 +439,7 @@ export class AdminPane extends React.Component { }} className="grey1-bg white-font margin-r-m" > - Delete + {this.props.msg.pkg.get("delete")}
@@ -434,7 +452,7 @@ export class AdminPane extends React.Component {
- Add New User + {this.props.msg.pkg.get("user.add")}
@@ -452,28 +470,28 @@ export class AdminPane extends React.Component { onChange={this.onChangeUserName} value={this.state.newUserName} className="black0-font margin-b-m" - placeholder="new user name" + placeholder={this.props.msg.pkg.get("user.name")} />
@@ -481,7 +499,7 @@ export class AdminPane extends React.Component { onClick={this.addUser} className="grey1-bg white-font margin-r-m" > - Create User + {this.props.msg.pkg.get("add")}
@@ -492,7 +510,7 @@ export class AdminPane extends React.Component {
- Users + {this.props.msg.pkg.get("admin.users")}
@@ -504,7 +522,7 @@ export class AdminPane extends React.Component {
- Add New Role + {this.props.msg.pkg.get("role.add")}
@@ -517,7 +535,7 @@ export class AdminPane extends React.Component { onChange={this.onChangeRole} value={this.state.newRole} className="black0-font margin-r-m" - placeholder="new role name" + placeholder={this.props.msg.pkg.get("role.name")} /> @@ -526,7 +544,7 @@ export class AdminPane extends React.Component { onClick={this.addRole} className="grey1-bg white-font margin-r-m" > - Create Role + {this.props.msg.pkg.get("add")} @@ -537,7 +555,7 @@ export class AdminPane extends React.Component {
- Roles + {this.props.msg.pkg.get("admin.roles")}
diff --git a/src/client/web/src/components/pane_login.tsx b/src/client/web/src/components/pane_login.tsx index 52bec36..c89e34c 100644 --- a/src/client/web/src/components/pane_login.tsx +++ b/src/client/web/src/components/pane_login.tsx @@ -1,14 +1,19 @@ import * as React from "react"; import { List } from "immutable"; -import { ICoreState } from "./core_state"; +import { ICoreState, MsgProps } from "./core_state"; import { updater } from "./state_updater"; import { alertMsg } from "../common/env"; -export interface Props { +export interface LoginProps { userRole: string; authed: boolean; captchaID: string; +} + +export interface Props { + login: LoginProps; + msg: MsgProps; update?: (updater: (prevState: ICoreState) => ICoreState) => void; } @@ -47,7 +52,7 @@ export class AuthPane extends React.Component { .login( this.state.user, this.state.pwd, - this.props.captchaID, + this.props.login.captchaID, this.state.captchaInput ) .then((ok: boolean): Promise => { @@ -85,7 +90,7 @@ export class AuthPane extends React.Component { if (ok) { this.update(updater().updateLogin); } else { - alertMsg("Failed to logout."); + alertMsg(this.props.msg.pkg.get("login.logout.fail")); } }); }; @@ -103,7 +108,7 @@ export class AuthPane extends React.Component {
@@ -114,7 +119,7 @@ export class AuthPane extends React.Component { onChange={this.changeUser} value={this.state.user} className="black0-font margin-t-m margin-b-m margin-r-m" - placeholder="user name" + placeholder={this.props.msg.pkg.get("login.username")} /> { onChange={this.changePwd} value={this.state.pwd} className="black0-font margin-t-m margin-b-m" - placeholder="password" + placeholder={this.props.msg.pkg.get("login.pwd")} />
@@ -130,7 +135,7 @@ export class AuthPane extends React.Component { onClick={this.login} className="green0-bg white-font margin-t-m margin-b-m" > - Log in + {this.props.msg.pkg.get("login.login")}
@@ -143,10 +148,10 @@ export class AuthPane extends React.Component { onChange={this.changeCaptcha} value={this.state.captchaInput} className="black0-font margin-t-m margin-b-m margin-r-m" - placeholder="captcha" + placeholder={this.props.msg.pkg.get("login.captcha")} /> @@ -156,9 +161,9 @@ export class AuthPane extends React.Component {
- + diff --git a/src/client/web/src/components/pane_settings.tsx b/src/client/web/src/components/pane_settings.tsx index 19f7718..73ba5d7 100644 --- a/src/client/web/src/components/pane_settings.tsx +++ b/src/client/web/src/components/pane_settings.tsx @@ -1,12 +1,12 @@ import * as React from "react"; -import { ICoreState } from "./core_state"; -import { AuthPane, Props as LoginProps } from "./pane_login"; +import { ICoreState, MsgProps } from "./core_state"; +import { AuthPane, LoginProps } from "./pane_login"; import { updater } from "./state_updater"; import { alertMsg } from "../common/env"; - export interface Props { login: LoginProps; + msg: MsgProps; update?: (updater: (prevState: ICoreState) => ICoreState) => void; } @@ -40,19 +40,19 @@ export class PaneSettings extends React.Component { setPwd = () => { if (this.state.newPwd1 !== this.state.newPwd2) { - alertMsg("new passwords are not same"); + alertMsg(this.props.msg.pkg.get("settings.pwd.notSame")); } else if (this.state.newPwd1 == "") { - alertMsg("new passwords can not be empty"); + alertMsg(this.props.msg.pkg.get("settings.pwd.empty")); } else if (this.state.oldPwd == this.state.newPwd1) { - alertMsg("old and new passwords are same"); + alertMsg(this.props.msg.pkg.get("settings.pwd.notChanged")); } else { updater() .setPwd(this.state.oldPwd, this.state.newPwd1) .then((ok: boolean) => { if (ok) { - alertMsg("Password is updated"); + alertMsg(this.props.msg.pkg.get("settings.pwd.updated")); } else { - alertMsg("Failed to update password"); + alertMsg(this.props.msg.pkg.get("settings.pwd.fail")); } this.setState({ oldPwd: "", @@ -64,36 +64,6 @@ export class PaneSettings extends React.Component { }; render() { - const inputs: Array = [ - , - , - , - , - ]; - return (
@@ -104,7 +74,7 @@ export class PaneSettings extends React.Component {
@@ -116,7 +86,7 @@ export class PaneSettings extends React.Component { onChange={this.changeOldPwd} value={this.state.oldPwd} className="black0-font margin-t-m margin-b-m" - placeholder="old password" + placeholder={this.props.msg.pkg.get("settings.pwd.old")} />
@@ -126,7 +96,7 @@ export class PaneSettings extends React.Component { onChange={this.changeNewPwd1} value={this.state.newPwd1} className="black0-font margin-t-m margin-b-m margin-r-m" - placeholder="new password" + placeholder={this.props.msg.pkg.get("settings.pwd.new1")} /> { onChange={this.changeNewPwd2} value={this.state.newPwd2} className="black0-font margin-t-m margin-b-m" - placeholder="new password again" + placeholder={this.props.msg.pkg.get("settings.pwd.new2")} />
@@ -148,9 +118,8 @@ export class PaneSettings extends React.Component {
diff --git a/src/client/web/src/components/panes.tsx b/src/client/web/src/components/panes.tsx index eb2d746..91151ce 100644 --- a/src/client/web/src/components/panes.tsx +++ b/src/client/web/src/components/panes.tsx @@ -2,10 +2,10 @@ import * as React from "react"; import { Set, Map } from "immutable"; import { updater } from "./state_updater"; -import { ICoreState } from "./core_state"; +import { ICoreState, MsgProps } from "./core_state"; import { PaneSettings } from "./pane_settings"; -import { AdminPane, Props as AdminPaneProps } from "./pane_admin"; -import { AuthPane, Props as AuthPaneProps } from "./pane_login"; +import { AdminPane, AdminProps } from "./pane_admin"; +import { AuthPane, LoginProps } from "./pane_login"; export interface PanesProps { displaying: string; @@ -13,8 +13,9 @@ export interface PanesProps { } export interface Props { panes: PanesProps; - login: AuthPaneProps; - admin: AdminPaneProps; + login: LoginProps; + admin: AdminProps; + msg: MsgProps; update?: (updater: (prevState: ICoreState) => ICoreState) => void; } @@ -41,14 +42,17 @@ export class Panes extends React.Component { let panesMap: Map = Map({ settings: ( - + ), login: ( ), }); @@ -57,8 +61,8 @@ export class Panes extends React.Component { panesMap = panesMap.set( "admin", ); @@ -86,7 +90,7 @@ export class Panes extends React.Component { onClick={this.closePane} className={`red0-bg white-font ${btnClass}`} > - Close + {this.props.msg.pkg.get("panes.close")} diff --git a/src/client/web/src/components/root_frame.tsx b/src/client/web/src/components/root_frame.tsx index 3f8a0d4..8f981c6 100644 --- a/src/client/web/src/components/root_frame.tsx +++ b/src/client/web/src/components/root_frame.tsx @@ -1,14 +1,18 @@ import * as React from "react"; -import { ICoreState } from "./core_state"; -import { Browser, Props as BrowserProps } from "./browser"; -import { Props as PaneLoginProps } from "./pane_login"; -import { Panes, Props as PanesProps } from "./panes"; +import { ICoreState, MsgProps } from "./core_state"; +import { Browser, BrowserProps } from "./browser"; +import { LoginProps } from "./pane_login"; +import { Panes, PanesProps } from "./panes"; +import { AdminProps } from "./pane_admin"; import { TopBar } from "./topbar"; export interface Props { browser: BrowserProps; panes: PanesProps; + admin: AdminProps; + login: LoginProps; + msg: MsgProps; update?: (updater: (prevState: ICoreState) => ICoreState) => void; } @@ -23,25 +27,24 @@ export class RootFrame extends React.Component {
- +
diff --git a/src/client/web/src/components/state_mgr.tsx b/src/client/web/src/components/state_mgr.tsx index b165e7a..a8f9ec7 100644 --- a/src/client/web/src/components/state_mgr.tsx +++ b/src/client/web/src/components/state_mgr.tsx @@ -56,7 +56,7 @@ export class StateMgr extends React.Component { }) .then((ok: boolean) => { if (!ok) { - alertMsg("failed to get captcha id"); + alertMsg(this.state.msg.pkg.get("stateMgr.cap.fail")); } else { this.update(updater().updateLogin); } @@ -114,11 +114,10 @@ export class StateMgr extends React.Component { return ( ); diff --git a/src/client/web/src/components/state_updater.ts b/src/client/web/src/components/state_updater.ts index a04b4b2..c52ab53 100644 --- a/src/client/web/src/components/state_updater.ts +++ b/src/client/web/src/components/state_updater.ts @@ -18,6 +18,8 @@ import { UploadEntry } from "../worker/interface"; import { Up } from "../worker/upload_mgr"; import { alertMsg } from "../common/env"; +import { MsgPackage } from "../i18n/msger"; + export class Updater { props: ICoreState; private usersClient: IUsersClient = new UsersClient(""); @@ -220,7 +222,11 @@ export class Updater { return resp.status === 200; }; - setUser = async (userID: string, role: string, quota: Quota): Promise => { + setUser = async ( + userID: string, + role: string, + quota: Quota + ): Promise => { const resp = await this.usersClient.setUser(userID, role, quota); return resp.status === 200; }; @@ -306,11 +312,9 @@ export class Updater { }; initIsAuthed = async (): Promise => { - return this - .isAuthed() - .then((isAuthed) => { - updater().setAuthed(isAuthed); - }); + return this.isAuthed().then((isAuthed) => { + updater().setAuthed(isAuthed); + }); }; setAuthed = (isAuthed: boolean) => { @@ -331,6 +335,21 @@ export class Updater { return resp.status === 200; }; + setLan = (lan: string) => { + switch (lan) { + case "en_US": + this.props.msg.lan = "en_US"; + this.props.msg.pkg = MsgPackage.get(lan); + break; + case "zh_CN": + this.props.msg.lan = "zh_CN"; + this.props.msg.pkg = MsgPackage.get(lan); + break; + default: + alertMsg("language package not found"); + } + }; + updateBrowser = (prevState: ICoreState): ICoreState => { return { ...prevState, @@ -358,6 +377,13 @@ export class Updater { admin: { ...prevState.admin, ...this.props.admin }, }; }; + + updateMsg = (prevState: ICoreState): ICoreState => { + return { + ...prevState, + msg: { ...prevState.msg, ...this.props.msg }, + }; + }; } export let coreUpdater = new Updater(); diff --git a/src/client/web/src/components/topbar.tsx b/src/client/web/src/components/topbar.tsx index 3c0b355..b1ecf5c 100644 --- a/src/client/web/src/components/topbar.tsx +++ b/src/client/web/src/components/topbar.tsx @@ -1,12 +1,13 @@ import * as React from "react"; -import { ICoreState } from "./core_state"; -import { Props as LoginProps } from "./pane_login"; +import { ICoreState, MsgProps } from "./core_state"; +import { LoginProps } from "./pane_login"; import { updater } from "./state_updater"; export interface State {} export interface Props { login: LoginProps; + msg: MsgProps; update?: (updater: (prevState: ICoreState) => ICoreState) => void; } @@ -57,13 +58,13 @@ export class TopBar extends React.Component { onClick={this.showSettings} className="grey1-bg white-font margin-r-m" > - Settings + {this.props.msg.pkg.get("settings")}
diff --git a/src/client/web/src/i18n/en_US.ts b/src/client/web/src/i18n/en_US.ts index 033f48d..827f9bb 100644 --- a/src/client/web/src/i18n/en_US.ts +++ b/src/client/web/src/i18n/en_US.ts @@ -1,8 +1,64 @@ import { Map } from "immutable"; -const adContent = ` -If you have any question, you can submit an issue in the github repo. But owner may be out of the office in the weekend 😎.`; - export const msgs: Map = Map({ - "loader.top.about": "关于", -}); \ No newline at end of file + "stateMgr.cap.fail": "failed to get captcha id", + "browser.upload.del.fail": "Failed to delete uploadini item", + "browser.folder.add.fail": "Folder name can not be empty", + "browser.del.fail": "Please select file or folder to delete at first", + "browser.move.fail": "Source directory is same as destination directory", + "browser.share.add.fail": "Failed to enable sharing", + "browser.share.del.fail": "Failed to disable sharing", + "browser.share.del": "Stop sharing", + "browser.share.add": "Share it", + "browser.share.title": "Sharings", + "browser.folder.name": "Folder name", + "browser.folder.add": "Add Folder", + "browser.upload": "Upload", + "browser.delete": "Delete", + "browser.paste": "Paste", + "browser.select": "Select", + "browser.deselect": "Deselect", + "browser.selectAll": "Select All", + "browser.stop": "Stop", + "browser.disable": "Disable", + "browser.location": "Location", + "browser.item.title": "Items", + "panes.close": "Close", + "login.logout.fail": "Failed to log out", + "login.username": "User Name", + "login.captcha": "Captcha", + "login.pwd": "Password", + "login.login": "Login", + "login.logout": "Logout", + "settings.pwd.notSame": "Input passwords are not identical", + "settings.pwd.empty": "Password can not be empty", + "settings.pwd.notChanged": "New Password can be identical to old password", + update: "Update", + "settings.pwd.old": "current password", + "settings.pwd.new1": "new password", + "settings.pwd.new2": "input again password", + settings: "Settings", + admin: "Admin", + "update.ok": "Succeeded to update", + "update.fail": "Failed to update", + "delete.fail": "Failed to delete", + "delete.ok": "Succeeded to delete", + delete: "Delete", + spaceLimit: "Space Limit", + uploadLimit: "Upload Speed Limit", + downloadLimit: "Download Speed Limit", + "add.fail": "Failed to create", + "add.ok": "Succeeded to create", + "role.delete.warning": + "After deleting this role, some of users may not be able to login.", + "user.id": "User ID", + "user.add": "Add User", + "user.name": "User Name", + "user.role": "User Role", + "user.password": "User Password", + add: "Add", + "admin.users": "Users", + "role.add": "Add Role", + "role.name": "Role Name", + "admin.roles": "Roles", +}); diff --git a/src/client/web/src/i18n/msger.ts b/src/client/web/src/i18n/msger.ts index 9e27600..f970b98 100644 --- a/src/client/web/src/i18n/msger.ts +++ b/src/client/web/src/i18n/msger.ts @@ -8,13 +8,13 @@ export class Msger { constructor(msgs: Map) { this.msgs = msgs; } - getMsg(key: string): string { + m(key: string): string { return this.msgs.get(key, ""); } } export class MsgPackage { - static getPkg(key: string): Map { + static get(key: string): Map { switch (key) { case "en-US": return Map(enMsgs); diff --git a/src/client/web/src/i18n/zh_CN.ts b/src/client/web/src/i18n/zh_CN.ts index 94f4f29..aa328db 100644 --- a/src/client/web/src/i18n/zh_CN.ts +++ b/src/client/web/src/i18n/zh_CN.ts @@ -1,8 +1,63 @@ import { Map } from "immutable"; -const adContent = ` -发现bug等, 可至下方github库提交issue, 不过周末可能不上班😎.`; - export const msgs: Map = Map({ - "loader.top.about": "关于", -}); \ No newline at end of file + "stateMgr.cap.fail": "获取captcha id失败", + "browser.upload.del.fail": "删除上传失败", + "browser.upload.title": "正在上传", + "browser.folder.add.fail": "文件夹名不可为空", + "browser.del.fail": "至少选择一个文件或文件夹", + "browser.move.fail": "源与目标相同", + "browser.share.add.fail": "共享失败", + "browser.share.del.fail": "删除共享失败", + "browser.share.del": "停止共享", + "browser.share.add": "开始共享", + "browser.share.title": "共享列表", + "browser.folder.name": "文件夹名", + "browser.folder.add": "添加文件夹", + "browser.upload": "上传", + "browser.delete": "删除", + "browser.paste": "粘贴", + "browser.select": "选择", + "browser.deselect": "不选", + "browser.selectAll": "选择所有", + "browser.stop": "停止", + "browser.location": "位置", + "browser.item.title": "列表", + "panes.close": "关闭", + "login.logout.fail": "登出失败", + "login.username": "用户名", + "login.captcha": "验证码", + "login.pwd": "密码", + "login.login": "登入", + "login.logout": "登出", + "settings.pwd.notSame": "两次密码不同", + "settings.pwd.empty": "密码不能为空", + "settings.pwd.notChanged": "新老密码不能相同", + update: "更新", + "settings.pwd.old": "当前密码", + "settings.pwd.new1": "新密码", + "settings.pwd.new2": "再次输入新密码", + settings: "设置", + admin: "管理", + "update.ok": "更新成功", + "update.fail": "更新失败", + "delete.fail": "删除失败", + "delete.ok": "删除成功", + delete: "删除", + spaceLimit: "空间上限", + uploadLimit: "上传速度限制", + downloadLimit: "下载速度限制", + "add.fail": "新增失败", + "add.ok": "新增成功", + "role.delete.warning": "注意删除角色后,该角色的用户可能不能登入", + "user.id": "用户ID", + "user.add": "新增用户", + "user.name": "用户名", + "user.role": "橘色", + "user.password": "密码", + add: "新增", + "admin.users": "用户列表", + "role.add": "新增角色", + "role.name": "角色名字", + "admin.roles": "角色列表", +});