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

yongjiezhao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new f9d28a1072 chore: add eslint custom plugin to prevent translation 
variables (#19828)
f9d28a1072 is described below

commit f9d28a107266aff1fea10056ec69d437981df1bd
Author: Stephen Liu <[email protected]>
AuthorDate: Wed Apr 27 17:44:13 2022 +0800

    chore: add eslint custom plugin to prevent translation variables (#19828)
---
 superset-frontend/.eslintrc.js                     | 10 +++-
 superset-frontend/jest.config.js                   |  2 +-
 superset-frontend/package-lock.json                | 27 ++++++++-
 superset-frontend/package.json                     |  1 +
 .../src/SqlLab/utils/newQueryTabName.ts            |  2 +-
 .../src/views/CRUD/annotation/AnnotationList.tsx   |  3 +-
 .../tools/eslint-plugin-translation-vars/index.js  | 56 ++++++++++++++++++
 .../no-template-vars.test.js                       | 68 ++++++++++++++++++++++
 .../eslint-plugin-translation-vars/package.json    | 20 +++++++
 9 files changed, 184 insertions(+), 5 deletions(-)

diff --git a/superset-frontend/.eslintrc.js b/superset-frontend/.eslintrc.js
index d4751c18ce..b77de41338 100644
--- a/superset-frontend/.eslintrc.js
+++ b/superset-frontend/.eslintrc.js
@@ -67,7 +67,13 @@ module.exports = {
       version: 'detect',
     },
   },
-  plugins: ['prettier', 'react', 'file-progress', 'theme-colors'],
+  plugins: [
+    'prettier',
+    'react',
+    'file-progress',
+    'theme-colors',
+    'translation-vars',
+  ],
   overrides: [
     {
       files: ['*.ts', '*.tsx'],
@@ -198,12 +204,14 @@ module.exports = {
       ],
       rules: {
         'theme-colors/no-literal-colors': 0,
+        'translation-vars/no-template-vars': 0,
         'no-restricted-imports': 0,
       },
     },
   ],
   rules: {
     'theme-colors/no-literal-colors': 1,
+    'translation-vars/no-template-vars': ['error', true],
     camelcase: [
       'error',
       {
diff --git a/superset-frontend/jest.config.js b/superset-frontend/jest.config.js
index 8ef49454b0..18d20a1f97 100644
--- a/superset-frontend/jest.config.js
+++ b/superset-frontend/jest.config.js
@@ -19,7 +19,7 @@
 
 module.exports = {
   testRegex:
-    
'\\/superset-frontend\\/(spec|src|plugins|packages)\\/.*(_spec|\\.test)\\.[jt]sx?$',
+    
'\\/superset-frontend\\/(spec|src|plugins|packages|tools)\\/.*(_spec|\\.test)\\.[jt]sx?$',
   moduleNameMapper: {
     '\\.(css|less|geojson)$': '<rootDir>/spec/__mocks__/mockExportObject.js',
     '\\.(gif|ttf|eot|png|jpg)$': 
'<rootDir>/spec/__mocks__/mockExportString.js',
diff --git a/superset-frontend/package-lock.json 
b/superset-frontend/package-lock.json
index 7ac71b41cd..07f2ab7601 100644
--- a/superset-frontend/package-lock.json
+++ b/superset-frontend/package-lock.json
@@ -234,6 +234,7 @@
         "eslint-plugin-react-hooks": "^4.2.0",
         "eslint-plugin-testing-library": "^3.10.1",
         "eslint-plugin-theme-colors": "file:tools/eslint-plugin-theme-colors",
+        "eslint-plugin-translation-vars": 
"file:tools/eslint-plugin-translation-vars",
         "exports-loader": "^0.7.0",
         "fetch-mock": "^7.7.3",
         "fork-ts-checker-webpack-plugin": "^6.3.3",
@@ -33942,6 +33943,10 @@
       "resolved": "tools/eslint-plugin-theme-colors",
       "link": true
     },
+    "node_modules/eslint-plugin-translation-vars": {
+      "resolved": "tools/eslint-plugin-translation-vars",
+      "link": true
+    },
     "node_modules/eslint-scope": {
       "version": "5.1.1",
       "resolved": 
"https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz";,
@@ -60691,7 +60696,23 @@
     "tools/eslint-plugin-theme-colors": {
       "version": "1.0.0",
       "dev": true,
-      "license": "Apache-2.0"
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^16.9.1",
+        "npm": "^7.5.4"
+      }
+    },
+    "tools/eslint-plugin-translation-vars": {
+      "version": "1.0.0",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^16.9.1",
+        "npm": "^7.5.4"
+      },
+      "peerDependencies": {
+        "eslint": ">=0.8.0"
+      }
     }
   },
   "dependencies": {
@@ -87649,6 +87670,10 @@
     "eslint-plugin-theme-colors": {
       "version": "file:tools/eslint-plugin-theme-colors"
     },
+    "eslint-plugin-translation-vars": {
+      "version": "file:tools/eslint-plugin-translation-vars",
+      "requires": {}
+    },
     "eslint-scope": {
       "version": "5.1.1",
       "resolved": 
"https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz";,
diff --git a/superset-frontend/package.json b/superset-frontend/package.json
index 5cf75e7c44..118377ee10 100644
--- a/superset-frontend/package.json
+++ b/superset-frontend/package.json
@@ -294,6 +294,7 @@
     "eslint-plugin-react-hooks": "^4.2.0",
     "eslint-plugin-testing-library": "^3.10.1",
     "eslint-plugin-theme-colors": "file:tools/eslint-plugin-theme-colors",
+    "eslint-plugin-translation-vars": 
"file:tools/eslint-plugin-translation-vars",
     "exports-loader": "^0.7.0",
     "fetch-mock": "^7.7.3",
     "fork-ts-checker-webpack-plugin": "^6.3.3",
diff --git a/superset-frontend/src/SqlLab/utils/newQueryTabName.ts 
b/superset-frontend/src/SqlLab/utils/newQueryTabName.ts
index a719a74af5..3815226cd4 100644
--- a/superset-frontend/src/SqlLab/utils/newQueryTabName.ts
+++ b/superset-frontend/src/SqlLab/utils/newQueryTabName.ts
@@ -40,7 +40,7 @@ export const newQueryTabName = (
       // When there are query tabs open, and at least one is called "Untitled 
Query #"
       // Where # is a valid number
       const largestNumber: number = Math.max(...untitledQueryNumbers);
-      return t(`${untitledQuery}%s`, largestNumber + 1);
+      return t('%s%s', untitledQuery, largestNumber + 1);
     }
     return resultTitle;
   }
diff --git a/superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx 
b/superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx
index a4599b9ff5..6dedb5e0ea 100644
--- a/superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx
+++ b/superset-frontend/src/views/CRUD/annotation/AnnotationList.tsx
@@ -280,7 +280,8 @@ function AnnotationList({
       {annotationCurrentlyDeleting && (
         <DeleteModal
           description={t(
-            `Are you sure you want to delete 
${annotationCurrentlyDeleting?.short_descr}?`,
+            'Are you sure you want to delete %s?',
+            annotationCurrentlyDeleting?.short_descr,
           )}
           onConfirm={() => {
             if (annotationCurrentlyDeleting) {
diff --git a/superset-frontend/tools/eslint-plugin-translation-vars/index.js 
b/superset-frontend/tools/eslint-plugin-translation-vars/index.js
new file mode 100644
index 0000000000..69493f3b9e
--- /dev/null
+++ b/superset-frontend/tools/eslint-plugin-translation-vars/index.js
@@ -0,0 +1,56 @@
+/**
+ * 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.
+ */
+
+/**
+ * @fileoverview Rule to warn about translation template variables
+ * @author Apache
+ */
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+/** @type {import('eslint').Rule.RuleModule} */
+module.exports = {
+  rules: {
+    'no-template-vars': {
+      create(context) {
+        function handler(node) {
+          if (node.arguments.length) {
+            const firstArgs = node.arguments[0];
+            if (
+              firstArgs.type === 'TemplateLiteral' &&
+              firstArgs.expressions.length
+            ) {
+              context.report({
+                node,
+                message:
+                  "Don't use variables in translation string templates. 
Flask-babel is a static translation translation service, so it can’t handle 
strings that include variables",
+              });
+            }
+          }
+        }
+        return {
+          "CallExpression[callee.name='t']": handler,
+          "CallExpression[callee.name='tn']": handler,
+        };
+      },
+    },
+  },
+};
diff --git 
a/superset-frontend/tools/eslint-plugin-translation-vars/no-template-vars.test.js
 
b/superset-frontend/tools/eslint-plugin-translation-vars/no-template-vars.test.js
new file mode 100644
index 0000000000..295a2f9fb8
--- /dev/null
+++ 
b/superset-frontend/tools/eslint-plugin-translation-vars/no-template-vars.test.js
@@ -0,0 +1,68 @@
+/**
+ * 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.
+ */
+
+/**
+ * @fileoverview Rule to warn about translation template variables
+ * @author Apache
+ */
+/* eslint-disable no-template-curly-in-string */
+const { RuleTester } = require('eslint');
+const plugin = require('.');
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
+const rule = plugin.rules['no-template-vars'];
+
+const errors = [
+  {
+    type: 'CallExpression',
+  },
+];
+
+ruleTester.run('no-template-vars', rule, {
+  valid: [
+    't(`foo`)',
+    'tn(`foo`)',
+    't(`foo %s bar`)',
+    'tn(`foo %s bar`)',
+    't(`foo %s bar %s`)',
+    'tn(`foo %s bar %s`)',
+  ],
+  invalid: [
+    {
+      code: 't(`foo${bar}`)',
+      errors,
+    },
+    {
+      code: 't(`foo${bar} ${baz}`)',
+      errors,
+    },
+    {
+      code: 'tn(`foo${bar}`)',
+      errors,
+    },
+    {
+      code: 'tn(`foo${bar} ${baz}`)',
+      errors,
+    },
+  ],
+});
diff --git 
a/superset-frontend/tools/eslint-plugin-translation-vars/package.json 
b/superset-frontend/tools/eslint-plugin-translation-vars/package.json
new file mode 100644
index 0000000000..d4353a88df
--- /dev/null
+++ b/superset-frontend/tools/eslint-plugin-translation-vars/package.json
@@ -0,0 +1,20 @@
+{
+  "name": "eslint-plugin-translation-vars",
+  "version": "1.0.0",
+  "description": "Warns about translation variables",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "keywords": [],
+  "license": "Apache-2.0",
+  "author": "Apache",
+  "dependencies": {},
+  "peerDependencies": {
+    "eslint": ">=0.8.0"
+  },
+  "engines": {
+    "node": "^16.9.1",
+    "npm": "^7.5.4"
+  }
+}

Reply via email to