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

maximebeauchemin pushed a commit to branch eslit-no-title-case
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/eslit-no-title-case by this 
push:
     new 16b4ec347d feat(i18n): Add ESLint rule to enforce sentence case in 
translations
16b4ec347d is described below

commit 16b4ec347d8c98a80275f1cbbc0b8755f2fc9378
Author: Maxime Beauchemin <[email protected]>
AuthorDate: Thu Jul 31 13:36:41 2025 -0700

    feat(i18n): Add ESLint rule to enforce sentence case in translations
    
    This commit introduces a new ESLint rule 'i18n-strings/no-title-case' that 
enforces
    sentence case instead of title case in translation strings, aligning with 
the recent
    UI modernization effort to use sentence case throughout the application.
    
    Key changes:
    - Add 'no-title-case' rule to detect title case patterns in t() and tn() 
functions
    - Rule intelligently skips: single words, acronyms, placeholders, and 
multi-sentence strings
    - Enhanced error messages to show the actual violating string for easier 
identification
    - Enable the rule as an error in .eslintrc.js
    - Add comprehensive test coverage for the new rule
    
    Fix title case violations across the codebase:
    - Convert "Yes"/"No" to "yes"/"no" in list filters
    - Fix "Virtual"/"Physical" to lowercase in DatasetList
    - Update various UI labels: "Create Chart", "Dataset Name", "Chart Source", 
etc.
    - Fix security page labels: "Row Level Security", "Filter Type", "Group Key"
    - Update time-related labels: "Time Range", "Time Column", "Time Grain"
    - Fix SqlLab keyboard shortcuts: "Previous Line" to "Previous line"
    - Fix additional violations: "Untitled Dataset", "Include Template 
Parameters",
      "Affected Dashboards/Charts", "Delete Dataset?", "0 Selected", "List 
Users",
      "Open Datasource tab"
    
    This change helps maintain consistency with the new sentence case standard 
