feature: full i18n support

This commit is contained in:
kkzzhizhou 2021-11-29 13:56:44 +08:00
parent 933c74804c
commit 6433c4c72a
10 changed files with 64 additions and 52 deletions

1
.gitignore vendored
View file

@ -8,6 +8,7 @@ package-lock.json
# yarn # yarn
yarn.lock yarn.lock
yarn-error.log
*.js.map *.js.map

View file

@ -30,7 +30,6 @@
}, },
"dependencies": { "dependencies": {
"@mui/icons-material": "^5.2.0", "@mui/icons-material": "^5.2.0",
"@react-navigation/native": "^6.0.6",
"i18next": "^21.5.2", "i18next": "^21.5.2",
"i18next-browser-languagedetector": "^6.1.2", "i18next-browser-languagedetector": "^6.1.2",
"node": "^16.10.0", "node": "^16.10.0",
@ -38,10 +37,8 @@
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-emoji-render": "^1.2.4", "react-emoji-render": "^1.2.4",
"react-hook-form": "^7.20.2",
"react-i18next": "^11.14.2", "react-i18next": "^11.14.2",
"react-markdown": "^7.1.0", "react-markdown": "^7.1.0",
"react-navigation": "^4.4.4",
"react-tabs": "^3.2.2" "react-tabs": "^3.2.2"
} }
} }

View file

@ -17,5 +17,17 @@
"API Error: Please check credentials": "API错误请检查凭据", "API Error: Please check credentials": "API错误请检查凭据",
"Resyncing, please try again": "重新同步失败,请稍后再试", "Resyncing, please try again": "重新同步失败,请稍后再试",
"Add!": "已添加", "Add!": "已添加",
"Loading....": "加载中...." "Loading....": "加载中....",
"Deleted!": "已删除!",
"Edit!": "已修改!",
"running cron": "正在运行定时任务",
"Checked!": "已完成",
"Un-Checked!": "取消完成状态",
"Plus!": "+1",
"Minus :(": "-1",
"Cost!": "消费成功",
"Add Daily Task": "添加每日任务",
"Add Todo": "添加待办事项",
"Add Habit": "添加习惯",
"Add Reward": "添加奖励"
} }

View file

