diff --git a/web/.eslintrc.json b/web/.eslintrc.json
index 8f59145e..209b39ad 100644
--- a/web/.eslintrc.json
+++ b/web/.eslintrc.json
@@ -25,11 +25,26 @@
     "@typescript-eslint/no-unused-vars": "error",
     "@typescript-eslint/no-explicit-any": ["off"],
     "react/react-in-jsx-scope": "off",
-    "react/jsx-no-target-blank": "off"
+    "react/jsx-no-target-blank": "off",
+    "no-restricted-syntax": [
+      "error",
+      {
+        "selector": "VariableDeclarator[init.callee.name='useTranslation'] > ObjectPattern > Property[key.name='t']:not([parent.declarations.0.init.callee.object.name='i18n'])",
+        "message": "Destructuring 't' from useTranslation is not allowed. Please use the 'useTranslate' hook from '@/utils/i18n'."
+      }
+    ]
   },
   "settings": {
     "react": {
       "version": "detect"
     }
-  }
+  },
+  "overrides": [
+    {
+      "files": ["src/utils/i18n.ts"],
+      "rules": {
+        "no-restricted-syntax": "off"
+      }
+    }
+  ]
 }
diff --git a/web/src/components/MemoChat/ChatInput.tsx b/web/src/components/MemoChat/ChatInput.tsx
index b33c518a..cbb97f74 100644
--- a/web/src/components/MemoChat/ChatInput.tsx
+++ b/web/src/components/MemoChat/ChatInput.tsx
@@ -1,6 +1,6 @@
 import Icon from "@/components/Icon";
 import Textarea from "@mui/joy/Textarea/Textarea";
-import { useTranslation } from "react-i18next";
+import { useTranslate } from "@/utils/i18n";
 
 interface Props {
   question: string;
@@ -11,7 +11,7 @@ interface Props {
 }
 
 const ChatInput = ({ question, handleQuestionTextareaChange, setIsInIME, handleKeyDown, handleSendQuestionButtonClick }: Props) => {
-  const { t } = useTranslation();
+  const t = useTranslate();
 
   return (
     <div className="w-full relative mt-4">
diff --git a/web/src/components/MemoEditor/MemoEditorDialog.tsx b/web/src/components/MemoEditor/MemoEditorDialog.tsx
index eec3e8ff..c2a51672 100644
--- a/web/src/components/MemoEditor/MemoEditorDialog.tsx
+++ b/web/src/components/MemoEditor/MemoEditorDialog.tsx
@@ -1,7 +1,7 @@
 import { generateDialog } from "../Dialog";
 import Icon from "../Icon";
 import MemoEditor from ".";
-import { useTranslation } from "react-i18next";
+import { useTranslate } from "@/utils/i18n";
 
 interface Props extends DialogProps {
   memoId?: MemoId;
@@ -12,7 +12,7 @@ const MemoEditorDialog: React.FC<Props> = ({ memoId, relationList, destroy }: Pr
   const handleCloseBtnClick = () => {
     destroy();
   };
-  const { t } = useTranslation();
+  const t = useTranslate();
 
   return (
     <>
diff --git a/web/src/pages/MemoChat.tsx b/web/src/pages/MemoChat.tsx
index f25378ed..dab59aef 100644
--- a/web/src/pages/MemoChat.tsx
+++ b/web/src/pages/MemoChat.tsx
@@ -2,7 +2,7 @@ import { Button, Stack } from "@mui/joy";
 import { head } from "lodash-es";
 import React, { useEffect, useState } from "react";
 import { toast } from "react-hot-toast";
-import { useTranslation } from "react-i18next";
+import { useTranslate } from "@/utils/i18n";
 import * as api from "@/helpers/api";
 import useLoading from "@/hooks/useLoading";
 import { useMessageStore } from "@/store/zustand/message";
@@ -16,7 +16,7 @@ import ConversationTab from "@/components/MemoChat/ConversationTab";
 import Empty from "@/components/Empty";
 
 const MemoChat = () => {
-  const { t } = useTranslation();
+  const t = useTranslate();
   const fetchingState = useLoading(false);
   const [isEnabled, setIsEnabled] = useState<boolean>(true);
   const [isInIME, setIsInIME] = useState(false);
@@ -174,7 +174,7 @@ const MemoChat = () => {
           )}
           {!isEnabled && (
             <div className="w-full flex flex-col justify-center items-center mt-4 space-y-2">
-              <p>{t("memo-chat.not_enabled")}</p>
+              <p>{t("memo-chat.not-enabled")}</p>
               <Button onClick={() => handleGotoSystemSetting()}>{t("memo-chat.go-to-settings")}</Button>
             </div>
           )}