and
    prevents future title case violations from being introduced.
    
    🤖 Generated with [Claude Code](https://claude.ai/code)
    
    Co-Authored-By: Claude <[email protected]>
---
 superset-frontend/.eslintrc.js                     |   1 +
 .../eslint-plugin-i18n-strings/index.js            | 131 +++++++++++++++++-
 .../no-title-case.test.js                          | 152 +++++++++++++++++++++
 .../superset-ui-chart-controls/src/constants.ts    |   8 +-
 .../components/ExploreResultsButton/index.tsx      |   2 +-
 .../components/KeyboardShortcutButton/index.tsx    |   2 +-
 .../SqlLab/components/SaveDatasetModal/index.tsx   |   8 +-
 .../components/ExploreViewContainer/index.jsx      |   4 +-
 .../src/explore/components/SaveModal.tsx           |   2 +-
 superset-frontend/src/pages/ChartList/index.tsx    |   4 +-
 .../src/pages/DashboardList/index.tsx              |   8 +-
 superset-frontend/src/pages/DatasetList/index.tsx  |  16 +--
 .../src/pages/RowLevelSecurityList/index.tsx       |  14 +-
 superset-frontend/src/pages/UsersList/index.tsx    |   4 +-
 14 files changed, 319 insertions(+), 37 deletions(-)

diff --git a/superset-frontend/.eslintrc.js b/superset-frontend/.eslintrc.js
index bd87c8c6a4..acab08bd72 100644
--- a/superset-frontend/.eslintrc.js
+++ b/superset-frontend/.eslintrc.js
@@ -403,6 +403,7 @@ module.exports = {
     'theme-colors/no-literal-colors': 'error',
     'icons/no-fa-icons-usage': 'error',
     'i18n-strings/no-template-vars': ['error', true],
+    'i18n-strings/no-title-case': 'error',
     camelcase: [
       'error',
       {
diff --git a/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/index.js 
b/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/index.js
index 9f3a54c42a..d59a2a44bf 100644
--- a/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/index.js
+++ b/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/index.js
@@ -41,7 +41,7 @@ module.exports = {
               context.report({
                 node,
                 message:
-                  "Don't use variables in translation string templates. 
Flask-babel is a static translation service, so it can’t handle strings that 
include variables",
+                  "Don't use variables in translation string templates. 
Flask-babel is a static translation service, so it can't handle strings that 
include variables",
               });
             }
           }
@@ -52,5 +52,134 @@ module.exports = {
         };
       },
     },
+    'no-title-case': {
+      create(context) {
+        function checkTitleCase(str) {
+          // Skip strings with placeholders like %s, %d, %(name)s, etc.
+          if (/%[sdf]|%\([^)]+\)[sdf]/.test(str)) {
+            return false;
+          }
+
+          // Skip strings that are all uppercase (likely acronyms)
+          if (str === str.toUpperCase()) {
+            return false;
+          }
+
+          // Skip strings with periods (likely multiple sentences)
+          if (str.includes('.')) {
+            return false;
+          }
+
+          // Skip single words
+          const words = str.trim().split(/\s+/);
+          if (words.length <= 1) {
+            return false;
+          }
+
+          // Whitelist of words that are commonly capitalized in product names
+          // but should not trigger title case warnings
+          const productWords = [
+            'Lab',
+            'Server',
+            'Studio',
+            'Pro',
+            'Plus',
+            'Max',
+            'Mini',
+          ];
+
+          // Common prepositions and articles that should be lowercase (unless 
at start)
+          const lowercaseWords = [
+            'a',
+            'an',
+            'the',
+            'and',
+            'or',
+            'but',
+            'for',
+            'with',
+            'to',
+            'from',
+            'in',
+            'on',
+            'at',
+            'by',
+            'of',
+          ];
+
+          // Check if the string uses title case (multiple words with first 
letter capitalized)
+          const hasTitleCase = words.some((word, index) => {
+            // Skip first word
+            if (index === 0) {
+              return false;
+            }
+
+            // Skip acronyms (all uppercase)
+            if (word === word.toUpperCase()) {
+              return false;
+            }
+
+            // Skip whitelisted product words when preceded by an uppercase 
word
+            if (
+              productWords.includes(word) &&
+              index > 0 &&
+              words[index - 1] === words[index - 1].toUpperCase()
+            ) {
+              return false;
+            }
+
+            // Check if it's a lowercase word that's incorrectly capitalized
+            if (
+              lowercaseWords.includes(word.toLowerCase()) &&
+              /^[A-Z]/.test(word)
+            ) {
+              return true;
+            }
+
+            // For other words, check if they start with capital letter
+            return (
+              word.length > 1 &&
+              /^[A-Z]/.test(word) &&
+              !productWords.includes(word)
+            );
+          });
+
+          return hasTitleCase;
+        }
+
+        function handler(node) {
+          if (node.arguments.length) {
+            const firstArg = node.arguments[0];
+            let stringValue = null;
+
+            // Extract string value based on node type
+            if (
+              firstArg.type === 'Literal' &&
+              typeof firstArg.value === 'string'
+            ) {
+              stringValue = firstArg.value;
+            } else if (
+              firstArg.type === 'TemplateLiteral' &&
+              firstArg.quasis.length === 1
+            ) {
+              // Handle template literals without expressions
+              stringValue = firstArg.quasis[0].value.raw;
+            }
+
+            if (stringValue && checkTitleCase(stringValue)) {
+              context.report({
+                node: firstArg,
+                message: `Avoid title case in i18n strings: "${stringValue}". 
Use sentence case instead.`,
+              });
+            }
+          }
+        }
+
+        return {
+          "CallExpression[callee.name='t']": handler,
+          "CallExpression[callee.name='tn']": handler,
+        };
+      },
+    },
   },
 };
diff --git 
a/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/no-title-case.test.js
 
