From a7a01df79aca394acb8384db9fbea7436b0a31c8 Mon Sep 17 00:00:00 2001 From: Steven Date: Fri, 19 Aug 2022 21:30:31 +0800 Subject: [PATCH] chore: update i18n --- web/src/components/AboutSiteDialog.tsx | 6 +- web/src/components/ArchivedMemo.tsx | 7 +- web/src/components/ChangePasswordDialog.tsx | 6 +- web/src/components/Editor/Editor.tsx | 6 +- web/src/components/Memo.tsx | 25 +++--- web/src/components/MemoEditor.tsx | 6 +- web/src/components/MenuBtnsPopup.tsx | 6 +- web/src/components/SettingDialog.tsx | 14 ++-- web/src/components/Settings/MemberSection.tsx | 20 ++--- .../components/Settings/MyAccountSection.tsx | 19 ++--- .../Settings/PreferencesSection.tsx | 79 +------------------ web/src/components/ShareMemoImageDialog.tsx | 5 +- web/src/components/ShortcutList.tsx | 9 ++- web/src/components/Sidebar.tsx | 13 +-- web/src/components/TagList.tsx | 6 +- web/src/less/about-site-dialog.less | 4 +- web/src/less/tag-list.less | 8 +- web/src/locales/en.json | 46 ++++++++++- web/src/locales/zh.json | 47 ++++++++++- web/src/pages/Auth.tsx | 2 +- web/src/pages/Home.tsx | 6 +- 21 files changed, 190 insertions(+), 150 deletions(-) diff --git a/web/src/components/AboutSiteDialog.tsx b/web/src/components/AboutSiteDialog.tsx index 869baa0b7..d11baf063 100644 --- a/web/src/components/AboutSiteDialog.tsx +++ b/web/src/components/AboutSiteDialog.tsx @@ -45,15 +45,13 @@ const AboutSiteDialog: React.FC = ({ destroy }: Props) => {
-

- Memos is an open source, self-hosted knowledge base that works with a SQLite db file. -

+

{t("slogan")}


<> - version: + {t("common.version")}: {profile?.version}-{profile?.mode} diff --git a/web/src/components/ArchivedMemo.tsx b/web/src/components/ArchivedMemo.tsx index 1ec274d3a..14a9a5230 100644 --- a/web/src/components/ArchivedMemo.tsx +++ b/web/src/components/ArchivedMemo.tsx @@ -1,5 +1,6 @@ import { IMAGE_URL_REG } from "../helpers/consts"; import * as utils from "../helpers/utils"; +import useI18n from "../hooks/useI18n"; import useToggle from "../hooks/useToggle"; import { memoService } from "../services"; import { formatMemoContent } from "../helpers/marked"; @@ -19,6 +20,7 @@ const ArchivedMemo: React.FC = (props: Props) => { createdAtStr: utils.getDateTimeString(propsMemo.createdTs), archivedAtStr: utils.getDateTimeString(propsMemo.updatedTs ?? Date.now()), }; + const { t } = useI18n(); const [showConfirmDeleteBtn, toggleConfirmDeleteBtn] = useToggle(false); const imageUrls = Array.from(memo.content.match(IMAGE_URL_REG) ?? []).map((s) => s.replace(IMAGE_URL_REG, "$1")); @@ -60,10 +62,11 @@ const ArchivedMemo: React.FC = (props: Props) => { Archived at {memo.archivedAtStr}
- Restore + {t("common.restore")} - {showConfirmDeleteBtn ? "Delete!" : "Delete"} + {t("common.delete")} + {showConfirmDeleteBtn ? "!" : ""}
diff --git a/web/src/components/ChangePasswordDialog.tsx b/web/src/components/ChangePasswordDialog.tsx index e8fcebc29..9f064e5fe 100644 --- a/web/src/components/ChangePasswordDialog.tsx +++ b/web/src/components/ChangePasswordDialog.tsx @@ -1,5 +1,6 @@ import { useEffect, useState } from "react"; import { validate, ValidatorConfig } from "../helpers/validator"; +import useI18n from "../hooks/useI18n"; import { userService } from "../services"; import Icon from "./Icon"; import { generateDialog } from "./Dialog"; @@ -16,6 +17,7 @@ const validateConfig: ValidatorConfig = { interface Props extends DialogProps {} const ChangePasswordDialog: React.FC = ({ destroy }: Props) => { + const { t } = useI18n(); const [newPassword, setNewPassword] = useState(""); const [newPasswordAgain, setNewPasswordAgain] = useState(""); @@ -85,10 +87,10 @@ const ChangePasswordDialog: React.FC = ({ destroy }: Props) => {
- Cancel + {t("common.cancel")} - Save + {t("common.save")}
diff --git a/web/src/components/Editor/Editor.tsx b/web/src/components/Editor/Editor.tsx index bf9472127..09f761c69 100644 --- a/web/src/components/Editor/Editor.tsx +++ b/web/src/components/Editor/Editor.tsx @@ -1,4 +1,5 @@ import { forwardRef, ReactNode, useCallback, useEffect, useImperativeHandle, useRef } from "react"; +import useI18n from "../../hooks/useI18n"; import useRefresh from "../../hooks/useRefresh"; import Only from "../common/OnlyWhen"; import "../../less/editor.less"; @@ -37,6 +38,7 @@ const Editor = forwardRef((props: EditorProps, ref: React.ForwardedRef(null); const refresh = useRefresh(); @@ -130,12 +132,12 @@ const Editor = forwardRef((props: EditorProps, ref: React.ForwardedRef diff --git a/web/src/components/Memo.tsx b/web/src/components/Memo.tsx index 8f9da8e5c..448dcce40 100644 --- a/web/src/components/Memo.tsx +++ b/web/src/components/Memo.tsx @@ -2,6 +2,8 @@ import { memo, useEffect, useRef, useState } from "react"; import { indexOf } from "lodash-es"; import dayjs from "dayjs"; import relativeTime from "dayjs/plugin/relativeTime"; +import "dayjs/locale/zh"; +import useI18n from "../hooks/useI18n"; import { IMAGE_URL_REG, UNKNOWN_ID } from "../helpers/consts"; import { DONE_BLOCK_REG, formatMemoContent, TODO_BLOCK_REG } from "../helpers/marked"; import { editorStateService, locationService, memoService, userService } from "../services"; @@ -27,20 +29,21 @@ interface State { expandButtonStatus: ExpandButtonStatus; } -export const getFormatedMemoCreatedAtStr = (createdTs: number): string => { +export const getFormatedMemoCreatedAtStr = (createdTs: number, locale = "en"): string => { if (Date.now() - createdTs < 1000 * 60 * 60 * 24) { - return dayjs(createdTs).fromNow(); + return dayjs(createdTs).locale(locale).fromNow(); } else { - return dayjs(createdTs).format("YYYY/MM/DD HH:mm:ss"); + return dayjs(createdTs).locale(locale).format("YYYY/MM/DD HH:mm:ss"); } }; const Memo: React.FC = (props: Props) => { const memo = props.memo; + const { t, locale } = useI18n(); const [state, setState] = useState({ expandButtonStatus: -1, }); - const [createdAtStr, setCreatedAtStr] = useState(getFormatedMemoCreatedAtStr(memo.createdTs)); + const [createdAtStr, setCreatedAtStr] = useState(getFormatedMemoCreatedAtStr(memo.createdTs, locale)); const memoContainerRef = useRef(null); const imageUrls = Array.from(memo.content.match(IMAGE_URL_REG) ?? []).map((s) => s.replace(IMAGE_URL_REG, "$1")); const isVisitorMode = userService.isVisitorMode(); @@ -59,10 +62,10 @@ const Memo: React.FC = (props: Props) => { if (Date.now() - memo.createdTs < 1000 * 60 * 60 * 24) { setInterval(() => { - setCreatedAtStr(dayjs(memo.createdTs).fromNow()); + setCreatedAtStr(getFormatedMemoCreatedAtStr(memo.createdTs, locale)); }, 1000 * 1); } - }, []); + }, [locale]); const handleShowMemoStoryDialog = () => { showMemoCardDialog(memo); @@ -186,25 +189,25 @@ const Memo: React.FC = (props: Props) => {
- {memo.pinned ? "Unpin" : "Pin"} + {memo.pinned ? t("common.unpin") : t("common.pin")}
- Edit + {t("common.edit")}
- Share + {t("common.share")}
- Mark + {t("common.mark")} View Story - Archive + {t("common.archive")} diff --git a/web/src/components/MemoEditor.tsx b/web/src/components/MemoEditor.tsx index 7fda26e0f..7e2d95ff0 100644 --- a/web/src/components/MemoEditor.tsx +++ b/web/src/components/MemoEditor.tsx @@ -1,6 +1,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { UNKNOWN_ID } from "../helpers/consts"; import { editorStateService, locationService, memoService, resourceService } from "../services"; +import useI18n from "../hooks/useI18n"; import { useAppSelector } from "../store"; import * as storage from "../helpers/storage"; import Icon from "./Icon"; @@ -16,6 +17,7 @@ interface State { } const MemoEditor: React.FC = () => { + const { t, locale } = useI18n(); const editorState = useAppSelector((state) => state.editor); const tags = useAppSelector((state) => state.memo.tags); const [state, setState] = useState({ @@ -212,7 +214,7 @@ const MemoEditor: React.FC = () => { () => ({ className: "memo-editor", initialContent: getEditorContentCache(), - placeholder: "Any thoughts...", + placeholder: t("editor.placeholder"), fullscreen: state.fullscreen, showConfirmBtn: true, showCancelBtn: isEditing, @@ -220,7 +222,7 @@ const MemoEditor: React.FC = () => { onCancelBtnClick: handleCancelBtnClick, onContentChange: handleContentChange, }), - [isEditing, state.fullscreen] + [isEditing, state.fullscreen, locale] ); return ( diff --git a/web/src/components/MenuBtnsPopup.tsx b/web/src/components/MenuBtnsPopup.tsx index d572c9bc1..7ee97a5a1 100644 --- a/web/src/components/MenuBtnsPopup.tsx +++ b/web/src/components/MenuBtnsPopup.tsx @@ -1,6 +1,7 @@ import { useEffect, useRef } from "react"; import * as api from "../helpers/api"; import { locationService, userService } from "../services"; +import useI18n from "../hooks/useI18n"; import toastHelper from "./Toast"; import Only from "./common/OnlyWhen"; import showAboutSiteDialog from "./AboutSiteDialog"; @@ -13,6 +14,7 @@ interface Props { const MenuBtnsPopup: React.FC = (props: Props) => { const { shownStatus, setShownStatus } = props; + const { t } = useI18n(); const popupElRef = useRef(null); useEffect(() => { @@ -63,14 +65,14 @@ const MenuBtnsPopup: React.FC = (props: Props) => { return (
diff --git a/web/src/components/SettingDialog.tsx b/web/src/components/SettingDialog.tsx index 42e49a7da..9248b534c 100644 --- a/web/src/components/SettingDialog.tsx +++ b/web/src/components/SettingDialog.tsx @@ -1,11 +1,12 @@ import { useState } from "react"; import { useAppSelector } from "../store"; +import useI18n from "../hooks/useI18n"; +import Icon from "./Icon"; import { generateDialog } from "./Dialog"; import MyAccountSection from "./Settings/MyAccountSection"; import PreferencesSection from "./Settings/PreferencesSection"; import MemberSection from "./Settings/MemberSection"; import "../less/setting-dialog.less"; -import Icon from "./Icon"; interface Props extends DialogProps {} @@ -17,6 +18,7 @@ interface State { const SettingDialog: React.FC = (props: Props) => { const { destroy } = props; + const { t } = useI18n(); const user = useAppSelector((state) => state.user.user); const [state, setState] = useState({ selectedSection: "my-account", @@ -34,30 +36,30 @@ const SettingDialog: React.FC = (props: Props) => {
- Basic + {t("common.basic")}
handleSectionSelectorItemClick("my-account")} className={`section-item ${state.selectedSection === "my-account" ? "selected" : ""}`} > - 🤠 My account + 🤠 {t("setting.my-account")} handleSectionSelectorItemClick("preferences")} className={`section-item ${state.selectedSection === "preferences" ? "selected" : ""}`} > - 🏟 Preferences + 🏟 {t("setting.preference")}
{user?.role === "HOST" ? ( <> - Admin + {t("common.admin")}
handleSectionSelectorItemClick("member")} className={`section-item ${state.selectedSection === "member" ? "selected" : ""}`} > - 👤 Member + 👤 {t("setting.member")}
diff --git a/web/src/components/Settings/MemberSection.tsx b/web/src/components/Settings/MemberSection.tsx index 263b0fa76..27cb8f4ef 100644 --- a/web/src/components/Settings/MemberSection.tsx +++ b/web/src/components/Settings/MemberSection.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from "react"; import { isEmpty } from "lodash-es"; +import useI18n from "../../hooks/useI18n"; import { userService } from "../../services"; import { useAppSelector } from "../../store"; import * as api from "../../helpers/api"; @@ -16,6 +17,7 @@ interface State { } const PreferencesSection: React.FC = () => { + const { t } = useI18n(); const currentUser = useAppSelector((state) => state.user.user); const [state, setState] = useState({ createUserEmail: "", @@ -110,18 +112,18 @@ const PreferencesSection: React.FC = () => { return (
-

Create a member

+

{t("setting.member-section.create-a-member")}

- Email - + {t("common.email")} +
- Password - + {t("common.password")} +
- +

Member list

@@ -140,12 +142,12 @@ const PreferencesSection: React.FC = () => { ) : ( {user.rowStatus === "NORMAL" ? ( - + ) : ( <> - + )} diff --git a/web/src/components/Settings/MyAccountSection.tsx b/web/src/components/Settings/MyAccountSection.tsx index 92baca970..6906ae7e1 100644 --- a/web/src/components/Settings/MyAccountSection.tsx +++ b/web/src/components/Settings/MyAccountSection.tsx @@ -1,4 +1,5 @@ import { useState } from "react"; +import useI18n from "../../hooks/useI18n"; import { useAppSelector } from "../../store"; import { userService } from "../../services"; import { validate, ValidatorConfig } from "../../helpers/validator"; @@ -17,6 +18,7 @@ const validateConfig: ValidatorConfig = { interface Props {} const MyAccountSection: React.FC = () => { + const { t } = useI18n(); const user = useAppSelector((state) => state.user.user as User); const [username, setUsername] = useState(user.name); const openAPIRoute = `${window.location.origin}/api/memo?openId=${user.openId}`; @@ -68,17 +70,17 @@ const MyAccountSection: React.FC = () => { return ( <>
-

Account Information

+

{t("setting.account-section.title")}

@@ -101,10 +103,9 @@ const MyAccountSection: React.FC = () => {

Open API

{openAPIRoute}

- Reset API + {t("common.reset")} API
-

Usage guide:

{`POST ${openAPIRoute}\nContent-type: application/json\n{\n  "content": "Hello #memos from ${window.location.origin}"\n}`}
diff --git a/web/src/components/Settings/PreferencesSection.tsx b/web/src/components/Settings/PreferencesSection.tsx index 0916d8c85..ca7e66057 100644 --- a/web/src/components/Settings/PreferencesSection.tsx +++ b/web/src/components/Settings/PreferencesSection.tsx @@ -1,8 +1,6 @@ -import { globalService, memoService, userService } from "../../services"; -import * as utils from "../../helpers/utils"; +import { globalService, userService } from "../../services"; import { useAppSelector } from "../../store"; -import Only from "../common/OnlyWhen"; -import toastHelper from "../Toast"; +import useI18n from "../../hooks/useI18n"; import Selector from "../common/Selector"; import "../../less/settings/preferences-section.less"; @@ -20,66 +18,9 @@ const localeSelectorItems = [ ]; const PreferencesSection: React.FC = () => { + const { t } = useI18n(); const { setting } = useAppSelector((state) => state.user.user as User); - const handleExportBtnClick = async () => { - const formatedMemos = memoService.getState().memos.map((m) => { - return { - content: m.content, - createdTs: m.createdTs, - }; - }); - - const jsonStr = JSON.stringify(formatedMemos); - const element = document.createElement("a"); - element.setAttribute("href", "data:text/json;charset=utf-8," + encodeURIComponent(jsonStr)); - element.setAttribute("download", `memos-${utils.getDateTimeString(Date.now())}.json`); - element.style.display = "none"; - document.body.appendChild(element); - element.click(); - document.body.removeChild(element); - }; - - const handleImportBtnClick = async () => { - const fileInputEl = document.createElement("input"); - fileInputEl.type = "file"; - fileInputEl.accept = "application/JSON"; - fileInputEl.onchange = () => { - if (fileInputEl.files?.length && fileInputEl.files.length > 0) { - const reader = new FileReader(); - reader.readAsText(fileInputEl.files[0]); - reader.onload = async (event) => { - const memoList = JSON.parse(event.target?.result as string) as Memo[]; - if (!Array.isArray(memoList)) { - toastHelper.error("Unexpected data type."); - } - - let succeedAmount = 0; - - for (const memo of memoList) { - const content = memo.content || ""; - const createdTs = (memo as any).createdAt || memo.createdTs || Date.now(); - - try { - const memoCreate = { - content, - createdTs: Math.floor(utils.getTimeStampByDate(createdTs) / 1000), - }; - await memoService.createMemo(memoCreate); - succeedAmount++; - } catch (error) { - // do nth - } - } - - await memoService.fetchAllMemos(); - toastHelper.success(`${succeedAmount} memos successfully imported.`); - }; - } - }; - fileInputEl.click(); - }; - const handleLocaleChanged = async (value: string) => { globalService.setLocale(value as Locale); await userService.upsertUserSetting("locale", value); @@ -87,22 +28,10 @@ const PreferencesSection: React.FC = () => { return (
- {/* Hide export/import buttons */} - -

Others

-
- - -
-
); }; diff --git a/web/src/components/ShareMemoImageDialog.tsx b/web/src/components/ShareMemoImageDialog.tsx index 4e5676ac8..c629de652 100644 --- a/web/src/components/ShareMemoImageDialog.tsx +++ b/web/src/components/ShareMemoImageDialog.tsx @@ -2,6 +2,7 @@ import { useEffect, useRef, useState } from "react"; import { userService } from "../services"; import toImage from "../labs/html2image"; import { ANIMATION_DURATION, IMAGE_URL_REG } from "../helpers/consts"; +import useI18n from "../hooks/useI18n"; import * as utils from "../helpers/utils"; import { formatMemoContent } from "../helpers/marked"; import Only from "./common/OnlyWhen"; @@ -16,6 +17,7 @@ interface Props extends DialogProps { const ShareMemoImageDialog: React.FC = (props: Props) => { const { memo: propsMemo, destroy } = props; + const { t } = useI18n(); const { user: userinfo } = userService.getState(); const memo = { ...propsMemo, @@ -73,7 +75,8 @@ const ShareMemoImageDialog: React.FC = (props: Props) => { <>

- 🌄Share Memo + 🌄 + {t("common.share")} Memo

diff --git a/web/src/components/TagList.tsx b/web/src/components/TagList.tsx index 76a1f309f..1fc32c16e 100644 --- a/web/src/components/TagList.tsx +++ b/web/src/components/TagList.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import * as utils from "../helpers/utils"; import { useAppSelector } from "../store"; import { locationService, memoService, userService } from "../services"; +import useI18n from "../hooks/useI18n"; import useToggle from "../hooks/useToggle"; import Icon from "./Icon"; import Only from "./common/OnlyWhen"; @@ -16,6 +17,7 @@ interface Tag { interface Props {} const TagList: React.FC = () => { + const { t } = useI18n(); const { memos, tags: tagsText } = useAppSelector((state) => state.memo); const query = useAppSelector((state) => state.location.query); const [tags, setTags] = useState([]); @@ -75,9 +77,7 @@ const TagList: React.FC = () => { ))} -

- Enter #tag to create a tag -

+

{t("tag-list.tip-text")}

diff --git a/web/src/less/about-site-dialog.less b/web/src/less/about-site-dialog.less index cfade21c1..b8593b597 100644 --- a/web/src/less/about-site-dialog.less +++ b/web/src/less/about-site-dialog.less @@ -18,10 +18,10 @@ } > .addtion-info-container { - @apply flex flex-row justify-start items-center; + @apply flex flex-row text-sm justify-start items-center; > .github-badge-container { - @apply mr-2; + @apply mr-4; } } } diff --git a/web/src/less/tag-list.less b/web/src/less/tag-list.less index a32e2713f..694aa95ec 100644 --- a/web/src/less/tag-list.less +++ b/web/src/less/tag-list.less @@ -61,12 +61,8 @@ } } - > .tag-tip-container { - @apply w-full mt-2 pl-4 text-sm text-gray-400; - - > .code-text { - @apply p-1 mx-1 text-blue-600 font-mono whitespace-pre-line bg-blue-100 rounded; - } + > .tip-text { + @apply w-full mt-2 pl-4 text-sm text-gray-400 font-mono; } } } diff --git a/web/src/locales/en.json b/web/src/locales/en.json index a8756d286..259c24d69 100644 --- a/web/src/locales/en.json +++ b/web/src/locales/en.json @@ -3,12 +3,56 @@ "about": "About", "email": "Email", "password": "Password", - "sign-in": "Sign in" + "username": "Username", + "save": "Save", + "cancel": "Cancel", + "create": "Create", + "change": "Change", + "reset": "Reset", + "language": "Language", + "version": "Version", + "pin": "Pin", + "unpin": "Unpin", + "edit": "Edit", + "delete": "Delete", + "share": "Share", + "mark": "Mark", + "archive": "Archive", + "basic": "Basic", + "admin": "Admin", + "sign-in": "Sign in", + "sign-out": "Sign out", + "back-to-home": "Back to Home" }, "slogan": "An open source, self-hosted knowledge base that works with a SQLite db file.", "auth": { "signup-as-host": "Sign up as Host", "host-tip": "You are registering as the Site Host.", "not-host-tip": "If you don't have an account, please contact the site host." + }, + "sidebar": { + "daily-review": "Daily Review", + "resources": "Resources", + "setting": "Setting", + "archived": "Archived" + }, + "editor": { + "save": "Save", + "cancel-edit": "Cancel edit", + "placeholder": "Any thoughts..." + }, + "tag-list": { + "tip-text": "Enter `#tag ` to create a tag" + }, + "setting": { + "my-account": "My Account", + "preference": "Preference", + "member": "Member", + "account-section": { + "title": "Account Information" + }, + "member-section": { + "create-a-member": "Create a member" + } } } diff --git a/web/src/locales/zh.json b/web/src/locales/zh.json index fb6754476..2bf092ce6 100644 --- a/web/src/locales/zh.json +++ b/web/src/locales/zh.json @@ -3,12 +3,57 @@ "about": "关于", "email": "邮箱", "password": "密码", - "sign-in": "登录" + "username": "用户名", + "save": "保存", + "cancel": "退出", + "create": "创建", + "change": "修改", + "reset": "重置", + "restore": "恢复", + "language": "语言", + "version": "版本", + "pin": "置顶", + "unpin": "取消置顶", + "edit": "编辑", + "delete": "删除", + "share": "分享", + "mark": "Mark", + "archive": "归档", + "basic": "基础", + "admin": "管理员", + "sign-in": "登录", + "sign-out": "退出登录", + "back-to-home": "回到主页" }, "slogan": "一个开源的、支持私有化部署的碎片化知识卡片管理工具。", "auth": { "signup-as-host": "注册为 Host", "host-tip": "你正在注册为 Host 用户账号。", "not-host-tip": "如果你没有账号,请联系站点 Host" + }, + "sidebar": { + "daily-review": "每日回顾", + "resources": "资源", + "setting": "设置", + "archived": "已归档" + }, + "editor": { + "save": "记下", + "cancel-edit": "退出编辑", + "placeholder": "现在的想法是..." + }, + "tag-list": { + "tip-text": "输入`#tag `来创建标签" + }, + "setting": { + "my-account": "我的账号", + "preference": "偏好设置", + "member": "成员", + "account-section": { + "title": "账号信息" + }, + "member-section": { + "create-a-member": "创建成员" + } } } diff --git a/web/src/pages/Auth.tsx b/web/src/pages/Auth.tsx index 959d467d0..a2ad8c8da 100644 --- a/web/src/pages/Auth.tsx +++ b/web/src/pages/Auth.tsx @@ -11,7 +11,7 @@ import "../less/auth.less"; interface Props {} const validateConfig: ValidatorConfig = { - minLength: 4, + minLength: 6, maxLength: 24, noSpace: true, noChinese: true, diff --git a/web/src/pages/Home.tsx b/web/src/pages/Home.tsx index 82211a990..3fbdc84c3 100644 --- a/web/src/pages/Home.tsx +++ b/web/src/pages/Home.tsx @@ -1,6 +1,7 @@ import { useEffect } from "react"; import { locationService, userService } from "../services"; import { useAppSelector } from "../store"; +import useI18n from "../hooks/useI18n"; import useLoading from "../hooks/useLoading"; import Only from "../components/common/OnlyWhen"; import Sidebar from "../components/Sidebar"; @@ -12,6 +13,7 @@ import toastHelper from "../components/Toast"; import "../less/home.less"; function Home() { + const { t } = useI18n(); const user = useAppSelector((state) => state.user.user); const location = useAppSelector((state) => state.location); const loadingState = useLoading(); @@ -58,11 +60,11 @@ function Home() {
{user ? ( ) : ( )}