You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by yo...@apache.org on 2025/05/14 02:05:01 UTC

(apisix-dashboard) branch master updated: refactor(i18n): reduce unnecessary keys (#3042)

This is an automated email from the ASF dual-hosted git repository.

young pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git


The following commit(s) were added to refs/heads/master by this push:
     new 2ed9f6382 refactor(i18n): reduce unnecessary keys (#3042)
2ed9f6382 is described below

commit 2ed9f6382e70886a849a7be2b95acb5310574da9
Author: YYYoung <is...@outlook.com>
AuthorDate: Wed May 14 10:04:55 2025 +0800

    refactor(i18n): reduce unnecessary keys (#3042)
---
 src/components/Header/LanguageMenu.tsx             |   4 +-
 src/components/Header/index.tsx                    |   7 +-
 src/components/Navbar.tsx                          |   2 +-
 src/components/form-slice/FormPartConsumer.tsx     |   4 +-
 src/components/form-slice/FormPartProto.tsx        |   7 +-
 src/components/form-slice/FormPartRoute/index.tsx  |  32 +--
 .../form-slice/FormPartStreamRoute/index.tsx       |  20 +-
 .../form-slice/FormPartUpstream/FormItemNodes.tsx  |  12 +-
 .../FormPartUpstream/FormSectionChecks.tsx         |  62 ++---
 .../FormPartUpstream/FormSectionDiscovery.tsx      |   8 +-
 .../form-slice/FormPartUpstream/index.tsx          |  62 ++---
 src/components/form/JsonInput.tsx                  |   2 +-
 .../page-slice/consumers/DetailCredentialsTabs.tsx |   6 +-
 .../page-slice/plugin_metadata/PluginMetadata.tsx  |   8 +-
 src/components/page/DeleteResourceBtn.tsx          |   6 +-
 src/components/page/ToAddPageBtn.tsx               |   2 +-
 src/config/navRoutes.ts                            |   2 +-
 src/locales/en/common.json                         | 254 +++++----------------
 src/locales/zh/common.json                         |  12 +-
 src/routes/consumer_groups/add.tsx                 |   6 +-
 src/routes/consumer_groups/detail.$id.tsx          |   6 +-
 src/routes/consumer_groups/index.tsx               |   8 +-
 src/routes/consumers/add.tsx                       |   6 +-
 .../consumers/detail.$username/credentials/add.tsx |  10 +-
 .../detail.$username/credentials/detail.$id.tsx    |   8 +-
 .../detail.$username/credentials/index.tsx         |  10 +-
 src/routes/consumers/detail.$username/index.tsx    |   6 +-
 src/routes/consumers/index.tsx                     |  10 +-
 src/routes/global_rules/add.tsx                    |   6 +-
 src/routes/global_rules/detail.$id.tsx             |   6 +-
 src/routes/global_rules/index.tsx                  |   8 +-
 src/routes/plugin_configs/add.tsx                  |   6 +-
 src/routes/plugin_configs/detail.$id.tsx           |   6 +-
 src/routes/plugin_configs/index.tsx                |   8 +-
 src/routes/plugin_metadata/index.tsx               |   2 +-
 src/routes/protos/add.tsx                          |   4 +-
 src/routes/protos/detail.$id.tsx                   |   6 +-
 src/routes/protos/index.tsx                        |   8 +-
 src/routes/routes/add.tsx                          |   4 +-
 src/routes/routes/detail.$id.tsx                   |   8 +-
 src/routes/routes/index.tsx                        |  13 +-
 src/routes/secrets/add.tsx                         |   6 +-
 src/routes/secrets/detail.$manager.$id.tsx         |   5 +-
 src/routes/secrets/index.tsx                       |   6 +-
 src/routes/services/add.tsx                        |   6 +-
 src/routes/services/detail.$id.tsx                 |   6 +-
 src/routes/services/index.tsx                      |   8 +-
 src/routes/ssls/add.tsx                            |   4 +-
 src/routes/ssls/detail.$id.tsx                     |   6 +-
 src/routes/ssls/index.tsx                          |  10 +-
 src/routes/stream_routes/add.tsx                   |   6 +-
 src/routes/stream_routes/detail.$id.tsx            |   6 +-
 src/routes/stream_routes/index.tsx                 |  12 +-
 src/routes/upstreams/add.tsx                       |   7 +-
 src/routes/upstreams/detail.$id.tsx                |   6 +-
 src/routes/upstreams/index.tsx                     |  12 +-
 56 files changed, 340 insertions(+), 433 deletions(-)

diff --git a/src/components/Header/LanguageMenu.tsx b/src/components/Header/LanguageMenu.tsx
index caaa68258..4347c9c07 100644
--- a/src/components/Header/LanguageMenu.tsx
+++ b/src/components/Header/LanguageMenu.tsx
@@ -26,7 +26,7 @@ const LangMap: Record<keyof Resources, string> = {
 };
 
 export const LanguageMenu = () => {
-  const { i18n } = useTranslation();
+  const { i18n, t } = useTranslation();
   return (
     <Menu shadow="md" width={200}>
       <Menu.Target>
@@ -46,7 +46,7 @@ export const LanguageMenu = () => {
           </Menu.Item>
         ))}
         <Menu.Divider />
-        <Menu.Label>Help Us Translate!</Menu.Label>
+        <Menu.Label>{t('help-us-translate')}</Menu.Label>
       </Menu.Dropdown>
     </Menu>
   );
diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx
index 6d7ab5b8a..75e8bc9da 100644
--- a/src/components/Header/index.tsx
+++ b/src/components/Header/index.tsx
@@ -24,7 +24,10 @@ import { LanguageMenu } from './LanguageMenu';
 import { SettingModalBtn } from './SettingModalBtn';
 
 const Logo = () => {
-  return <Image src={apisixLogo} alt="APISIX Logo" w={24} h={24} fit="fill" />;
+  const { t } = useTranslation();
+  return (
+    <Image src={apisixLogo} alt={t('apisix.logo')} w={24} h={24} fit="fill" />
+  );
 };
 
 type HeaderProps = {
@@ -40,7 +43,7 @@ export const Header: FC<HeaderProps> = (props) => {
         <Group h="100%" gap="sm">
           <Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
           <Logo />
-          <div>{t('APISIX Dashboard')}</div>
+          <div>{t('apisix.dashboard')}</div>
         </Group>
         <Group h="100%" gap="sm">
           <SettingModalBtn />
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
index e8ab19db6..c2dda747c 100644
--- a/src/components/Navbar.tsx
+++ b/src/components/Navbar.tsx
@@ -54,7 +54,7 @@ export const Navbar = () => {
         <NavbarLink
           {...route}
           key={route.to}
-          label={t(`navbar.${route.label}`)}
+          label={t(`sources.${route.label}`)}
         />
       ))}
     </AppShellNavbar>
diff --git a/src/components/form-slice/FormPartConsumer.tsx b/src/components/form-slice/FormPartConsumer.tsx
index 69d099da0..a931b93bd 100644
--- a/src/components/form-slice/FormPartConsumer.tsx
+++ b/src/components/form-slice/FormPartConsumer.tsx
@@ -45,7 +45,7 @@ export const FormPartConsumer = () => {
           <FormItemTextInput
             control={control}
             name="username"
-            label={t('consumers.username')}
+            label={t('form.consumers.username')}
             required
           />
         }
@@ -53,7 +53,7 @@ export const FormPartConsumer = () => {
       <FormItemTextInput
         control={control}
         name="group_id"
-        label={t('form.consumer.groupId')}
+        label={t('form.consumers.groupId')}
       />
       <FormSectionPluginsOnly />
     </>
diff --git a/src/components/form-slice/FormPartProto.tsx b/src/components/form-slice/FormPartProto.tsx
index e594a04d9..841c97d6c 100644
--- a/src/components/form-slice/FormPartProto.tsx
+++ b/src/components/form-slice/FormPartProto.tsx
@@ -24,6 +24,7 @@ import {
   type FormItemTextareaWithUploadProps,
 } from '../form/TextareaWithUpload';
 
+const fileTypes = '.proto,.pb';
 export const FormPartProto = <T extends FieldValues>(
   props: Pick<FormItemTextareaWithUploadProps<T>, 'allowUpload'>
 ) => {
@@ -32,11 +33,11 @@ export const FormPartProto = <T extends FieldValues>(
   return (
     <FormItemTextareaWithUpload
       name="content"
-      label={t('protos.form.content')}
-      placeholder={t('protos.form.contentPlaceholder')}
+      label={t('form.protos.content')}
+      placeholder={t('form.protos.contentPlaceholder', { fileTypes })}
       control={form.control}
       minRows={10}
-      acceptFileTypes=".proto,.pb"
+      acceptFileTypes={fileTypes}
       {...props}
     />
   );
diff --git a/src/components/form-slice/FormPartRoute/index.tsx b/src/components/form-slice/FormPartRoute/index.tsx
index 06fe67d6c..56ee5c762 100644
--- a/src/components/form-slice/FormPartRoute/index.tsx
+++ b/src/components/form-slice/FormPartRoute/index.tsx
@@ -41,7 +41,7 @@ const FormPartBasicWithPriority = () => {
       <FormItemNumberInput
         control={control}
         name="priority"
-        label={t('form.route.priority')}
+        label={t('form.routes.priority')}
         defaultValue={zGetDefault(APISIX.Route).priority!}
       />
     </FormPartBasic>
@@ -52,56 +52,56 @@ const FormSectionMatchRules = () => {
   const { t } = useTranslation();
   const { control } = useFormContext<RoutePostType>();
   return (
-    <FormSection legend={t('form.route.matchRules')}>
+    <FormSection legend={t('form.routes.matchRules')}>
       <FormItemTagsInput
         control={control}
         name="methods"
-        label={t('form.route.methods')}
+        label={t('form.routes.methods')}
         data={APISIX.HttpMethod.options.map((v) => v.value)}
         searchValue=""
       />
-      <InputWrapper label={t('form.route.enableWebsocket')}>
+      <InputWrapper label={t('form.routes.enableWebsocket')}>
         <FormItemSwitch control={control} name="enable_websocket" />
       </InputWrapper>
       <FormItemTextInput
         control={control}
         name="uri"
-        label={t('form.route.uri')}
+        label={t('form.routes.uri')}
       />
       <FormItemTagsInput
         control={control}
         name="uris"
-        label={t('form.route.uris')}
+        label={t('form.routes.uris')}
       />
       <FormItemTextInput
         control={control}
         name="host"
-        label={t('form.route.host')}
+        label={t('form.routes.host')}
       />
       <FormItemTagsInput
         control={control}
         name="hosts"
-        label={t('form.route.hosts')}
+        label={t('form.routes.hosts')}
       />
       <FormItemTextInput
         control={control}
         name="remote_addr"
-        label={t('form.route.remoteAddr')}
+        label={t('form.routes.remoteAddr')}
       />
       <FormItemTagsInput
         control={control}
         name="remote_addrs"
-        label={t('form.route.remoteAddrs')}
+        label={t('form.routes.remoteAddrs')}
       />
       <FormItemTagsInput
         control={control}
         name="vars"
-        label={t('form.route.vars')}
+        label={t('form.routes.vars')}
       />
       <FormItemTextarea
         control={control}
         name="filter_func"
-        label={t('form.route.filterFunc')}
+        label={t('form.routes.filterFunc')}
       />
     </FormSection>
   );
@@ -111,8 +111,8 @@ export const FormSectionUpstream = () => {
   const { t } = useTranslation();
   const { control } = useFormContext<RoutePostType>();
   return (
-    <FormSection legend={t('form.upstream.title')}>
-      <FormSection legend={t('form.upstream.upstreamId')}>
+    <FormSection legend={t('form.upstreams.title')}>
+      <FormSection legend={t('form.upstreams.upstreamId')}>
         <FormItemTextInput control={control} name="upstream_id" />
       </FormSection>
       <Divider my="xs" label={t('or')} />
@@ -143,11 +143,11 @@ export const FormSectionService = () => {
   const { t } = useTranslation();
   const { control } = useFormContext<RoutePostType>();
   return (
-    <FormSection legend={t('form.route.service')}>
+    <FormSection legend={t('form.routes.service')}>
       <FormItemTextInput
         control={control}
         name="service_id"
-        label={t('form.upstream.serviceId')}
+        label={t('form.upstreams.serviceId')}
       />
     </FormSection>
   );
diff --git a/src/components/form-slice/FormPartStreamRoute/index.tsx b/src/components/form-slice/FormPartStreamRoute/index.tsx
index 9d2a63afc..1283fd82a 100644
--- a/src/components/form-slice/FormPartStreamRoute/index.tsx
+++ b/src/components/form-slice/FormPartStreamRoute/index.tsx
@@ -35,27 +35,27 @@ const FormSectionStreamRouteBasic = () => {
   const { control } = useFormContext<StreamRoutePostType>();
 
   return (
-    <FormSection legend={t('form.streamRoute.server')}>
+    <FormSection legend={t('form.streamRoutes.server')}>
       <FormItemTextInput
         control={control}
         name="server_addr"
-        label={t('form.streamRoute.serverAddr')}
+        label={t('form.streamRoutes.serverAddr')}
       />
       <FormItemNumberInput
         control={control}
         name="server_port"
-        label={t('form.streamRoute.serverPort')}
+        label={t('form.streamRoutes.serverPort')}
         allowDecimal={false}
       />
       <FormItemTextInput
         control={control}
         name="remote_addr"
-        label={t('form.streamRoute.remoteAddr')}
+        label={t('form.streamRoutes.remoteAddr')}
       />
       <FormItemTextInput
         control={control}
         name="sni"
-        label={t('form.streamRoute.sni')}
+        label={t('form.streamRoutes.sni')}
       />
     </FormSection>
   );
@@ -66,26 +66,26 @@ const FormSectionStreamRouteProtocol = () => {
   const { control } = useFormContext<StreamRoutePostType>();
 
   return (
-    <FormSection legend={t('form.streamRoute.protocol.title')}>
+    <FormSection legend={t('form.streamRoutes.protocol.title')}>
       <FormItemTextInput
         control={control}
         name="protocol.name"
-        label={t('form.streamRoute.protocol.name')}
+        label={t('form.streamRoutes.protocol.name')}
       />
       <FormItemTextInput
         control={control}
         name="protocol.superior_id"
-        label={t('form.streamRoute.protocol.superiorId')}
+        label={t('form.streamRoutes.protocol.superiorId')}
       />
       <FormItemJsonInput
         control={control}
         name="protocol.conf"
-        label={t('form.streamRoute.protocol.conf')}
+        label={t('form.streamRoutes.protocol.conf')}
       />
       <FormItemJsonInput
         control={control}
         name="protocol.logger"
-        label={t('form.streamRoute.protocol.logger')}
+        label={t('form.streamRoutes.protocol.logger')}
         toObject
       />
     </FormSection>
diff --git a/src/components/form-slice/FormPartUpstream/FormItemNodes.tsx b/src/components/form-slice/FormPartUpstream/FormItemNodes.tsx
index 2a14da3b5..8824bc6fa 100644
--- a/src/components/form-slice/FormPartUpstream/FormItemNodes.tsx
+++ b/src/components/form-slice/FormPartUpstream/FormItemNodes.tsx
@@ -136,32 +136,32 @@ export const FormItemNodes = <T extends FieldValues>(
         hidden: true,
       },
       {
-        title: t('form.upstream.nodes.host.title'),
+        title: t('form.upstreams.nodes.host.title'),
         dataIndex: 'host',
         valueType: 'text',
         formItemProps: genProps('host'),
       },
       {
-        title: t('form.upstream.nodes.port.title'),
+        title: t('form.upstreams.nodes.port.title'),
         dataIndex: 'port',
         valueType: 'digit',
         valueEnum: portValueEnum,
         formItemProps: genProps('port'),
       },
       {
-        title: t('form.upstream.nodes.weight.title'),
+        title: t('form.upstreams.nodes.weight.title'),
         dataIndex: 'weight',
         valueType: 'digit',
         formItemProps: genProps('weight'),
       },
       {
-        title: t('form.upstream.nodes.priority.title'),
+        title: t('form.upstreams.nodes.priority.title'),
         dataIndex: 'priority',
         valueType: 'digit',
         formItemProps: genProps('priority'),
       },
       {
-        title: t('form.upstream.nodes.action.title'),
+        title: t('form.upstreams.nodes.action.title'),
         valueType: 'option',
         width: 100,
         hidden: disabled,
@@ -256,7 +256,7 @@ export const FormItemNodes = <T extends FieldValues>(
         onClick={() => ob.append(genRecord())}
         {...(disabled && { display: 'none' })}
       >
-        {t('form.upstream.nodes.add')}
+        {t('form.upstreams.nodes.add')}
       </Button>
     </InputWrapper>
   );
diff --git a/src/components/form-slice/FormPartUpstream/FormSectionChecks.tsx b/src/components/form-slice/FormPartUpstream/FormSectionChecks.tsx
index 4f58a0d3d..6a2add4e6 100644
--- a/src/components/form-slice/FormPartUpstream/FormSectionChecks.tsx
+++ b/src/components/form-slice/FormPartUpstream/FormSectionChecks.tsx
@@ -35,102 +35,102 @@ const FormSectionChecksActive = () => {
   const { control } = useFormContext<FormPartUpstreamType>();
   const np = useNamePrefix();
   return (
-    <FormSection legend={t('form.upstream.checks.active.title')}>
+    <FormSection legend={t('form.upstreams.checks.active.title')}>
       <FormItemSwitch
         control={control}
         name={np('checks.active.https_verify_certificate')}
-        label={t('form.upstream.checks.active.https_verify_certificate')}
+        label={t('form.upstreams.checks.active.https_verify_certificate')}
       />
       <FormItemSelect
         control={control}
         name={np('checks.active.type')}
         defaultValue={APISIX.UpstreamHealthCheckActiveType.options[0].value}
-        label={t('form.upstream.checks.active.type')}
+        label={t('form.upstreams.checks.active.type')}
         data={APISIX.UpstreamHealthCheckActiveType.options.map((v) => v.value)}
       />
       <FormItemNumberInput
         control={control}
         name={np('checks.active.timeout')}
-        label={t('form.upstream.checks.active.timeout')}
+        label={t('form.upstreams.checks.active.timeout')}
         suffix="s"
       />
       <FormItemNumberInput
         control={control}
         name={np('checks.active.concurrency')}
-        label={t('form.upstream.checks.active.concurrency')}
+        label={t('form.upstreams.checks.active.concurrency')}
         allowDecimal={false}
       />
       <FormItemTextInput
         control={control}
         name={np('checks.active.host')}
-        label={t('form.upstream.checks.active.host')}
+        label={t('form.upstreams.checks.active.host')}
       />
       <FormItemNumberInput
         control={control}
         name={np('checks.active.port')}
-        label={t('form.upstream.checks.active.port')}
+        label={t('form.upstreams.checks.active.port')}
         allowDecimal={false}
       />
       <FormItemTextInput
         control={control}
         name={np('checks.active.http_path')}
-        label={t('form.upstream.checks.active.http_path')}
+        label={t('form.upstreams.checks.active.http_path')}
       />
       <FormItemLabels
         control={control}
         name={np('checks.active.http_request_headers')}
-        label={t('form.upstream.checks.active.http_request_headers')}
+        label={t('form.upstreams.checks.active.http_request_headers')}
       />
-      <FormSection legend={t('form.upstream.checks.active.healthy.title')}>
+      <FormSection legend={t('form.upstreams.checks.active.healthy.title')}>
         <FormItemNumberInput
           control={control}
           name={np('checks.active.healthy.interval')}
-          label={t('form.upstream.checks.active.healthy.interval')}
+          label={t('form.upstreams.checks.active.healthy.interval')}
           suffix="s"
         />
         <FormItemNumberInput
           control={control}
           name={np('checks.active.healthy.successes')}
-          label={t('form.upstream.checks.active.healthy.successes')}
+          label={t('form.upstreams.checks.active.healthy.successes')}
           allowDecimal={false}
         />
         <FormItemTagsInput
           control={control}
           name={np('checks.active.healthy.http_statuses')}
-          label={t('form.upstream.checks.active.healthy.http_statuses')}
+          label={t('form.upstreams.checks.active.healthy.http_statuses')}
           from={String}
           to={Number}
         />
       </FormSection>
-      <FormSection legend={t('form.upstream.checks.active.unhealthy.title')}>
+      <FormSection legend={t('form.upstreams.checks.active.unhealthy.title')}>
         <FormItemNumberInput
           control={control}
           name={np('checks.active.unhealthy.interval')}
-          label={t('form.upstream.checks.active.unhealthy.interval')}
+          label={t('form.upstreams.checks.active.unhealthy.interval')}
           suffix="s"
         />
         <FormItemNumberInput
           control={control}
           name={np('checks.active.unhealthy.http_failures')}
-          label={t('form.upstream.checks.active.unhealthy.http_failures')}
+          label={t('form.upstreams.checks.active.unhealthy.http_failures')}
           allowDecimal={false}
         />
         <FormItemNumberInput
           control={control}
           name={np('checks.active.unhealthy.tcp_failures')}
-          label={t('form.upstream.checks.active.unhealthy.tcp_failures')}
+          label={t('form.upstreams.checks.active.unhealthy.tcp_failures')}
           allowDecimal={false}
         />
         <FormItemNumberInput
           control={control}
           name={np('checks.active.unhealthy.timeouts')}
-          label={t('form.upstream.checks.active.unhealthy.timeouts')}
+          label={t('form.upstreams.checks.active.unhealthy.timeouts')}
           allowDecimal={false}
         />
         <FormItemTagsInput
           control={control}
           name={np('checks.active.unhealthy.http_statuses')}
-          label={t('form.upstream.checks.active.unhealthy.http_statuses')}
+          label={t('form.upstreams.checks.active.unhealthy.http_statuses')}
           from={String}
           to={Number}
         />
@@ -159,51 +159,53 @@ const FormSectionChecksPassiveCore = () => {
           control={control}
           name={np('checks.passive.type')}
           defaultValue={APISIX.UpstreamHealthCheckPassiveType.options[0].value}
-          label={t('form.upstream.checks.passive.type')}
+          label={t('form.upstreams.checks.passive.type')}
           data={APISIX.UpstreamHealthCheckPassiveType.options.map(
             (v) => v.value
           )}
         />
 
-        <FormSection legend={t('form.upstream.checks.passive.healthy.title')}>
+        <FormSection legend={t('form.upstreams.checks.passive.healthy.title')}>
           <FormItemNumberInput
             control={control}
             name={np('checks.passive.healthy.successes')}
-            label={t('form.upstream.checks.passive.healthy.successes')}
+            label={t('form.upstreams.checks.passive.healthy.successes')}
             allowDecimal={false}
           />
           <FormItemTagsInput
             control={control}
             name={np('checks.passive.healthy.http_statuses')}
-            label={t('form.upstream.checks.passive.healthy.http_statuses')}
+            label={t('form.upstreams.checks.passive.healthy.http_statuses')}
             from={String}
             to={Number}
           />
         </FormSection>
 
-        <FormSection legend={t('form.upstream.checks.passive.unhealthy.title')}>
+        <FormSection
+          legend={t('form.upstreams.checks.passive.unhealthy.title')}
+        >
           <FormItemNumberInput
             control={control}
             name={np('checks.passive.unhealthy.http_failures')}
-            label={t('form.upstream.checks.passive.unhealthy.http_failures')}
+            label={t('form.upstreams.checks.passive.unhealthy.http_failures')}
             allowDecimal={false}
           />
           <FormItemNumberInput
             control={control}
             name={np('checks.passive.unhealthy.tcp_failures')}
-            label={t('form.upstream.checks.passive.unhealthy.tcp_failures')}
+            label={t('form.upstreams.checks.passive.unhealthy.tcp_failures')}
             allowDecimal={false}
           />
           <FormItemNumberInput
             control={control}
             name={np('checks.passive.unhealthy.timeouts')}
-            label={t('form.upstream.checks.passive.unhealthy.timeouts')}
+            label={t('form.upstreams.checks.passive.unhealthy.timeouts')}
             allowDecimal={false}
           />
           <FormItemTagsInput
             control={control}
             name={np('checks.passive.unhealthy.http_statuses')}
-            label={t('form.upstream.checks.passive.unhealthy.http_statuses')}
+            label={t('form.upstreams.checks.passive.unhealthy.http_statuses')}
             from={String}
             to={Number}
           />
@@ -222,7 +224,7 @@ const FormSectionChecksPassive = () => {
   const { t } = useTranslation();
   return (
     <FormSection
-      legend={t('form.upstream.checks.passive.title')}
+      legend={t('form.upstreams.checks.passive.title')}
       extra={<FormItemChecksPassiveEnabled />}
     >
       <FormSectionChecksPassiveCore />
@@ -259,7 +261,7 @@ export const FormSectionChecks = () => {
   const { t } = useTranslation();
   return (
     <FormSection
-      legend={t('form.upstream.checks.title')}
+      legend={t('form.upstreams.checks.title')}
       extra={<FormItemChecksEnabled />}
     >
       <FormSectionChecksCore />
diff --git a/src/components/form-slice/FormPartUpstream/FormSectionDiscovery.tsx b/src/components/form-slice/FormPartUpstream/FormSectionDiscovery.tsx
index fbd691dc0..7eb04aa3f 100644
--- a/src/components/form-slice/FormPartUpstream/FormSectionDiscovery.tsx
+++ b/src/components/form-slice/FormPartUpstream/FormSectionDiscovery.tsx
@@ -29,20 +29,20 @@ export const FormSectionDiscovery = () => {
   const { control } = useFormContext<FormPartUpstreamType>();
   const np = useNamePrefix();
   return (
-    <FormSection legend={t('form.upstream.serviceDiscovery.title')}>
+    <FormSection legend={t('form.upstreams.serviceDiscovery.title')}>
       <FormItemTextInput
         name={np('service_name')}
-        label={t('form.upstream.serviceName.title')}
+        label={t('form.upstreams.serviceName.title')}
         control={control}
       />
       <FormItemTextInput
         name={np('discovery_type')}
-        label={t('form.upstream.discoveryType.title')}
+        label={t('form.upstreams.discoveryType.title')}
         control={control}
       />
       <FormItemJsonInput
         name={np('discovery_args')}
-        label={t('form.upstream.discoveryArgs.title')}
+        label={t('form.upstreams.discoveryArgs.title')}
         control={control}
         toObject
       />
diff --git a/src/components/form-slice/FormPartUpstream/index.tsx b/src/components/form-slice/FormPartUpstream/index.tsx
index e5852dc1f..2aed3c7c0 100644
--- a/src/components/form-slice/FormPartUpstream/index.tsx
+++ b/src/components/form-slice/FormPartUpstream/index.tsx
@@ -39,28 +39,28 @@ export const FormSectionTLS = () => {
   const np = useNamePrefix();
 
   return (
-    <FormSection legend={t('form.upstream.tls.title')}>
+    <FormSection legend={t('form.upstreams.tls.title')}>
       <FormItemSwitch
         control={control}
         name={np('tls.verify')}
-        label={t('form.upstream.tls.verify')}
+        label={t('form.upstreams.tls.verify')}
       />
-      <FormSection legend={t('form.upstream.tls.clientCert')}>
+      <FormSection legend={t('form.upstreams.tls.clientCert')}>
         <FormItemTextarea
           control={control}
           name={np('tls.client_cert')}
-          label={t('form.upstream.tls.clientCert')}
+          label={t('form.upstreams.tls.clientCert')}
         />
         <FormItemTextarea
           control={control}
           name={np('tls.client_key')}
-          label={t('form.upstream.tls.clientKey')}
+          label={t('form.upstreams.tls.clientKey')}
         />
         <Divider my="xs" label={t('or')} />
         <FormItemTextInput
           control={control}
           name={np('tls.client_cert_id')}
-          label={t('form.upstream.tls.clientCertId')}
+          label={t('form.upstreams.tls.clientCertId')}
         />
       </FormSection>
     </FormSection>
@@ -75,7 +75,7 @@ export const FormItemScheme = () => {
     <FormItemSelect
       control={control}
       name={np('scheme')}
-      label={t('form.upstream.scheme')}
+      label={t('form.upstreams.scheme')}
       defaultValue={APISIX.UpstreamSchemeL7.options[0].value}
       data={[
         {
@@ -96,27 +96,27 @@ export const FormSectionLoadbalancing = () => {
   const { control } = useFormContext<FormPartUpstreamType>();
   const np = useNamePrefix();
   return (
-    <FormSection legend={t('form.upstream.loadBalancing')}>
+    <FormSection legend={t('form.upstreams.loadBalancing')}>
       <FormItemSelect
         control={control}
         name={np('type')}
-        label={t('form.upstream.type')}
+        label={t('form.upstreams.type')}
         defaultValue={APISIX.UpstreamBalancer.options[0].value}
         data={APISIX.UpstreamBalancer.options.map((v) => v.value)}
       />
       <FormItemSelect
         control={control}
         name={np('hash_on')}
-        label={t('form.upstream.hashOn')}
+        label={t('form.upstreams.hashOn')}
         defaultValue={APISIX.UpstreamHashOn.options[0].value}
         data={APISIX.UpstreamHashOn.options.map((v) => v.value)}
-        description={t('form.upstream.hashOnDesc')}
+        description={t('form.upstreams.hashOnDesc')}
       />
       <FormItemTextInput
         control={control}
         name={np('key')}
-        label={t('form.upstream.key')}
-        description={t('form.upstream.keyDesc')}
+        label={t('form.upstreams.key')}
+        description={t('form.upstreams.keyDesc')}
       />
     </FormSection>
   );
@@ -127,19 +127,19 @@ export const FormSectionPassHost = () => {
   const { control } = useFormContext<FormPartUpstreamType>();
   const np = useNamePrefix();
   return (
-    <FormSection legend={t('form.upstream.passHost')}>
+    <FormSection legend={t('form.upstreams.passHost')}>
       <FormItemSelect
         control={control}
         name={np('pass_host')}
-        label={t('form.upstream.passHost')}
+        label={t('form.upstreams.passHost')}
         defaultValue={APISIX.UpstreamPassHost.options[0].value}
         data={APISIX.UpstreamPassHost.options.map((v) => v.value)}
       />
       <FormItemTextInput
         control={control}
         name={np('upstream_host')}
-        label={t('form.upstream.upstreamHost')}
-        description={t('form.upstream.upstreamHostDesc')}
+        label={t('form.upstreams.upstreamHost')}
+        description={t('form.upstreams.upstreamHostDesc')}
       />
     </FormSection>
   );
@@ -150,17 +150,17 @@ export const FormSectionRetry = () => {
   const { control } = useFormContext<FormPartUpstreamType>();
   const np = useNamePrefix();
   return (
-    <FormSection legend={t('form.upstream.retry')}>
+    <FormSection legend={t('form.upstreams.retry')}>
       <FormItemNumberInput
         control={control}
         name={np('retries')}
-        label={t('form.upstream.retries')}
+        label={t('form.upstreams.retries')}
         allowDecimal={false}
       />
       <FormItemNumberInput
         control={control}
         name={np('retry_timeout')}
-        label={t('form.upstream.retryTimeout')}
+        label={t('form.upstreams.retryTimeout')}
         suffix="s"
         allowDecimal={false}
       />
@@ -173,23 +173,23 @@ export const FormSectionTimeout = () => {
   const { control } = useFormContext<FormPartUpstreamType>();
   const np = useNamePrefix();
   return (
-    <FormSection legend={t('form.upstream.timeout.title')}>
+    <FormSection legend={t('form.upstreams.timeout.title')}>
       <FormItemNumberInput
         control={control}
         name={np('timeout.connect')}
-        label={t('form.upstream.timeout.connect')}
+        label={t('form.upstreams.timeout.connect')}
         suffix="s"
       />
       <FormItemNumberInput
         control={control}
         name={np('timeout.send')}
-        label={t('form.upstream.timeout.send')}
+        label={t('form.upstreams.timeout.send')}
         suffix="s"
       />
       <FormItemNumberInput
         control={control}
         name={np('timeout.read')}
-        label={t('form.upstream.timeout.read')}
+        label={t('form.upstreams.timeout.read')}
         suffix="s"
       />
     </FormSection>
@@ -201,22 +201,22 @@ export const FormSectionKeepAlive = () => {
   const { control } = useFormContext<FormPartUpstreamType>();
   const np = useNamePrefix();
   return (
-    <FormSection legend={t('form.upstream.keepalivePool.title')}>
+    <FormSection legend={t('form.upstreams.keepalivePool.title')}>
       <FormItemNumberInput
         control={control}
         name={np('keepalive_pool.size')}
-        label={t('form.upstream.keepalivePool.size')}
+        label={t('form.upstreams.keepalivePool.size')}
       />
       <FormItemNumberInput
         control={control}
         name={np('keepalive_pool.idle_timeout')}
-        label={t('form.upstream.keepalivePool.idleTimeout')}
+        label={t('form.upstreams.keepalivePool.idleTimeout')}
         suffix="s"
       />
       <FormItemNumberInput
         control={control}
         name={np('keepalive_pool.requests')}
-        label={t('form.upstream.keepalivePool.requests')}
+        label={t('form.upstreams.keepalivePool.requests')}
         allowDecimal={false}
       />
     </FormSection>
@@ -229,14 +229,14 @@ export const FormPartUpstream = () => {
   return (
     <>
       <FormPartBasic />
-      <FormSection legend={t('form.upstream.findUpstreamFrom')}>
-        <FormSection legend={t('form.upstream.nodes.title')}>
+      <FormSection legend={t('form.upstreams.findUpstreamFrom')}>
+        <FormSection legend={t('form.upstreams.nodes.title')}>
           <FormItemNodes name={np('nodes')} required />
         </FormSection>
         <Divider my="xs" label={t('or')} />
         <FormSectionDiscovery />
       </FormSection>
-      <FormSection legend={t('form.upstream.connectionConfiguration')}>
+      <FormSection legend={t('form.upstreams.connectionConfiguration')}>
         <FormItemScheme />
         <FormSectionLoadbalancing />
         <FormSectionPassHost />
diff --git a/src/components/form/JsonInput.tsx b/src/components/form/JsonInput.tsx
index 21a31e2c7..3796c1139 100644
--- a/src/components/form/JsonInput.tsx
+++ b/src/components/form/JsonInput.tsx
@@ -36,7 +36,7 @@ export const FormItemJsonInput = <T extends FieldValues>(
   const {
     controllerProps,
     restProps: { toObject, ...restProps },
-  } = genControllerProps(props, '');
+  } = genControllerProps(props, props.toObject ? {} : '');
   const {
     field: { value: rawVal, onChange: fOnChange, ...restField },
     fieldState,
diff --git a/src/components/page-slice/consumers/DetailCredentialsTabs.tsx b/src/components/page-slice/consumers/DetailCredentialsTabs.tsx
index f7b401257..a82ae093b 100644
--- a/src/components/page-slice/consumers/DetailCredentialsTabs.tsx
+++ b/src/components/page-slice/consumers/DetailCredentialsTabs.tsx
@@ -32,11 +32,13 @@ export const DetailCredentialsTabs = () => {
     (): TabsItem[] => [
       {
         value: 'detail',
-        label: t('consumers.detail.title'),
+        label: t('info.detail.title', { name: t('consumers.singular') }),
       },
       {
         value: 'credentials',
-        label: t('consumers.credentials.title'),
+        label: t('info.detail.title', {
+          name: t('credentials.singular'),
+        }),
       },
     ],
     [t]
diff --git a/src/components/page-slice/plugin_metadata/PluginMetadata.tsx b/src/components/page-slice/plugin_metadata/PluginMetadata.tsx
index 976e76a0b..486f1131e 100644
--- a/src/components/page-slice/plugin_metadata/PluginMetadata.tsx
+++ b/src/components/page-slice/plugin_metadata/PluginMetadata.tsx
@@ -45,7 +45,9 @@ export const PluginMetadata = () => {
     mutationFn: putPluginMetadataReq,
     onSuccess(_, variables) {
       notifications.show({
-        message: t('pluginMetadata.update.success', { name: variables.name }),
+        message: t('info.edit.success', {
+          name: `${t('pluginMetadata.singular')} of ${variables.name}`,
+        }),
         color: 'green',
       });
       getMetadataListReq.refetch();
@@ -55,7 +57,9 @@ export const PluginMetadata = () => {
     mutationFn: (name: string) => deletePluginMetadataReq(name),
     onSuccess(_, name) {
       notifications.show({
-        message: t('pluginMetadata.delete.success', { name }),
+        message: t('info.delete.success', {
+          name: `${t('pluginMetadata.singular')} of ${name}`,
+        }),
         color: 'green',
       });
       getMetadataListReq.refetch();
diff --git a/src/components/page/DeleteResourceBtn.tsx b/src/components/page/DeleteResourceBtn.tsx
index fb0521601..f8f9422a6 100644
--- a/src/components/page/DeleteResourceBtn.tsx
+++ b/src/components/page/DeleteResourceBtn.tsx
@@ -46,10 +46,10 @@ export const DeleteResourceBtn = (props: DeleteResourceProps) => {
     modals.openConfirmModal({
       centered: true,
       confirmProps: { color: 'red' },
-      title: t('msg.delete.title', { name: name }),
+      title: t('info.delete.title', { name: name }),
       children: (
         <Text>
-          {t('msg.delete.content', { name: name })}
+          {t('info.delete.content', { name: name })}
           {target && (
             <Text
               component="span"
@@ -67,7 +67,7 @@ export const DeleteResourceBtn = (props: DeleteResourceProps) => {
       onConfirm: () =>
         req.delete(api).then((res) => {
           notifications.show({
-            message: t('msg.delete.success', { name: name }),
+            message: t('info.delete.success', { name: name }),
             color: 'green',
           });
           onSuccess?.(res);
diff --git a/src/components/page/ToAddPageBtn.tsx b/src/components/page/ToAddPageBtn.tsx
index bb90af25a..8767d3131 100644
--- a/src/components/page/ToAddPageBtn.tsx
+++ b/src/components/page/ToAddPageBtn.tsx
@@ -53,7 +53,7 @@ export const ToDetailPageBtn = (props: ToDetailPageBtnProps) => {
   const { t } = useTranslation();
   return (
     <RouteLinkBtn size="compact-xs" variant="light" to={to} params={params}>
-      {t('view')}
+      {t('form.btn.view')}
     </RouteLinkBtn>
   );
 };
diff --git a/src/config/navRoutes.ts b/src/config/navRoutes.ts
index 0bdb23727..848243541 100644
--- a/src/config/navRoutes.ts
+++ b/src/config/navRoutes.ts
@@ -19,7 +19,7 @@ import type { FileRouteTypes } from '@/routeTree.gen';
 
 export type NavRoute = {
   to: FileRouteTypes['to'];
-  label: keyof Resources['en']['common']['navbar'];
+  label: keyof Resources['en']['common']['sources'];
 };
 export const navRoutes: NavRoute[] = [
   {
diff --git a/src/locales/en/common.json b/src/locales/en/common.json
index 95b74ff11..847346dd8 100644
--- a/src/locales/en/common.json
+++ b/src/locales/en/common.json
@@ -1,53 +1,17 @@
 {
-  "APISIX Dashboard": "APISIX Dashboard",
-  "actions": "Actions",
+  "apisix": {
+    "dashboard": "APISIX Dashboard",
+    "logo": "APISIX Logo"
+  },
   "consumerGroups": {
-    "add": {
-      "success": "Add Consumer Group Successfully",
-      "title": "Add Consumer Group"
-    },
-    "detail": {
-      "title": "Consumer Group Detail"
-    },
-    "edit": {
-      "success": "Edit Consumer Group Successfully",
-      "title": "Edit Consumer Group"
-    },
     "singular": "Consumer Group"
   },
   "consumers": {
-    "add": {
-      "success": "Add Consumer Successfully",
-      "title": "Add Consumer"
-    },
-    "credentials": {
-      "add": {
-        "success": "Add Credential Successfully",
-        "title": "Add Credential"
-      },
-      "detail": {
-        "title": "Credential Detail"
-      },
-      "edit": {
-        "success": "Edit Credential Successfully",
-        "title": "Edit Credential"
-      },
-      "singular": "Credential",
-      "title": "Credentials"
-    },
-    "detail": {
-      "title": "Consumer Detail"
-    },
-    "edit": {
-      "success": "Edit Consumer Successfully",
-      "title": "Edit Consumer"
-    },
-    "singular": "Consumer",
-    "title": "Consumers",
-    "username": "Username"
+    "singular": "Consumer"
+  },
+  "credentials": {
+    "singular": "Credential"
   },
-  "disabled": "Disabled",
-  "enabled": "Enabled",
   "form": {
     "basic": {
       "desc": "Description",
@@ -72,9 +36,9 @@
       "upload": "Upload",
       "view": "View"
     },
-    "consumer": {
-      "details": "Consumer Details",
-      "groupId": "Group ID"
+    "consumers": {
+      "groupId": "Group ID",
+      "username": "Username"
     },
     "disabled": "Disabled, click switch to enable",
     "general": {
@@ -97,7 +61,11 @@
       },
       "viewPlugin": "View Plugin"
     },
-    "route": {
+    "protos": {
+      "content": "Content",
+      "contentPlaceholder": "Paste or upload {{fileTypes}} file"
+    },
+    "routes": {
       "enableWebsocket": "Enable WebSocket",
       "filterFunc": "Filter Func",
       "host": "Host",
@@ -168,7 +136,7 @@
       "ssl_protocols": "SSL Protocols",
       "type": "Certificate Type"
     },
-    "streamRoute": {
+    "streamRoutes": {
       "protocol": {
         "conf": "Conf",
         "logger": "Logger",
@@ -189,7 +157,7 @@
       "fileOverSize": "file size is too large",
       "readError": "file read error:"
     },
-    "upstream": {
+    "upstreams": {
       "checks": {
         "active": {
           "concurrency": "Concurrency",
@@ -309,184 +277,84 @@
     }
   },
   "globalRules": {
+    "singular": "Global Rule"
+  },
+  "help-us-translate": "Help Us Translate!",
+  "info": {
     "add": {
-      "success": "Add Global Rule Successfully",
-      "title": "Add Global Rule"
-    },
-    "detail": {
-      "title": "Global Rule Detail"
-    },
-    "edit": {
-      "success": "Edit Global Rule Successfully",
-      "title": "Edit Global Rule"
+      "success": "Add {{name}} Successfully",
+      "title": "Add {{name}}"
     },
-    "plugins": "Plugins",
-    "singular": "Global Rule",
-    "title": "Global Rules"
-  },
-  "mark": {
-    "question": "?"
-  },
-  "msg": {
     "delete": {
       "content": "Do you want to delete the {{name}}",
       "success": "Delete {{name}} Successfully",
       "title": "Delete {{name}}"
+    },
+    "detail": {
+      "title": "{{name}} Detail"
+    },
+    "edit": {
+      "success": "Edit {{name}} Successfully",
+      "title": "Edit {{name}}"
     }
   },
-  "navbar": {
-    "consumerGroups": "Consumer Groups",
-    "consumers": "Consumers",
-    "globalRules": "Global Rules",
-    "pluginConfigs": "Plugin Configs",
-    "pluginMetadata": "Plugin Metadata",
-    "protos": "Protos",
-    "routes": "Routes",
-    "secrets": "Secrets",
-    "services": "Services",
-    "ssls": "SSLs",
-    "streamRoutes": "Stream Routes",
-    "upstreams": "Upstreams"
+  "mark": {
+    "question": "?"
   },
   "noData": "No Data",
   "or": "OR",
   "pluginConfigs": {
-    "add": {
-      "success": "Add Plugin Config Successfully",
-      "title": "Add Plugin Config"
-    },
-    "detail": {
-      "title": "Plugin Config Detail"
-    },
-    "edit": {
-      "success": "Edit Plugin Config Successfully",
-      "title": "Edit Plugin Config"
-    },
     "singular": "Plugin Config"
   },
   "pluginMetadata": {
-    "delete": {
-      "success": "Delete Plugin Metadata of {{name}} Successfully"
-    },
     "search": "Search Plugin Metadata",
-    "singular": "Plugin Metadata",
-    "title": "Plugin Metadata",
-    "update": {
-      "success": "Update Plugin Metadata of {{name}} Successfully"
-    }
+    "singular": "Plugin Metadata"
   },
   "protos": {
-    "add": {
-      "success": "Add Proto Successfully",
-      "title": "Add Proto"
-    },
-    "detail": {
-      "title": "Proto Detail"
-    },
-    "edit": {
-      "success": "Edit Proto Successfully",
-      "title": "Edit Proto"
-    },
-    "form": {
-      "content": "Content",
-      "contentPlaceholder": "Paste or upload .proto, .pb file"
-    },
-    "singular": "Proto",
-    "title": "Protos"
+    "singular": "Proto"
   },
-  "route": {
-    "add": {
-      "success": "Add Route Successfully",
-      "title": "Add Route"
-    },
-    "detail": {
-      "title": "Route Detail"
-    },
-    "edit": {
-      "success": "Edit Route Successfully",
-      "title": "Edit Route"
-    },
-    "singular": "Route",
-    "title": "Routes"
+  "routes": {
+    "singular": "Route"
   },
   "seconds": "Seconds",
   "secrets": {
-    "add": {
-      "success": "Add Secret Successfully",
-      "title": "Add Secret"
-    },
-    "detail": {
-      "title": "Secret Detail"
-    },
-    "edit": {
-      "success": "Edit Secret Successfully",
-      "title": "Edit Secret"
-    },
     "singular": "Secret"
   },
   "services": {
-    "add": {
-      "success": "Add Service Successfully",
-      "title": "Add Service"
-    },
-    "detail": {
-      "title": "Service Detail"
-    },
-    "edit": {
-      "success": "Edit Service Successfully",
-      "title": "Edit Service"
-    },
-    "singular": "Service",
-    "title": "Services"
+    "singular": "Service"
   },
   "settings": {
     "adminKey": "Admin Key",
     "title": "Settings",
     "ui-commit-sha": "UI Commit SHA"
   },
+  "sources": {
+    "consumerGroups": "Consumer Groups",
+    "consumers": "Consumers",
+    "credentials": "Credentials",
+    "globalRules": "Global Rules",
+    "pluginConfigs": "Plugin Configs",
+    "pluginMetadata": "Plugin Metadata",
+    "protos": "Protos",
+    "routes": "Routes",
+    "secrets": "Secrets",
+    "services": "Services",
+    "ssls": "SSLs",
+    "streamRoutes": "Stream Routes",
+    "upstreams": "Upstreams"
+  },
   "ssls": {
-    "add": {
-      "success": "Add SSL Successfully",
-      "title": "Add SSL"
-    },
-    "detail": {
-      "title": "SSL Detail"
-    },
-    "edit": {
-      "success": "Edit SSL Successfully",
-      "title": "Edit SSL"
-    },
     "singular": "SSL"
   },
   "streamRoutes": {
-    "add": {
-      "success": "Add Stream Route Successfully",
-      "title": "Add Stream Route"
-    },
-    "detail": {
-      "title": "Stream Route Detail"
-    },
-    "edit": {
-      "success": "Edit Stream Route Successfully",
-      "title": "Edit Stream Route"
-    },
-    "singular": "Stream Route",
-    "title": "Stream Routes"
+    "singular": "Stream Route"
   },
-  "upstreams": {
-    "add": {
-      "success": "Add Upstream Successfully",
-      "title": "Add Upstream"
-    },
-    "detail": {
-      "title": "Upstream Detail"
-    },
-    "edit": {
-      "success": "Edit Upstream Successfully",
-      "title": "Edit Upstream"
-    },
-    "singular": "Upstream",
-    "title": "Upstreams"
+  "table": {
+    "actions": "Actions",
+    "disabled": "Disabled",
+    "enabled": "Enabled"
   },
-  "view": "View"
+  "upstreams": {
+    "singular": "Upstream"
+  }
 }
diff --git a/src/locales/zh/common.json b/src/locales/zh/common.json
index 120be507d..0967ef424 100644
--- a/src/locales/zh/common.json
+++ b/src/locales/zh/common.json
@@ -1,11 +1 @@
-{
-  "APISIX Dashboard": "APISIX Dashboard",
-  "navbar": {
-    "consumer": "消费者",
-    "globalRules": "插件全局规则",
-    "route": "路由",
-    "secret": "Secret",
-    "service": "服务",
-    "ssl": "SSL"
-  }
-}
+{}
diff --git a/src/routes/consumer_groups/add.tsx b/src/routes/consumer_groups/add.tsx
index f44d34f97..da57d00b1 100644
--- a/src/routes/consumer_groups/add.tsx
+++ b/src/routes/consumer_groups/add.tsx
@@ -38,7 +38,7 @@ const ConsumerGroupAddForm = () => {
     mutationFn: putConsumerGroupReq,
     async onSuccess(response) {
       notifications.show({
-        message: t('consumerGroups.add.success'),
+        message: t('info.add.success', { name: t('consumerGroups.singular') }),
         color: 'green',
       });
       await router.navigate({
@@ -79,7 +79,9 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('consumerGroups.add.title')} />
+      <PageHeader
+        title={t('info.add.title', { name: t('consumerGroups.singular') })}
+      />
       <FormTOCBox>
         <ConsumerGroupAddForm />
       </FormTOCBox>
diff --git a/src/routes/consumer_groups/detail.$id.tsx b/src/routes/consumer_groups/detail.$id.tsx
index 9e3021cd3..497c1008e 100644
--- a/src/routes/consumer_groups/detail.$id.tsx
+++ b/src/routes/consumer_groups/detail.$id.tsx
@@ -58,7 +58,7 @@ const ConsumerGroupDetailForm = (props: Props) => {
     mutationFn: putConsumerGroupReq,
     async onSuccess() {
       notifications.show({
-        message: t('consumerGroups.edit.success'),
+        message: t('info.edit.success', { name: t('consumerGroups.singular') }),
         color: 'green',
       });
       consumerGroupQuery.refetch();
@@ -113,9 +113,9 @@ function RouteComponent() {
   return (
     <>
       <PageHeader
-        title={t('consumerGroups.edit.title')}
+        title={t('info.edit.title', { name: t('consumerGroups.singular') })}
         {...(readOnly && {
-          title: t('consumerGroups.detail.title'),
+          title: t('info.detail.title', { name: t('consumerGroups.singular') }),
           extra: (
             <Group>
               <Button
diff --git a/src/routes/consumer_groups/index.tsx b/src/routes/consumer_groups/index.tsx
index da8f458b5..747df0be2 100644
--- a/src/routes/consumer_groups/index.tsx
+++ b/src/routes/consumer_groups/index.tsx
@@ -84,7 +84,7 @@ function ConsumerGroupsList() {
         },
       },
       {
-        title: t('actions'),
+        title: t('table.actions'),
         valueType: 'option',
         key: 'option',
         width: 120,
@@ -133,7 +133,9 @@ function ConsumerGroupsList() {
                   <ToAddPageBtn
                     key="add"
                     to="/consumer_groups/add"
-                    label={t('consumerGroups.add.title')}
+                    label={t('info.add.title', {
+                      name: t('consumerGroups.singular'),
+                    })}
                   />
                 ),
               },
@@ -149,7 +151,7 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('navbar.consumerGroups')} />
+      <PageHeader title={t('sources.consumerGroups')} />
       <ConsumerGroupsList />
     </>
   );
diff --git a/src/routes/consumers/add.tsx b/src/routes/consumers/add.tsx
index 16b96b0c9..c7e8adb72 100644
--- a/src/routes/consumers/add.tsx
+++ b/src/routes/consumers/add.tsx
@@ -37,7 +37,7 @@ const ConsumerAddForm = () => {
     mutationFn: putConsumerReq,
     async onSuccess(_, res) {
       notifications.show({
-        message: t('consumers.add.success'),
+        message: t('info.add.success', { name: t('consumers.singular') }),
         color: 'green',
       });
       await router.navigate({
@@ -72,7 +72,9 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('consumers.add.title')} />
+      <PageHeader
+        title={t('info.add.title', { name: t('consumers.singular') })}
+      />
       <FormTOCBox>
         <ConsumerAddForm />
       </FormTOCBox>
diff --git a/src/routes/consumers/detail.$username/credentials/add.tsx b/src/routes/consumers/detail.$username/credentials/add.tsx
index a2edaa0af..f157bd89b 100644
--- a/src/routes/consumers/detail.$username/credentials/add.tsx
+++ b/src/routes/consumers/detail.$username/credentials/add.tsx
@@ -42,7 +42,9 @@ const CredentialAddForm = () => {
     mutationFn: putCredentialReq,
     async onSuccess(_, res) {
       notifications.show({
-        message: t('consumers.credentials.add.success'),
+        message: t('info.add.success', {
+          name: t('credentials.singular'),
+        }),
         color: 'green',
       });
       await router.navigate({
@@ -80,7 +82,11 @@ function RouteComponent() {
   return (
     <>
       <DetailCredentialsTabs />
-      <PageHeader title={t('consumers.credentials.add.title')} />
+      <PageHeader
+        title={t('info.add.title', {
+          name: t('credentials.singular'),
+        })}
+      />
       <FormTOCBox>
         <CredentialAddForm />
       </FormTOCBox>
diff --git a/src/routes/consumers/detail.$username/credentials/detail.$id.tsx b/src/routes/consumers/detail.$username/credentials/detail.$id.tsx
index 97e77ab70..f13235aa0 100644
--- a/src/routes/consumers/detail.$username/credentials/detail.$id.tsx
+++ b/src/routes/consumers/detail.$username/credentials/detail.$id.tsx
@@ -78,7 +78,7 @@ const CredentialDetailForm = (props: CredentialFormProps) => {
     mutationFn: putCredentialReq,
     async onSuccess() {
       notifications.show({
-        message: t('consumers.credentials.edit.success'),
+        message: t('info.edit.success', { name: t('credentials.singular') }),
         color: 'green',
       });
       await refetch();
@@ -126,9 +126,9 @@ function RouteComponent() {
     <>
       <DetailCredentialsTabs />
       <PageHeader
-        title={t('consumers.credentials.edit.title')}
+        title={t('info.edit.title', { name: t('credentials.singular') })}
         {...(readOnly && {
-          title: t('consumers.credentials.detail.title'),
+          title: t('info.detail.title', { name: t('credentials.singular') }),
           extra: (
             <Group>
               <Button
@@ -140,7 +140,7 @@ function RouteComponent() {
               </Button>
               <DeleteResourceBtn
                 key="delete"
-                name={t('consumers.credentials.singular')}
+                name={t('credentials.singular')}
                 target={id}
                 api={`${API_CREDENTIALS(username)}/${id}`}
                 onSuccess={() =>
diff --git a/src/routes/consumers/detail.$username/credentials/index.tsx b/src/routes/consumers/detail.$username/credentials/index.tsx
index 053de01d5..ff0291967 100644
--- a/src/routes/consumers/detail.$username/credentials/index.tsx
+++ b/src/routes/consumers/detail.$username/credentials/index.tsx
@@ -70,7 +70,7 @@ function CredentialsList() {
         },
       },
       {
-        title: t('actions'),
+        title: t('table.actions'),
         valueType: 'option',
         key: 'option',
         width: 120,
@@ -85,7 +85,7 @@ function CredentialsList() {
           />,
           <DeleteResourceBtn
             key="delete"
-            name={t('consumers.credentials.singular')}
+            name={t('credentials.singular')}
             target={record.value.id}
             api={`${API_CREDENTIALS(username)}/${record.value.id}`}
             onSuccess={refetch}
@@ -117,7 +117,9 @@ function CredentialsList() {
                     key="add"
                     to="/consumers/detail/$username/credentials/add"
                     params={{ username }}
-                    label={t('consumers.credentials.add.title')}
+                    label={t('info.add.title', {
+                      name: t('credentials.singular'),
+                    })}
                   />
                 ),
               },
@@ -134,7 +136,7 @@ function RouteComponent() {
   return (
     <>
       <DetailCredentialsTabs />
-      <PageHeader title={t('consumers.credentials.title')} />
+      <PageHeader title={t('sources.credentials')} />
       <CredentialsList />
     </>
   );
diff --git a/src/routes/consumers/detail.$username/index.tsx b/src/routes/consumers/detail.$username/index.tsx
index d9d3b13f4..b44ec4150 100644
--- a/src/routes/consumers/detail.$username/index.tsx
+++ b/src/routes/consumers/detail.$username/index.tsx
@@ -71,7 +71,7 @@ const ConsumerDetailForm = (props: Props) => {
     mutationFn: putConsumerReq,
     async onSuccess() {
       notifications.show({
-        message: t('consumers.edit.success'),
+        message: t('info.edit.success', { name: t('consumers.singular') }),
         color: 'green',
       });
       await refetch();
@@ -114,9 +114,9 @@ const ConsumerDetailTab = () => {
   return (
     <>
       <PageHeader
-        title={t('consumers.edit.title')}
+        title={t('info.edit.title', { name: t('consumers.singular') })}
         {...(readOnly && {
-          title: t('consumers.detail.title'),
+          title: t('info.detail.title', { name: t('consumers.singular') }),
           extra: (
             <Group>
               <Button
diff --git a/src/routes/consumers/index.tsx b/src/routes/consumers/index.tsx
index da9442c47..2663e2496 100644
--- a/src/routes/consumers/index.tsx
+++ b/src/routes/consumers/index.tsx
@@ -56,7 +56,7 @@ function ConsumersList() {
     return [
       {
         dataIndex: ['value', 'username'],
-        title: t('consumers.username'),
+        title: t('form.consumers.username'),
         key: 'username',
         valueType: 'text',
       },
@@ -78,7 +78,7 @@ function ConsumersList() {
         },
       },
       {
-        title: t('actions'),
+        title: t('table.actions'),
         valueType: 'option',
         key: 'option',
         width: 120,
@@ -127,7 +127,9 @@ function ConsumersList() {
                   <ToAddPageBtn
                     key="add"
                     to="/consumers/add"
-                    label={t('consumers.add.title')}
+                    label={t('info.add.title', {
+                      name: t('consumers.singular'),
+                    })}
                   />
                 ),
               },
@@ -143,7 +145,7 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('consumers.title')} />
+      <PageHeader title={t('sources.consumers')} />
       <ConsumersList />
     </>
   );
diff --git a/src/routes/global_rules/add.tsx b/src/routes/global_rules/add.tsx
index 5cba0b852..ff59f4abb 100644
--- a/src/routes/global_rules/add.tsx
+++ b/src/routes/global_rules/add.tsx
@@ -56,7 +56,7 @@ const GlobalRuleAddForm = () => {
     const res = await putGlobalRule.mutateAsync(data);
     notifications.show({
       id: 'add-global_rule',
-      message: t('globalRules.add.success'),
+      message: t('info.add.success', { name: t('globalRules.singular') }),
       color: 'green',
     });
     await router.navigate({
@@ -79,7 +79,9 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('globalRules.add.title')} />
+      <PageHeader
+        title={t('info.add.title', { name: t('globalRules.singular') })}
+      />
       <FormTOCBox>
         <GlobalRuleAddForm />
       </FormTOCBox>
diff --git a/src/routes/global_rules/detail.$id.tsx b/src/routes/global_rules/detail.$id.tsx
index 8ed0a404b..edc5bc0b5 100644
--- a/src/routes/global_rules/detail.$id.tsx
+++ b/src/routes/global_rules/detail.$id.tsx
@@ -69,7 +69,7 @@ const GlobalRuleDetailForm = (props: Props) => {
   const submit = async (data: APISIXType['GlobalRulePut']) => {
     await putglobalRule.mutateAsync(data);
     notifications.show({
-      message: t('globalRules.edit.success'),
+      message: t('info.edit.success', { name: t('globalRules.singular') }),
       color: 'green',
     });
     await detailReq.refetch();
@@ -102,9 +102,9 @@ function RouteComponent() {
   return (
     <>
       <PageHeader
-        title={t('globalRules.edit.title')}
+        title={t('info.edit.title', { name: t('globalRules.singular') })}
         {...(readOnly && {
-          title: t('globalRules.detail.title'),
+          title: t('info.detail.title', { name: t('globalRules.singular') }),
           extra: (
             <Group>
               <Button
diff --git a/src/routes/global_rules/index.tsx b/src/routes/global_rules/index.tsx
index e7c84ef7b..ec5a9c647 100644
--- a/src/routes/global_rules/index.tsx
+++ b/src/routes/global_rules/index.tsx
@@ -81,7 +81,7 @@ function RouteComponent() {
         valueType: 'text',
       },
       {
-        title: t('actions'),
+        title: t('table.actions'),
         valueType: 'option',
         key: 'option',
         width: 120,
@@ -105,7 +105,7 @@ function RouteComponent() {
 
   return (
     <>
-      <PageHeader title={t('globalRules.title')} />
+      <PageHeader title={t('sources.globalRules')} />
       <AntdConfigProvider>
         <ProTable
           columns={columns}
@@ -132,7 +132,9 @@ function RouteComponent() {
                     <ToAddPageBtn
                       key="add"
                       to="/global_rules/add"
-                      label={t('globalRules.add.title')}
+                      label={t('info.add.title', {
+                        name: t('globalRules.singular'),
+                      })}
                     />
                   ),
                 },
diff --git a/src/routes/plugin_configs/add.tsx b/src/routes/plugin_configs/add.tsx
index 5390dfa6e..dca90c2ea 100644
--- a/src/routes/plugin_configs/add.tsx
+++ b/src/routes/plugin_configs/add.tsx
@@ -38,7 +38,7 @@ const PluginConfigAddForm = () => {
     mutationFn: putPluginConfigReq,
     async onSuccess(response) {
       notifications.show({
-        message: t('pluginConfigs.add.success'),
+        message: t('info.add.success', { name: t('pluginConfigs.singular') }),
         color: 'green',
       });
       await router.navigate({
@@ -76,7 +76,9 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('pluginConfigs.add.title')} />
+      <PageHeader
+        title={t('info.add.title', { name: t('pluginConfigs.singular') })}
+      />
       <FormTOCBox>
         <PluginConfigAddForm />
       </FormTOCBox>
diff --git a/src/routes/plugin_configs/detail.$id.tsx b/src/routes/plugin_configs/detail.$id.tsx
index d27ff0f4d..d882b9f13 100644
--- a/src/routes/plugin_configs/detail.$id.tsx
+++ b/src/routes/plugin_configs/detail.$id.tsx
@@ -59,7 +59,7 @@ const PluginConfigDetailForm = (props: Props) => {
     mutationFn: putPluginConfigReq,
     async onSuccess() {
       notifications.show({
-        message: t('pluginConfigs.edit.success'),
+        message: t('info.edit.success', { name: t('pluginConfigs.singular') }),
         color: 'green',
       });
       pluginConfigQuery.refetch();
@@ -112,9 +112,9 @@ function RouteComponent() {
   return (
     <>
       <PageHeader
-        title={t('pluginConfigs.edit.title')}
+        title={t('info.edit.title', { name: t('pluginConfigs.singular') })}
         {...(readOnly && {
-          title: t('pluginConfigs.detail.title'),
+          title: t('info.detail.title', { name: t('pluginConfigs.singular') }),
           extra: (
             <Group>
               <Button
diff --git a/src/routes/plugin_configs/index.tsx b/src/routes/plugin_configs/index.tsx
index 87f323cdb..f646a1fdc 100644
--- a/src/routes/plugin_configs/index.tsx
+++ b/src/routes/plugin_configs/index.tsx
@@ -84,7 +84,7 @@ function PluginConfigsList() {
         },
       },
       {
-        title: t('actions'),
+        title: t('table.actions'),
         valueType: 'option',
         key: 'option',
         width: 120,
@@ -133,7 +133,9 @@ function PluginConfigsList() {
                   <ToAddPageBtn
                     key="add"
                     to="/plugin_configs/add"
-                    label={t('pluginConfigs.add.title')}
+                    label={t('info.add.title', {
+                      name: t('pluginConfigs.singular'),
+                    })}
                   />
                 ),
               },
@@ -149,7 +151,7 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('navbar.pluginConfigs')} />
+      <PageHeader title={t('sources.pluginConfigs')} />
       <PluginConfigsList />
     </>
   );
diff --git a/src/routes/plugin_metadata/index.tsx b/src/routes/plugin_metadata/index.tsx
index 2f73c4e44..7d8b23159 100644
--- a/src/routes/plugin_metadata/index.tsx
+++ b/src/routes/plugin_metadata/index.tsx
@@ -25,7 +25,7 @@ function RouteComponent() {
 
   return (
     <>
-      <PageHeader title={t('pluginMetadata.title')} />
+      <PageHeader title={t('sources.pluginMetadata')} />
       <PluginMetadata />
     </>
   );
diff --git a/src/routes/protos/add.tsx b/src/routes/protos/add.tsx
index 46f9cdbd7..b8d981359 100644
--- a/src/routes/protos/add.tsx
+++ b/src/routes/protos/add.tsx
@@ -55,7 +55,7 @@ const ProtoAddForm = () => {
     await postProto.mutateAsync(data);
     notifications.show({
       id: 'add-proto',
-      message: t('protos.add.success'),
+      message: t('info.add.success', { name: t('protos.singular') }),
       color: 'green',
     });
     await router.navigate({ to: '/protos' });
@@ -75,7 +75,7 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('protos.add.title')} />
+      <PageHeader title={t('info.add.title', { name: t('protos.singular') })} />
       <ProtoAddForm />
     </>
   );
diff --git a/src/routes/protos/detail.$id.tsx b/src/routes/protos/detail.$id.tsx
index e1d8ff157..883464026 100644
--- a/src/routes/protos/detail.$id.tsx
+++ b/src/routes/protos/detail.$id.tsx
@@ -64,7 +64,7 @@ const ProtoDetailForm = ({ id, readOnly, setReadOnly }: ProtoFormProps) => {
     mutationFn: putProtoReq,
     async onSuccess() {
       notifications.show({
-        message: t('protos.edit.success'),
+        message: t('info.edit.success', { name: t('protos.singular') }),
         color: 'green',
       });
       await refetch();
@@ -114,9 +114,9 @@ function RouteComponent() {
   return (
     <>
       <PageHeader
-        title={t('protos.edit.title')}
+        title={t('info.edit.title', { name: t('protos.singular') })}
         {...(readOnly && {
-          title: t('protos.detail.title'),
+          title: t('info.detail.title', { name: t('protos.singular') }),
           extra: (
             <Group>
               <Button
diff --git a/src/routes/protos/index.tsx b/src/routes/protos/index.tsx
index 70a63bfbe..af8436540 100644
--- a/src/routes/protos/index.tsx
+++ b/src/routes/protos/index.tsx
@@ -60,7 +60,7 @@ function RouteComponent() {
         valueType: 'text',
       },
       {
-        title: t('actions'),
+        title: t('table.actions'),
         valueType: 'option',
         key: 'option',
         width: 120,
@@ -84,7 +84,7 @@ function RouteComponent() {
 
   return (
     <>
-      <PageHeader title={t('protos.title')} />
+      <PageHeader title={t('sources.protos')} />
       <AntdConfigProvider>
         <ProTable
           columns={columns}
@@ -111,7 +111,9 @@ function RouteComponent() {
                     <ToAddPageBtn
                       key="add"
                       to="/protos/add"
-                      label={t('protos.add.title')}
+                      label={t('info.add.title', {
+                        name: t('protos.singular'),
+                      })}
                     />
                   ),
                 },
diff --git a/src/routes/routes/add.tsx b/src/routes/routes/add.tsx
index cf147def1..9b2c5f6eb 100644
--- a/src/routes/routes/add.tsx
+++ b/src/routes/routes/add.tsx
@@ -37,7 +37,7 @@ const RouteAddForm = () => {
     mutationFn: postRouteReq,
     async onSuccess() {
       notifications.show({
-        message: t('route.add.success'),
+        message: t('info.add.success', { name: t('routes.singular') }),
         color: 'green',
       });
       await router.navigate({ to: '/routes' });
@@ -69,7 +69,7 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('route.add.title')} />
+      <PageHeader title={t('info.add.title', { name: t('routes.singular') })} />
       <FormTOCBox>
         <RouteAddForm />
       </FormTOCBox>
diff --git a/src/routes/routes/detail.$id.tsx b/src/routes/routes/detail.$id.tsx
index 14ce5e541..593b33c56 100644
--- a/src/routes/routes/detail.$id.tsx
+++ b/src/routes/routes/detail.$id.tsx
@@ -70,7 +70,7 @@ const RouteDetailForm = (props: Props) => {
     mutationFn: putRouteReq,
     async onSuccess() {
       notifications.show({
-        message: t('route.edit.success'),
+        message: t('info.edit.success', { name: t('routes.singular') }),
         color: 'green',
       });
       await refetch();
@@ -113,9 +113,9 @@ function RouteComponent() {
   return (
     <>
       <PageHeader
-        title={t('route.edit.title')}
+        title={t('info.edit.title', { name: t('routes.singular') })}
         {...(readOnly && {
-          title: t('route.detail.title'),
+          title: t('info.detail.title', { name: t('routes.singular') }),
           extra: (
             <Group>
               <Button
@@ -127,7 +127,7 @@ function RouteComponent() {
               </Button>
               <DeleteResourceBtn
                 mode="detail"
-                name={t('route.singular')}
+                name={t('routes.singular')}
                 target={id}
                 api={`${API_ROUTES}/${id}`}
                 onSuccess={() => navigate({ to: '/routes' })}
diff --git a/src/routes/routes/index.tsx b/src/routes/routes/index.tsx
index 4362fcea9..89cf81897 100644
--- a/src/routes/routes/index.tsx
+++ b/src/routes/routes/index.tsx
@@ -74,7 +74,7 @@ const RouteList = () => {
         valueType: 'text',
       },
       {
-        title: t('actions'),
+        title: t('table.actions'),
         valueType: 'option',
         key: 'option',
         width: 120,
@@ -86,7 +86,7 @@ const RouteList = () => {
           />,
           <DeleteResourceBtn
             key="delete"
-            name={t('route.singular')}
+            name={t('routes.singular')}
             target={record.value.id}
             api={`${API_ROUTES}/${record.value.id}`}
             onSuccess={refetch}
@@ -122,7 +122,7 @@ const RouteList = () => {
                 label: (
                   <ToAddPageBtn
                     key="add"
-                    label={t('route.add.title')}
+                    label={t('info.add.title', { name: t('routes.singular') })}
                     to="/routes/add"
                   />
                 ),
@@ -136,12 +136,11 @@ const RouteList = () => {
 };
 
 function RouteComponent() {
+  const { t } = useTranslation();
   return (
     <>
-      <PageHeader title="Routes" />
-      <AntdConfigProvider>
-        <RouteList />
-      </AntdConfigProvider>
+      <PageHeader title={t('sources.routes')} />
+      <RouteList />
     </>
   );
 }
diff --git a/src/routes/secrets/add.tsx b/src/routes/secrets/add.tsx
index 9086e80b2..83295d917 100644
--- a/src/routes/secrets/add.tsx
+++ b/src/routes/secrets/add.tsx
@@ -39,7 +39,7 @@ const SecretAddForm = () => {
     mutationFn: putSecretReq,
     async onSuccess() {
       notifications.show({
-        message: t('secrets.add.success'),
+        message: t('info.add.success', { name: t('secrets.singular') }),
         color: 'green',
       });
       await router.navigate({
@@ -78,7 +78,9 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('secrets.add.title')} />
+      <PageHeader
+        title={t('info.add.title', { name: t('secrets.singular') })}
+      />
       <FormTOCBox>
         <SecretAddForm />
       </FormTOCBox>
diff --git a/src/routes/secrets/detail.$manager.$id.tsx b/src/routes/secrets/detail.$manager.$id.tsx
index 1bcc34814..de6d5db3f 100644
--- a/src/routes/secrets/detail.$manager.$id.tsx
+++ b/src/routes/secrets/detail.$manager.$id.tsx
@@ -76,7 +76,7 @@ const SecretDetailForm = (props: Props) => {
     mutationFn: putSecretReq,
     async onSuccess() {
       notifications.show({
-        message: t('secrets.edit.success'),
+        message: t('info.edit.success', { name: t('secrets.singular') }),
         color: 'green',
       });
       await refetch();
@@ -119,8 +119,9 @@ function RouteComponent() {
   return (
     <>
       <PageHeader
-        title={readOnly ? t('secrets.detail.title') : t('secrets.edit.title')}
+        title={t('info.edit.title', { name: t('secrets.singular') })}
         {...(readOnly && {
+          title: t('info.detail.title', { name: t('secrets.singular') }),
           extra: (
             <Group>
               <Button
diff --git a/src/routes/secrets/index.tsx b/src/routes/secrets/index.tsx
index 29a5b5742..18a7417e7 100644
--- a/src/routes/secrets/index.tsx
+++ b/src/routes/secrets/index.tsx
@@ -67,7 +67,7 @@ function SecretList() {
         width: 120,
       },
       {
-        title: t('actions'),
+        title: t('table.actions'),
         valueType: 'option',
         key: 'option',
         width: 120,
@@ -119,7 +119,7 @@ function SecretList() {
                   <ToAddPageBtn
                     key="add"
                     to="/secrets/add"
-                    label={t('secrets.add.title')}
+                    label={t('info.add.title', { name: t('secrets.singular') })}
                   />
                 ),
               },
@@ -136,7 +136,7 @@ function RouteComponent() {
 
   return (
     <>
-      <PageHeader title={t('navbar.secrets')} />
+      <PageHeader title={t('sources.secrets')} />
       <SecretList />
     </>
   );
diff --git a/src/routes/services/add.tsx b/src/routes/services/add.tsx
index e8b3ec4c5..37b83ad9b 100644
--- a/src/routes/services/add.tsx
+++ b/src/routes/services/add.tsx
@@ -37,7 +37,7 @@ const ServiceAddForm = () => {
     mutationFn: postServiceReq,
     async onSuccess() {
       notifications.show({
-        message: t('services.add.success'),
+        message: t('info.add.success', { name: t('services.singular') }),
         color: 'green',
       });
       await router.navigate({ to: '/services' });
@@ -69,7 +69,9 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('services.add.title')} />
+      <PageHeader
+        title={t('info.add.title', { name: t('services.singular') })}
+      />
       <FormTOCBox>
         <ServiceAddForm />
       </FormTOCBox>
diff --git a/src/routes/services/detail.$id.tsx b/src/routes/services/detail.$id.tsx
index 5ab35f682..9c613f7a1 100644
--- a/src/routes/services/detail.$id.tsx
+++ b/src/routes/services/detail.$id.tsx
@@ -70,7 +70,7 @@ const ServiceDetailForm = (props: Props) => {
     mutationFn: putServiceReq,
     async onSuccess() {
       notifications.show({
-        message: t('services.edit.success'),
+        message: t('info.edit.success', { name: t('services.singular') }),
         color: 'green',
       });
       await refetch();
@@ -113,9 +113,9 @@ function RouteComponent() {
   return (
     <>
       <PageHeader
-        title={t('services.edit.title')}
+        title={t('info.edit.title', { name: t('services.singular') })}
         {...(readOnly && {
-          title: t('services.detail.title'),
+          title: t('info.detail.title', { name: t('services.singular') }),
           extra: (
             <Group>
               <Button
diff --git a/src/routes/services/index.tsx b/src/routes/services/index.tsx
index bb2234678..b01b776ed 100644
--- a/src/routes/services/index.tsx
+++ b/src/routes/services/index.tsx
@@ -79,7 +79,7 @@ const ServiceList = () => {
         },
       },
       {
-        title: t('actions'),
+        title: t('table.actions'),
         valueType: 'option',
         key: 'option',
         width: 120,
@@ -127,7 +127,9 @@ const ServiceList = () => {
                 label: (
                   <ToAddPageBtn
                     key="add"
-                    label={t('services.add.title')}
+                    label={t('info.add.title', {
+                      name: t('services.singular'),
+                    })}
                     to="/services/add"
                   />
                 ),
@@ -144,7 +146,7 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('services.title')} />
+      <PageHeader title={t('sources.services')} />
       <AntdConfigProvider>
         <ServiceList />
       </AntdConfigProvider>
diff --git a/src/routes/ssls/add.tsx b/src/routes/ssls/add.tsx
index e532877ab..fe84f82fd 100644
--- a/src/routes/ssls/add.tsx
+++ b/src/routes/ssls/add.tsx
@@ -42,7 +42,7 @@ const SSLAddForm = () => {
       req.post<unknown, APISIXType['RespSSLDetail']>(API_SSLS, data),
     async onSuccess() {
       notifications.show({
-        message: t('ssls.add.success'),
+        message: t('info.add.success', { name: t('ssls.singular') }),
         color: 'green',
       });
       await router.navigate({
@@ -75,7 +75,7 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('ssls.add.title')} />
+      <PageHeader title={t('info.add.title', { name: t('ssls.singular') })} />
       <FormTOCBox>
         <SSLAddForm />
       </FormTOCBox>
diff --git a/src/routes/ssls/detail.$id.tsx b/src/routes/ssls/detail.$id.tsx
index bde23ee7d..4c323131b 100644
--- a/src/routes/ssls/detail.$id.tsx
+++ b/src/routes/ssls/detail.$id.tsx
@@ -67,7 +67,7 @@ const SSLDetailForm = (props: Props & { id: string }) => {
     mutationFn: putSSLReq,
     async onSuccess() {
       notifications.show({
-        message: t('ssls.edit.success'),
+        message: t('info.edit.success', { name: t('ssls.singular') }),
         color: 'green',
       });
       await refetch();
@@ -118,9 +118,9 @@ function RouteComponent() {
   return (
     <>
       <PageHeader
-        title={t('ssls.edit.title')}
+        title={t('info.edit.title', { name: t('ssls.singular') })}
         {...(readOnly && {
-          title: t('ssls.detail.title'),
+          title: t('info.detail.title', { name: t('ssls.singular') }),
           extra: (
             <Group>
               <Button
diff --git a/src/routes/ssls/index.tsx b/src/routes/ssls/index.tsx
index ab6c9e45b..1b485136a 100644
--- a/src/routes/ssls/index.tsx
+++ b/src/routes/ssls/index.tsx
@@ -75,12 +75,12 @@ function RouteComponent() {
         title: t('form.basic.status'),
         key: 'status',
         valueEnum: {
-          1: { text: t('enabled'), status: 'Success' },
-          0: { text: t('disabled'), status: 'Error' },
+          1: { text: t('table.enabled'), status: 'Success' },
+          0: { text: t('table.disabled'), status: 'Error' },
         },
       },
       {
-        title: t('actions'),
+        title: t('table.actions'),
         valueType: 'option',
         key: 'option',
         width: 120,
@@ -104,7 +104,7 @@ function RouteComponent() {
 
   return (
     <>
-      <PageHeader title={t('navbar.ssls')} />
+      <PageHeader title={t('sources.ssls')} />
       <AntdConfigProvider>
         <ProTable
           columns={columns}
@@ -131,7 +131,7 @@ function RouteComponent() {
                     <ToAddPageBtn
                       key="add"
                       to="/ssls/add"
-                      label={t('ssls.add.title')}
+                      label={t('info.add.title', { name: t('ssls.singular') })}
                     />
                   ),
                 },
diff --git a/src/routes/stream_routes/add.tsx b/src/routes/stream_routes/add.tsx
index a624ee489..0e986a980 100644
--- a/src/routes/stream_routes/add.tsx
+++ b/src/routes/stream_routes/add.tsx
@@ -37,7 +37,7 @@ const StreamRouteAddForm = () => {
     mutationFn: postStreamRouteReq,
     async onSuccess() {
       notifications.show({
-        message: t('streamRoutes.add.success'),
+        message: t('info.add.success', { name: t('streamRoutes.singular') }),
         color: 'green',
       });
       await router.navigate({ to: '/stream_routes' });
@@ -69,7 +69,9 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('streamRoutes.add.title')} />
+      <PageHeader
+        title={t('info.add.title', { name: t('streamRoutes.singular') })}
+      />
       <FormTOCBox>
         <StreamRouteAddForm />
       </FormTOCBox>
diff --git a/src/routes/stream_routes/detail.$id.tsx b/src/routes/stream_routes/detail.$id.tsx
index 452cfd312..4b634851e 100644
--- a/src/routes/stream_routes/detail.$id.tsx
+++ b/src/routes/stream_routes/detail.$id.tsx
@@ -73,7 +73,7 @@ const StreamRouteDetailForm = (props: Props) => {
     mutationFn: putStreamRouteReq,
     async onSuccess() {
       notifications.show({
-        message: t('streamRoutes.edit.success'),
+        message: t('info.edit.success', { name: t('streamRoutes.singular') }),
         color: 'green',
       });
       await refetch();
@@ -116,9 +116,9 @@ function RouteComponent() {
   return (
     <>
       <PageHeader
-        title={t('streamRoutes.edit.title')}
+        title={t('info.edit.title', { name: t('streamRoutes.singular') })}
         {...(readOnly && {
-          title: t('streamRoutes.detail.title'),
+          title: t('info.detail.title', { name: t('streamRoutes.singular') }),
           extra: (
             <Group>
               <Button
diff --git a/src/routes/stream_routes/index.tsx b/src/routes/stream_routes/index.tsx
index cae54bcda..b7b5dd5b2 100644
--- a/src/routes/stream_routes/index.tsx
+++ b/src/routes/stream_routes/index.tsx
@@ -70,7 +70,7 @@ const StreamRouteList = () => {
         valueType: 'text',
       },
       {
-        title: t('actions'),
+        title: t('table.actions'),
         valueType: 'option',
         key: 'option',
         width: 120,
@@ -118,7 +118,9 @@ const StreamRouteList = () => {
                 label: (
                   <ToAddPageBtn
                     key="add"
-                    label={t('streamRoutes.add.title')}
+                    label={t('info.add.title', {
+                      name: t('streamRoutes.singular'),
+                    })}
                     to="/stream_routes/add"
                   />
                 ),
@@ -136,10 +138,8 @@ function StreamRouteComponent() {
 
   return (
     <>
-      <PageHeader title={t('streamRoutes.title')} />
-      <AntdConfigProvider>
-        <StreamRouteList />
-      </AntdConfigProvider>
+      <PageHeader title={t('sources.streamRoutes')} />
+      <StreamRouteList />
     </>
   );
 }
diff --git a/src/routes/upstreams/add.tsx b/src/routes/upstreams/add.tsx
index 642ae1b7b..55d1c7f4b 100644
--- a/src/routes/upstreams/add.tsx
+++ b/src/routes/upstreams/add.tsx
@@ -18,7 +18,6 @@ import { zodResolver } from '@hookform/resolvers/zod';
 import { notifications } from '@mantine/notifications';
 import { useMutation } from '@tanstack/react-query';
 import { createFileRoute, useRouter } from '@tanstack/react-router';
-import {} from 'axios';
 import { FormProvider, useForm } from 'react-hook-form';
 import { useTranslation } from 'react-i18next';
 import type { z } from 'zod';
@@ -47,7 +46,7 @@ const UpstreamAddForm = () => {
       req.post<unknown, APISIXType['RespUpstreamDetail']>(API_UPSTREAMS, data),
     async onSuccess(data) {
       notifications.show({
-        message: t('upstreams.add.success'),
+        message: t('info.add.success', { name: t('upstreams.singular') }),
         color: 'green',
       });
       await router.navigate({
@@ -80,7 +79,9 @@ function RouteComponent() {
   const { t } = useTranslation();
   return (
     <>
-      <PageHeader title={t('upstreams.add.title')} />
+      <PageHeader
+        title={t('info.add.title', { name: t('upstreams.singular') })}
+      />
       <FormTOCBox>
         <UpstreamAddForm />
       </FormTOCBox>
diff --git a/src/routes/upstreams/detail.$id.tsx b/src/routes/upstreams/detail.$id.tsx
index 0d65fca32..1ac7bcd23 100644
--- a/src/routes/upstreams/detail.$id.tsx
+++ b/src/routes/upstreams/detail.$id.tsx
@@ -68,7 +68,7 @@ const UpstreamDetailForm = (
     mutationFn: putUpstreamReq,
     async onSuccess() {
       notifications.show({
-        message: t('upstreams.edit.success'),
+        message: t('info.edit.success', { name: t('upstreams.singular') }),
         color: 'green',
       });
       await refetch();
@@ -119,9 +119,9 @@ function RouteComponent() {
   return (
     <>
       <PageHeader
-        title={t('upstreams.edit.title')}
+        title={t('info.edit.title', { name: t('upstreams.singular') })}
         {...(readOnly && {
-          title: t('upstreams.detail.title'),
+          title: t('info.detail.title', { name: t('upstreams.singular') }),
           extra: (
             <Group>
               <Button
diff --git a/src/routes/upstreams/index.tsx b/src/routes/upstreams/index.tsx
index 8ed759b7f..9b7eeb398 100644
--- a/src/routes/upstreams/index.tsx
+++ b/src/routes/upstreams/index.tsx
@@ -92,13 +92,13 @@ function RouteComponent() {
       },
       {
         dataIndex: ['value', 'scheme'],
-        title: t('form.upstream.scheme'),
+        title: t('form.upstreams.scheme'),
         key: 'scheme',
         valueType: 'text',
       },
       {
         dataIndex: ['value', 'update_time'],
-        title: t('form.upstream.updateTime'),
+        title: t('form.upstreams.updateTime'),
         key: 'update_time',
         valueType: 'dateTime',
         sorter: true,
@@ -108,7 +108,7 @@ function RouteComponent() {
         },
       },
       {
-        title: t('actions'),
+        title: t('table.actions'),
         valueType: 'option',
         key: 'option',
         width: 120,
@@ -132,7 +132,7 @@ function RouteComponent() {
 
   return (
     <>
-      <PageHeader title={t('upstreams.title')} />
+      <PageHeader title={t('sources.upstreams')} />
       <AntdConfigProvider>
         <ProTable
           columns={columns}
@@ -159,7 +159,9 @@ function RouteComponent() {
                     <ToAddPageBtn
                       key="add"
                       to="/upstreams/add"
-                      label={t('upstreams.add.title')}
+                      label={t('info.add.title', {
+                        name: t('upstreams.singular'),
+                      })}
                     />
                   ),
                 },