b/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/no-title-case.test.js
new file mode 100644
index 0000000000..3e2ba0d150
--- /dev/null
+++ 
b/superset-frontend/eslint-rules/eslint-plugin-i18n-strings/no-title-case.test.js
@@ -0,0 +1,152 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+const { RuleTester } = require('eslint');
+const plugin = require('./index');
+
+const ruleTester = new RuleTester({
+  parserOptions: {
+    ecmaVersion: 6,
+  },
+});
+
+const rule = plugin.rules['no-title-case'];
+
+ruleTester.run('no-title-case', rule, {
+  valid: [
+    // Sentence case (correct)
+    {
+      code: "t('Add a divider')",
+    },
+    {
+      code: "t('Create new dashboard')",
+    },
+    {
+      code: "t('Save and continue')",
+    },
+    // Single words
+    {
+      code: "t('Save')",
+    },
+    {
+      code: "t('Delete')",
+    },
+    // All uppercase (acronyms)
+    {
+      code: "t('SQL')",
+    },
+    {
+      code: "t('API KEY')",
+    },
+    // With placeholders
+    {
+      code: "t('Deleted: %s', name)",
+    },
+    {
+      code: "t('User %(username)s added', { username })",
+    },
+    // Template literals without expressions
+    {
+      code: 't(`Add a new filter`)',
+    },
+    // Mixed case but not title case
+    {
+      code: "t('Use SQL Lab')",
+    },
+    // tn function
+    {
+      code: "tn('Add a filter', 'Add filters', count)",
+    },
+    // Multiple sentences with period
+    {
+      code: "t('Welcome Back. Please Login.')",
+    },
+    {
+      code: "t('Save Changes. This Will Update All Records.')",
+    },
+  ],
+  invalid: [
+    // Title case (incorrect)
+    {
+      code: "t('Add Divider')",
+      errors: [
+        {
+          message:
+            'Avoid title case in i18n strings: "Add Divider". Use sentence 
case instead.',
+        },
+      ],
+    },
+    {
+      code: "t('Create New Dashboard')",
+      errors: [
+        {
+          message:
+            'Avoid title case in i18n strings: "Create New Dashboard". Use 
sentence case instead.',
+        },
+      ],
+    },
+    {
+      code: "t('Save And Continue')",
+      errors: [
+        {
+          message:
+            'Avoid title case in i18n strings: "Save And Continue". Use 
sentence case instead.',
+        },
+      ],
+    },
+    {
+      code: "t('Add Filter')",
+      errors: [
+        {
+          message:
+            'Avoid title case in i18n strings: "Add Filter". Use sentence case 
instead.',
+        },
+      ],
+    },
+    {
+      code: "t('Edit User')",
+      errors: [
+        {
+          message:
+            'Avoid title case in i18n strings: "Edit User". Use sentence case 
instead.',
+        },
+      ],
+    },
+    // Template literals
+    {
+      code: 't(`Add Layer`)',
+      errors: [
+        {
+          message:
+            'Avoid title case in i18n strings: "Add Layer". Use sentence case 
instead.',
+        },
+      ],
+    },
+    // tn function
+    {
+      code: "tn('Delete Item', 'Delete Items', count)",
+      errors: [
+        {
+          message:
+            'Avoid title case in i18n strings: "Delete Item". Use sentence 
case instead.',
+        },
+      ],
+    },
+  ],
+});
diff --git 
a/superset-frontend/packages/superset-ui-chart-controls/src/constants.ts 
b/superset-frontend/packages/superset-ui-chart-controls/src/constants.ts
index 394c2c7f30..2f7532b389 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/constants.ts
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/constants.ts
@@ -30,10 +30,10 @@ export const DEFAULT_MAX_ROW_TABLE_SERVER = 500000;
 
 // eslint-disable-next-line import/prefer-default-export
 export const TIME_FILTER_LABELS = {
-  time_range: t('Time Range'),
-  granularity_sqla: t('Time Column'),
-  time_grain_sqla: t('Time Grain'),
-  granularity: t('Time Granularity'),
+  time_range: t('Time range'),
+  granularity_sqla: t('Time column'),
+  time_grain_sqla: t('Time grain'),
+  granularity: t('Time granularity'),
 };
 
 export const COLUMN_NAME_ALIASES: Record<string, string> = {
diff --git 
a/superset-frontend/src/SqlLab/components/ExploreResultsButton/index.tsx 
b/superset-frontend/src/SqlLab/components/ExploreResultsButton/index.tsx
index 53f9cdc2b0..415b5beb3e 100644
--- a/superset-frontend/src/SqlLab/components/ExploreResultsButton/index.tsx
+++ b/superset-frontend/src/SqlLab/components/ExploreResultsButton/index.tsx
@@ -46,7 +46,7 @@ const ExploreResultsButton = ({
       tooltip={t('Explore the result set in the data exploration view')}
       data-test="explore-results-button"
     >
-      {t('Create Chart')}
+      {t('Create chart')}
     </Button>
   );
 };
diff --git 
a/superset-frontend/src/SqlLab/components/KeyboardShortcutButton/index.tsx 
b/superset-frontend/src/SqlLab/components/KeyboardShortcutButton/index.tsx
index e9749a5618..217e724f42 100644
--- a/superset-frontend/src/SqlLab/components/KeyboardShortcutButton/index.tsx
+++ b/superset-frontend/src/SqlLab/components/KeyboardShortcutButton/index.tsx
@@ -51,7 +51,7 @@ export const KEY_MAP: Record<KeyboardShortcut, string | 
undefined> = {
   [KeyboardShortcut.CtrlE]: userOS !== 'MacOS' ? t('Stop query') : undefined,
   [KeyboardShortcut.CtrlQ]: userOS === 'Windows' ? t('New tab') : undefined,
   [KeyboardShortcut.CtrlT]: userOS !== 'Windows' ? t('New tab') : undefined,
-  [KeyboardShortcut.CtrlP]: t('Previous Line'),
+  [KeyboardShortcut.CtrlP]: t('Previous line'),
   [KeyboardShortcut.CtrlShiftF]: t('Format SQL'),
   [KeyboardShortcut.CtrlLeft]: t('Switch to the previous tab'),
   [KeyboardShortcut.CtrlRight]: t('Switch to the next tab'),
diff --git a/superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx 
b/superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx
index 6186a1e900..16ad5ad6c6 100644
--- a/superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx
+++ b/superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx
@@ -158,7 +158,7 @@ const updateDataset = async (
   return data.json.result;
 };
 
-const UNTITLED = t('Untitled Dataset');
+const UNTITLED = t('Untitled dataset');
 
 export const SaveDatasetModal = ({
   visible,
@@ -374,10 +374,10 @@ export const SaveDatasetModal = ({
   return (
     <Modal
       show={visible}
-      name={t('Save or Overwrite Dataset')}
+      name={t('Save or overwrite dataset')}
       title={
         <ModalTitleWithIcon
-          title={t('Save or Overwrite Dataset')}
+          title={t('Save or overwrite dataset')}
           icon={<Icons.SaveOutlined />}
           data-test="save-or-overwrite-dataset-title"
         />
@@ -394,7 +394,7 @@ export const SaveDatasetModal = ({
                 }
               />
               <span style={{ marginLeft: '5px' }}>
-                {t('Include Template Parameters')}
+                {t('Include template parameters')}
               </span>
             </div>
           )}
diff --git 
a/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx 
b/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx
index 13b67c5b99..9d64e3e713 100644
--- a/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx
+++ b/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx
@@ -637,7 +637,7 @@ function ExploreViewContainer(props) {
           }
         >
           <div className="title-container">
-            <span className="horizontal-text">{t('Chart Source')}</span>
+            <span className="horizontal-text">{t('Chart source')}</span>
             <span
               role="button"
               tabIndex={0}
@@ -672,7 +672,7 @@ function ExploreViewContainer(props) {
             tabIndex={0}
           >
             <span role="button" tabIndex={0} className="action-button">
-              <Tooltip title={t('Open Datasource tab')}>
+              <Tooltip title={t('Open datasource tab')}>
                 <Icons.VerticalAlignTopOutlined
                   iconSize="xl"
                   css={css`
diff --git a/superset-frontend/src/explore/components/SaveModal.tsx 
b/superset-frontend/src/explore/components/SaveModal.tsx
index 6b737e0c22..c79c209e6e 100644
--- a/superset-frontend/src/explore/components/SaveModal.tsx
+++ b/superset-frontend/src/explore/components/SaveModal.tsx
@@ -370,7 +370,7 @@ class SaveModal extends Component<SaveModalProps, 
SaveModalState> {
           />
         </FormItem>
         {this.props.datasource?.type === 'query' && (
-          <FormItem label={t('Dataset Name')} required>
+          <FormItem label={t('Dataset name')} required>
             <InfoTooltip
               tooltip={t('A reusable dataset will be saved with your chart.')}
               placement="right"
diff --git a/superset-frontend/src/pages/ChartList/index.tsx 
b/superset-frontend/src/pages/ChartList/index.tsx
index 5696438eab..b79d25a774 100644
--- a/superset-frontend/src/pages/ChartList/index.tsx
+++ b/superset-frontend/src/pages/ChartList/index.tsx
@@ -575,8 +575,8 @@ function ChartList(props: ChartListProps) {
       operator: FilterOperator.ChartIsFav,
       unfilteredLabel: t('Any'),
       selects: [
-        { label: t('Yes'), value: true },
-        { label: t('No'), value: false },
+        { label: t('yes'), value: true },
+        { label: t('no'), value: false },
       ],
     }),
     [],
diff --git a/superset-frontend/src/pages/DashboardList/index.tsx 
b/superset-frontend/src/pages/DashboardList/index.tsx
index 25856e7179..b7c4f1308e 100644
--- a/superset-frontend/src/pages/DashboardList/index.tsx
+++ b/superset-frontend/src/pages/DashboardList/index.tsx
@@ -530,8 +530,8 @@ function DashboardList(props: DashboardListProps) {
       operator: FilterOperator.DashboardIsFav,
       unfilteredLabel: t('Any'),
       selects: [
-        { label: t('Yes'), value: true },
-        { label: t('No'), value: false },
+        { label: t('yes'), value: true },
+        { label: t('no'), value: false },
       ],
     }),
     [],
@@ -604,8 +604,8 @@ function DashboardList(props: DashboardListProps) {
         operator: FilterOperator.DashboardIsCertified,
         unfilteredLabel: t('Any'),
         selects: [
-          { label: t('Yes'), value: true },
-          { label: t('No'), value: false },
+          { label: t('yes'), value: true },
+          { label: t('no'), value: false },
         ],
       },
       {
diff --git a/superset-frontend/src/pages/DatasetList/index.tsx 
b/superset-frontend/src/pages/DatasetList/index.tsx
index 25e655c8ea..1e98b91b32 100644
--- a/superset-frontend/src/pages/DatasetList/index.tsx
+++ b/superset-frontend/src/pages/DatasetList/index.tsx
@@ -530,8 +530,8 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
         operator: FilterOperator.DatasetIsNullOrEmpty,
         unfilteredLabel: 'All',
         selects: [
-          { label: t('Virtual'), value: false },
-          { label: t('Physical'), value: true },
+          { label: t('virtual'), value: false },
+          { label: t('physical'), value: true },
         ],
       },
       {
@@ -598,8 +598,8 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
         operator: FilterOperator.DatasetIsCertified,
         unfilteredLabel: t('Any'),
         selects: [
-          { label: t('Yes'), value: true },
-          { label: t('No'), value: false },
+          { label: t('yes'), value: true },
+          { label: t('no'), value: false },
         ],
       },
       {
@@ -764,7 +764,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
               </p>
               {datasetCurrentlyDeleting.dashboards.count >= 1 && (
                 <>
-                  <h4>{t('Affected Dashboards')}</h4>
+                  <h4>{t('Affected dashboards')}</h4>
                   <List
                     split={false}
                     size="small"
@@ -807,7 +807,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
               )}
               {datasetCurrentlyDeleting.charts.count >= 1 && (
                 <>
-                  <h4>{t('Affected Charts')}</h4>
+                  <h4>{t('Affected charts')}</h4>
                   <List
                     split={false}
                     size="small"
@@ -860,7 +860,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
           }}
           onHide={closeDatasetDeleteModal}
           open
-          title={t('Delete Dataset?')}
+          title={t('Delete dataset?')}
         />
       )}
       {datasetCurrentlyEditing && (
@@ -931,7 +931,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
                 );
 
                 if (!selected.length) {
-                  return t('0 Selected');
+                  return t('0 selected');
                 }
                 if (virtualCount && !physicalCount) {
                   return t(
diff --git a/superset-frontend/src/pages/RowLevelSecurityList/index.tsx 
b/superset-frontend/src/pages/RowLevelSecurityList/index.tsx
index fa0f3085f5..3626b91930 100644
--- a/superset-frontend/src/pages/RowLevelSecurityList/index.tsx
+++ b/superset-frontend/src/pages/RowLevelSecurityList/index.tsx
@@ -65,7 +65,7 @@ function RowLevelSecurityList(props: RLSProps) {
     toggleBulkSelect,
   } = useListViewResource<RLSObject>(
     'rowlevelsecurity',
-    t('Row Level Security'),
+    t('Row level security'),
     addDangerToast,
     true,
     undefined,
@@ -130,13 +130,13 @@ function RowLevelSecurityList(props: RLSProps) {
       },
       {
         accessor: 'filter_type',
-        Header: t('Filter Type'),
+        Header: t('Filter type'),
         size: 'xl',
         id: 'filter_type',
       },
       {
         accessor: 'group_key',
-        Header: t('Group Key'),
+        Header: t('Group key'),
         size: 'xl',
         id: 'group_key',
       },
@@ -246,7 +246,7 @@ function RowLevelSecurityList(props: RLSProps) {
   );
 
   const emptyState = {
-    title: t('No Rules yet'),
+    title: t('No rules yet'),
     image: 'filter-results.svg',
     buttonAction: () => handleRuleEdit(null),
     buttonIcon: canEdit ? (
@@ -265,7 +265,7 @@ function RowLevelSecurityList(props: RLSProps) {
         operator: FilterOperator.StartsWith,
       },
       {
-        Header: t('Filter Type'),
+        Header: t('Filter type'),
         key: 'filter_type',
         id: 'filter_type',
         input: 'select',
@@ -277,7 +277,7 @@ function RowLevelSecurityList(props: RLSProps) {
         ],
       },
       {
-        Header: t('Group Key'),
+        Header: t('Group key'),
         key: 'search',
         id: 'group_key',
         input: 'search',
@@ -329,7 +329,7 @@ function RowLevelSecurityList(props: RLSProps) {
 
   return (
     <>
-      <SubMenu name={t('Row Level Security')} buttons={subMenuButtons} />
+      <SubMenu name={t('Row level security')} buttons={subMenuButtons} />
       <ConfirmStatusChange
         title={t('Please confirm')}
         description={t('Are you sure you want to delete the selected rules?')}
diff --git a/superset-frontend/src/pages/UsersList/index.tsx 
b/superset-frontend/src/pages/UsersList/index.tsx
index bd1d65ad93..6a4b81c768 100644
--- a/superset-frontend/src/pages/UsersList/index.tsx
+++ b/superset-frontend/src/pages/UsersList/index.tsx
@@ -519,7 +519,7 @@ function UsersList({ user }: UsersListProps) {
 
   return (
     <>
-      <SubMenu name={t('List Users')} buttons={subMenuButtons} />
+      <SubMenu name={t('List users')} buttons={subMenuButtons} />
       <UserListAddModal
         onHide={() => closeModal(ModalType.ADD)}
         show={modalState.add}
@@ -554,7 +554,7 @@ function UsersList({ user }: UsersListProps) {
           }}
           onHide={() => setUserCurrentlyDeleting(null)}
           open
-          title={t('Delete User?')}
+          title={t('Delete user?')}
         />
       )}
       <ConfirmStatusChange

Reply via email to