@ -33,7 +33,6 @@ export default class HabiticaSync extends Plugin {
} }
}); });
this.activateView(); this.activateView();
} }
async loadSettings() { async loadSettings() {
this.settings = Object.assign(DEFAULT_SETTINGS, await this.loadData()) this.settings = Object.assign(DEFAULT_SETTINGS, await this.loadData())
@ -52,12 +51,10 @@ export default class HabiticaSync extends Plugin {
} }
async activateView() { async activateView() {
this.app.workspace.detachLeavesOfType(VIEW_TYPE); this.app.workspace.detachLeavesOfType(VIEW_TYPE);
await this.app.workspace.getRightLeaf(false).setViewState({ await this.app.workspace.getRightLeaf(false).setViewState({
type: VIEW_TYPE, type: VIEW_TYPE,
active: true, active: true,
}); });
this.app.workspace.revealLeaf( this.app.workspace.revealLeaf(
this.app.workspace.getLeavesOfType(VIEW_TYPE)[0] this.app.workspace.getLeavesOfType(VIEW_TYPE)[0]
); );

View file

@ -3,7 +3,9 @@ import { Notice } from "obsidian";
import { getStats, scoreTask, makeCronReq, costReward, addTask, deleteTask, updateTask } from "./habiticaAPI" import { getStats, scoreTask, makeCronReq, costReward, addTask, deleteTask, updateTask } from "./habiticaAPI"
import Statsview from "./Components/Statsview" import Statsview from "./Components/Statsview"
import Taskview from "./Components/Taskview" import Taskview from "./Components/Taskview"
import "../i18n" import { Trans } from 'react-i18next';
import "src/i18n"
import i18next from "i18next";
class App extends React.Component<any, any> { class App extends React.Component<any, any> {
private _username = ""; private _username = "";
@ -63,7 +65,7 @@ class App extends React.Component<any, any> {
}; };
} }
async runCron() { async runCron() {
console.log("running cron"); console.log(i18next.t('running cron'));
try { try {
let response = await makeCronReq(this.username, this.credentials); let response = await makeCronReq(this.username, this.credentials);
this.setState({ this.setState({
@ -71,7 +73,7 @@ class App extends React.Component<any, any> {
}) })
} catch (error) { } catch (error) {
console.log(error); console.log(error);
new Notice("There was an error running the cron. Please try again later."); new Notice(i18next.t("There was an error running the cron. Please try again later."));
} }
this.reloadData(); this.reloadData();
} }
@ -80,7 +82,7 @@ class App extends React.Component<any, any> {
let response = await getStats(this.username, this.credentials); let response = await getStats(this.username, this.credentials);
let result = await response.json(); let result = await response.json();
if (result.success === false) { if (result.success === false) {
new Notice('Login Failed, Please check credentials and try again!'); new Notice(i18next.t('Login Failed, Please check credentials and try again!'));
} }
else { else {
this.setState({ this.setState({
@ -91,7 +93,7 @@ class App extends React.Component<any, any> {
} }
} catch (e) { } catch (e) {
console.log(e); console.log(e);
new Notice("API Error: Please check credentials") new Notice(i18next.t('API Error: Please check credentials'))
} }
} }
componentDidMount() { componentDidMount() {
@ -106,12 +108,12 @@ class App extends React.Component<any, any> {
new Notice(message); new Notice(message);
this.reloadData(); this.reloadData();
} else { } else {
new Notice("Resyncing, please try again"); new Notice(i18next.t('Resyncing, please try again'));
this.reloadData(); this.reloadData();
} }
} catch (e) { } catch (e) {
console.log(e); console.log(e);
new Notice("API Error: Please check credentials") new Notice(i18next.t('API Error: Please check credentials'))
} }
} }
@ -123,12 +125,12 @@ class App extends React.Component<any, any> {
new Notice(message); new Notice(message);
this.reloadData(); this.reloadData();
} else { } else {
new Notice("Resyncing, please try again"); new Notice(i18next.t('Resyncing, please try again'));
this.reloadData(); this.reloadData();
} }
} catch (e) { } catch (e) {
console.log(e); console.log(e);
new Notice("API Error: Please check credentials") new Notice(i18next.t('API Error: Please check credentials'))
} }
} }
@ -140,12 +142,12 @@ class App extends React.Component<any, any> {
new Notice(message); new Notice(message);
this.reloadData(); this.reloadData();
} else { } else {
new Notice("Resyncing, please try again"); new Notice(i18next.t('Resyncing, please try again'));
this.reloadData(); this.reloadData();
} }
} catch (e) { } catch (e) {
console.log(e); console.log(e);
new Notice("API Error: Please check credentials") new Notice(i18next.t('API Error: Please check credentials'))
} }
} }
@ -157,12 +159,12 @@ class App extends React.Component<any, any> {
new Notice(message); new Notice(message);
this.reloadData(); this.reloadData();
} else { } else {
new Notice("Resyncing, please try again"); new Notice(i18next.t('Resyncing, please try again'));
this.reloadData(); this.reloadData();
} }
} catch (e) { } catch (e) {
console.log(e); console.log(e);
new Notice("API Error: Please check credentials") new Notice(i18next.t('API Error: Please check credentials'))
} }
} }
@ -174,12 +176,12 @@ class App extends React.Component<any, any> {
new Notice(message); new Notice(message);
this.reloadData(); this.reloadData();
} else { } else {
new Notice("Resyncing, please try again"); new Notice(i18next.t('Resyncing, please try again'));
this.reloadData(); this.reloadData();
} }
} catch (e) { } catch (e) {
console.log(e); console.log(e);
new Notice("API Error: Please check credentials") new Notice(i18next.t('API Error: Please check credentials'))
} }
// console.log(id, type,title,notes) // console.log(id, type,title,notes)
} }
@ -187,20 +189,20 @@ class App extends React.Component<any, any> {
handleChangeTodos(event: any) { handleChangeTodos(event: any) {
if (event.target.id == "add-todo") { if (event.target.id == "add-todo") {
const title = event.target.name const title = event.target.name
this.sendAddTask("todo", title, "Add!") this.sendAddTask("todo", title, i18next.t('Add!'))
} else { } else {
this.state.tasks.todos.forEach((element: any) => { this.state.tasks.todos.forEach((element: any) => {
if (element.id == event.target.id) { if (element.id == event.target.id) {
if (event.type == "click") { if (event.type == "click") {
console.log(event) console.log(event)
if (event.target.innerText == 'clear') { if (event.target.innerText == 'clear') {
this.sendDeleteTask(event.target.id, "Deleted!") this.sendDeleteTask(event.target.id, i18next.t('Deleted!'))
} }
} else { } else {
if (!element.completed) { if (!element.completed) {
this.sendScore(event.target.id, "up", "Checked!") this.sendScore(event.target.id, "up", i18next.t('Checked!'))
} else { } else {
this.sendScore(event.target.id, "down", "Un-Checked!") this.sendScore(event.target.id, "down", i18next.t('Un-Checked!'))
} }
} }
} }
@ -212,7 +214,7 @@ class App extends React.Component<any, any> {
handleChangeDailys(event: any) { handleChangeDailys(event: any) {
if (event.target.id == "add-daily") { if (event.target.id == "add-daily") {
const title = event.target.name const title = event.target.name
this.sendAddTask("daily", title, "Add!") this.sendAddTask("daily", title, i18next.t('Add!'))
} else { } else {
this.state.tasks.dailys.forEach((element: any) => { this.state.tasks.dailys.forEach((element: any) => {
if (element.id == event.target.id) { if (element.id == event.target.id) {
@ -222,11 +224,11 @@ class App extends React.Component<any, any> {
const task_notes = event.target.attributes['data-notes'].value ? event.target.attributes['data-notes'].value : element.notes const task_notes = event.target.attributes['data-notes'].value ? event.target.attributes['data-notes'].value : element.notes
this.sendUpdateTask(event.target.id, 'daily', "Update!", task_title, task_notes) this.sendUpdateTask(event.target.id, 'daily', "Update!", task_title, task_notes)
} else if (event.target.attributes.title.value == 'delete') { } else if (event.target.attributes.title.value == 'delete') {
this.sendDeleteTask(event.target.id, "Deleted!") this.sendDeleteTask(event.target.id, i18next.t('Deleted!'))
} else if (!element.completed) { } else if (!element.completed) {
this.sendScore(event.target.id, "up", "Checked!") this.sendScore(event.target.id, "up", i18next.t('Checked!'))
} else { } else {
this.sendScore(event.target.id, "down", "Un-Checked!") this.sendScore(event.target.id, "down", i18next.t('Un-Checked!'))
} }
} }
} }
@ -237,23 +239,23 @@ class App extends React.Component<any, any> {
handleChangeHabits(event: any) { handleChangeHabits(event: any) {
if (event.target.id == "add-habit") { if (event.target.id == "add-habit") {
const title = event.target.name const title = event.target.name
this.sendAddTask("habit", title, "Add!") this.sendAddTask("habit", title, i18next.t('Add!'))
} else { } else {
if (event.target.innerText == 'clear') { if (event.target.innerText == 'clear') {
this.sendDeleteTask(event.target.id, "Deleted!") this.sendDeleteTask(event.target.id, i18next.t('Deleted!'))
} else { } else {
const target_id = event.target.id.slice(4) const target_id = event.target.id.slice(4)
if (event.target.id.slice(0, 4) == "plus") { if (event.target.id.slice(0, 4) == "plus") {
this.state.tasks.habits.forEach((element: any) => { this.state.tasks.habits.forEach((element: any) => {
if (element.id == target_id) { if (element.id == target_id) {
this.sendScore(target_id, "up", "Plus!") this.sendScore(target_id, "up", i18next.t('Plus!'))
} }
}) })
} }
else { else {
this.state.tasks.habits.forEach((element: any) => { this.state.tasks.habits.forEach((element: any) => {
if (element.id == target_id) { if (element.id == target_id) {
this.sendScore(target_id, "down", "Minus :(") this.sendScore(target_id, "down", i18next.t("Minus :("))
} }
}) })
} }
@ -265,17 +267,17 @@ class App extends React.Component<any, any> {
console.log(event) console.log(event)
if (event.target.id == "add-reward") { if (event.target.id == "add-reward") {
const title = event.target.name const title = event.target.name
this.sendAddTask("reward", title, "Add!") this.sendAddTask("reward", title, i18next.t('Add!'))
} else { } else {
const target_id = event.target.id const target_id = event.target.id
this.state.tasks.rewards.forEach((element: any) => { this.state.tasks.rewards.forEach((element: any) => {
if (element.id == target_id) { if (element.id == target_id) {
if (event.target.innerText == 'clear') { if (event.target.innerText == 'clear') {
this.sendDeleteTask(event.target.id, "Deleted!") this.sendDeleteTask(event.target.id, i18next.t('Deleted!'))
} else if (event.target.innerText == 'create') { } else if (event.target.innerText == 'create') {
this.sendUpdateTask(event.target.id, 'reward', "Edit!", "1", "1") this.sendUpdateTask(event.target.id, 'reward', i18next.t('Edit!'), "1", "1")
} else { } else {
this.sendReward(target_id, "down", "Cost!") this.sendReward(target_id, "down", i18next.t('Cost!'))
} }
} }
}) })
@ -284,9 +286,9 @@ class App extends React.Component<any, any> {
render() { render() {
let content = this.CheckCron(this.state.user_data.lastCron); let content = this.CheckCron(this.state.user_data.lastCron);
if (this.state.error) if (this.state.error)
return (<div className="loading">Loading....</div>) return (<div className="loading"><Trans>Loading....</Trans></div>)
else if (!this.state.isLoaded) else if (!this.state.isLoaded)
return <div className="loading">Loading....</div> return <div className="loading"><Trans>Loading....</Trans></div>
else { else {
return (<div className="plugin-root"> return (<div className="plugin-root">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />

View file

@ -1,14 +1,14 @@
import * as React from "react"; import * as React from "react";
import DailyItem from "./DailyItem" import DailyItem from "./DailyItem"
import { Tab, Tabs, TabList, TabPanel } from "react-tabs"; import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
import { Trans } from 'react-i18next'; import { Trans, useTranslation } from 'react-i18next';
export default function Index(props: any) { export default function Index(props: any) {
const [title, setTitle] = React.useState('') const [title, setTitle] = React.useState('')
let { t ,i18n} = useTranslation()
if (props.dailys == undefined) { if (props.dailys == undefined) {
return <div id="classDisplay"> return <div id="classDisplay">
<input type="text" placeholder="添加每日任务" onChange={event => setTitle(event.target.value)} /> <input type="text" placeholder={t('Add Daily Task')} onChange={event => setTitle(event.target.value)} />
<button className="submit-button" id="add-daily" onClick={props.onChange} name={title}><Trans>submit</Trans></button> <button className="submit-button" id="add-daily" onClick={props.onChange} name={title}><Trans>submit</Trans></button>
<Trans>No Dailies Present</Trans> <Trans>No Dailies Present</Trans>
</div> </div>
@ -32,7 +32,7 @@ export default function Index(props: any) {
<Tab><Trans>Completed</Trans></Tab> <Tab><Trans>Completed</Trans></Tab>
</TabList> </TabList>
<TabPanel> <TabPanel>
<input type="text" id="task-input-box" placeholder="添加每日任务" onChange={event => setTitle(event.target.value)} value={title} /> <input type="text" id="task-input-box" placeholder={t('Add Daily Task')} onChange={event => setTitle(event.target.value)} value={title} />
<button className="submit-button" id="add-daily" onClick={function (e) { setTitle(""); props.onChange(e) }} name={title}><Trans>submit</Trans></button> <button className="submit-button" id="add-daily" onClick={function (e) { setTitle(""); props.onChange(e) }} name={title}><Trans>submit</Trans></button>
<div className="task-panel"> <div className="task-panel">
<ul>{incompleteDailies}</ul> <ul>{incompleteDailies}</ul>

View file

@ -4,9 +4,10 @@ import { useTranslation, Trans, Translation } from 'react-i18next'
export default function Index(props: any){ export default function Index(props: any){
const [title, setTitle] = React.useState('') const [title, setTitle] = React.useState('')
let { t ,i18n} = useTranslation()
if(props.habits == undefined) { if(props.habits == undefined) {
return (<div id="classDisplay"> return (<div id="classDisplay">
<input type="text" placeholder="添加习惯" onChange={event => setTitle(event.target.value)} /> <input type="text" placeholder={t('Add Habit')} onChange={event => setTitle(event.target.value)} />
<button className="submit-button" id="add-habit" onClick={props.onChange} name={title}><Trans>submit</Trans></button> <button className="submit-button" id="add-habit" onClick={props.onChange} name={title}><Trans>submit</Trans></button>
<Trans>No habits present.</Trans> <Trans>No habits present.</Trans>
</div>) </div>)
@ -18,7 +19,7 @@ export default function Index(props: any){
const display = <div id="classDisplay"> const display = <div id="classDisplay">
<input type="text" placeholder="添加习惯" onChange={event => setTitle(event.target.value)} /> <input type="text" placeholder={t('Add Habit')} onChange={event => setTitle(event.target.value)} />
<button className="submit-button" id="add-habit" onClick={props.onChange} name={title}><Trans>submit</Trans></button> <button className="submit-button" id="add-habit" onClick={props.onChange} name={title}><Trans>submit</Trans></button>
<ul>{allHabits}</ul> <ul>{allHabits}</ul>
</div> </div>

View file

@ -1,12 +1,13 @@
import * as React from "react"; import * as React from "react";
import RewardItem from "./RewardItem" import RewardItem from "./RewardItem"
import { Trans } from 'react-i18next' import { Trans,useTranslation } from 'react-i18next'
export default function Index(props: any){ export default function Index(props: any){
const [title, setTitle] = React.useState('') const [title, setTitle] = React.useState('')
let { t ,i18n} = useTranslation()
if(props.rewards == undefined) { if(props.rewards == undefined) {
return (<div id="classDisplay"> return (<div id="classDisplay">
<input type="text" placeholder="添加奖励" onChange={event => setTitle(event.target.value)} /> <input type="text" placeholder={t('Add Reward')} onChange={event => setTitle(event.target.value)} />
<button className="submit-button" id="add-reward" onClick={props.onChange} name={title}><Trans>submit</Trans></button> <button className="submit-button" id="add-reward" onClick={props.onChange} name={title}><Trans>submit</Trans></button>
<Trans>No Rewards present.</Trans> <Trans>No Rewards present.</Trans>
</div>) </div>)
@ -16,7 +17,7 @@ export default function Index(props: any){
return <RewardItem key={reward.id} id={reward.id} reward_text={reward.text} reward_notes={reward.notes} reward_value={reward.value} onChange={props.onChange}/> return <RewardItem key={reward.id} id={reward.id} reward_text={reward.text} reward_notes={reward.notes} reward_value={reward.value} onChange={props.onChange}/>
}) })
const display = <div id="classDisplay"> const display = <div id="classDisplay">
<input type="text" placeholder="添加奖励" onChange={event => setTitle(event.target.value)} /> <input type="text" placeholder={t('Add Reward')} onChange={event => setTitle(event.target.value)} />
<button className="submit-button" id="add-reward" onClick={props.onChange} name={title}><Trans>submit</Trans></button> <button className="submit-button" id="add-reward" onClick={props.onChange} name={title}><Trans>submit</Trans></button>
<ul>{allRewards}</ul> <ul>{allRewards}</ul>
</div> </div>

View file

@ -1,13 +1,14 @@
import * as React from "react"; import * as React from "react";
import TodoItem from "./TodoItem" import TodoItem from "./TodoItem"
import { Tab, Tabs, TabList, TabPanel } from "react-tabs"; import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
import { Trans } from 'react-i18next' import { Trans,useTranslation } from 'react-i18next'
export default function Index(props: any){ export default function Index(props: any){
const [title, setTitle] = React.useState('') const [title, setTitle] = React.useState('')
let { t ,i18n} = useTranslation()
if(props.todos == undefined) { if(props.todos == undefined) {
return <div id="classDisplay"> return <div id="classDisplay">
<input type="text" placeholder="添加待办事项" onChange={event => setTitle(event.target.value)} /> <input type="text" placeholder={t('Add Todo')} onChange={event => setTitle(event.target.value)} />
<button className="submit-button" id="add-todo" onClick={props.onChange} name={title}><Trans>submit</Trans></button> <button className="submit-button" id="add-todo" onClick={props.onChange} name={title}><Trans>submit</Trans></button>
No Todos present. No Todos present.
</div> </div>
@ -28,7 +29,7 @@ export default function Index(props: any){
<Tab><Trans>Completed</Trans></Tab> <Tab><Trans>Completed</Trans></Tab>
</TabList> </TabList>
<TabPanel> <TabPanel>
<input type="text" placeholder="添加待办事项" onChange={event => setTitle(event.target.value)} /> <input type="text" placeholder={t('Add Todo')} onChange={event => setTitle(event.target.value)} />
<button className="submit-button" id="add-todo" onClick={props.onChange} name={title}><Trans>submit</Trans></button> <button className="submit-button" id="add-todo" onClick={props.onChange} name={title}><Trans>submit</Trans></button>
<ul>{incompleteTodos}</ul> <ul>{incompleteTodos}</ul>
</TabPanel> </TabPanel>