@18ways/eslint-plugin-translate 0.0.0-alpha.185b0ef4fee2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 18ways
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,43 @@
1
+ ![18ways logo](https://18ways.com/18w-light.svg)
2
+
3
+ # @18ways/eslint-plugin-translate
4
+
5
+ 18ways makes i18n easy. SEO-ready, AI-powered translations for modern products.
6
+
7
+ `@18ways/eslint-plugin-translate` is the ESLint plugin for 18ways. It catches hard-coded user-facing strings and nudges code toward `<T>` and `useT()`.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install -D @18ways/eslint-plugin-translate
13
+ ```
14
+
15
+ ## Basic config
16
+
17
+ ```js
18
+ module.exports = {
19
+ extends: ['plugin:@18ways/translate/recommended'],
20
+ };
21
+ ```
22
+
23
+ ## Good / bad
24
+
25
+ ```tsx
26
+ // Bad
27
+ export function Header() {
28
+ return <h1>Hello world</h1>;
29
+ }
30
+
31
+ // Good
32
+ import { T } from '@18ways/react';
33
+
34
+ export function Header() {
35
+ return (
36
+ <h1>
37
+ <T>Hello world</T>
38
+ </h1>
39
+ );
40
+ }
41
+ ```
42
+
43
+ Docs: [18ways.com/docs](https://18ways.com/docs)
@@ -0,0 +1,31 @@
1
+ declare const plugin: {
2
+ meta: {
3
+ name: string;
4
+ version: string;
5
+ };
6
+ rules: {
7
+ 'require-translation': import("@typescript-eslint/utils/ts-eslint").RuleModule<"untranslatedText" | "untranslatedAttribute" | "untranslatedStringLiteral" | "untranslatedTemplateLiteral", [import("./rules/require-translation").Options], import("@typescript-eslint/utils/ts-eslint").RuleListener>;
8
+ };
9
+ configs: {
10
+ recommended: {
11
+ plugins: string[];
12
+ rules: {
13
+ '@18ways/translate/require-translation': string;
14
+ };
15
+ };
16
+ strict: {
17
+ plugins: string[];
18
+ rules: {
19
+ '@18ways/translate/require-translation': (string | {
20
+ translateComponent: string;
21
+ translateHook: string;
22
+ userFacingAttributes: string[];
23
+ ignorePatterns: string[];
24
+ ignoreFiles: string[];
25
+ })[];
26
+ };
27
+ };
28
+ };
29
+ };
30
+ export = plugin;
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0DX,CAAC;AAEF,SAAS,MAAM,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ const require_translation_1 = require("./rules/require-translation");
3
+ const plugin = {
4
+ meta: {
5
+ name: '@18ways/eslint-plugin-translate',
6
+ version: '1.0.0',
7
+ },
8
+ rules: {
9
+ 'require-translation': require_translation_1.requireTranslation,
10
+ },
11
+ configs: {
12
+ recommended: {
13
+ plugins: ['@18ways/translate'],
14
+ rules: {
15
+ '@18ways/translate/require-translation': 'error',
16
+ },
17
+ },
18
+ strict: {
19
+ plugins: ['@18ways/translate'],
20
+ rules: {
21
+ '@18ways/translate/require-translation': [
22
+ 'error',
23
+ {
24
+ translateComponent: 'T',
25
+ translateHook: 'useT',
26
+ userFacingAttributes: [
27
+ 'alt',
28
+ 'title',
29
+ 'aria-label',
30
+ 'aria-labelledby',
31
+ 'aria-describedby',
32
+ 'placeholder',
33
+ 'value',
34
+ 'defaultValue',
35
+ 'label',
36
+ 'summary',
37
+ 'caption',
38
+ ],
39
+ ignorePatterns: [
40
+ '^[a-zA-Z0-9_-]{1,3}$',
41
+ '^[A-Z_]+$',
42
+ '^\\d+$',
43
+ '^[a-z]+://.*',
44
+ '^/.*',
45
+ '^#[a-fA-F0-9]{3,8}$',
46
+ '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$',
47
+ '^\\s*$',
48
+ ],
49
+ ignoreFiles: [
50
+ '.*\\.test\\.[jt]sx?$',
51
+ '.*\\.spec\\.[jt]sx?$',
52
+ '.*/test/.*',
53
+ '.*/tests/.*',
54
+ '.*/__tests__/.*',
55
+ ],
56
+ },
57
+ ],
58
+ },
59
+ },
60
+ },
61
+ };
62
+ module.exports = plugin;
63
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,qEAAiE;AAEjE,MAAM,MAAM,GAAG;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,iCAAiC;QACvC,OAAO,EAAE,OAAO;KACjB;IACD,KAAK,EAAE;QACL,qBAAqB,EAAE,wCAAkB;KAC1C;IACD,OAAO,EAAE;QACP,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,mBAAmB,CAAC;YAC9B,KAAK,EAAE;gBACL,uCAAuC,EAAE,OAAO;aACjD;SACF;QACD,MAAM,EAAE;YACN,OAAO,EAAE,CAAC,mBAAmB,CAAC;YAC9B,KAAK,EAAE;gBACL,uCAAuC,EAAE;oBACvC,OAAO;oBACP;wBACE,kBAAkB,EAAE,GAAG;wBACvB,aAAa,EAAE,MAAM;wBACrB,oBAAoB,EAAE;4BACpB,KAAK;4BACL,OAAO;4BACP,YAAY;4BACZ,iBAAiB;4BACjB,kBAAkB;4BAClB,aAAa;4BACb,OAAO;4BACP,cAAc;4BACd,OAAO;4BACP,SAAS;4BACT,SAAS;yBACV;wBACD,cAAc,EAAE;4BACd,sBAAsB;4BACtB,WAAW;4BACX,QAAQ;4BACR,cAAc;4BACd,MAAM;4BACN,qBAAqB;4BACrB,mDAAmD;4BACnD,QAAQ;yBACT;wBACD,WAAW,EAAE;4BACX,sBAAsB;4BACtB,sBAAsB;4BACtB,YAAY;4BACZ,aAAa;4BACb,iBAAiB;yBAClB;qBACF;iBACF;aACF;SACF;KACF;CACF,CAAC;AAEF,iBAAS,MAAM,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export interface Options {
3
+ translateComponent?: string;
4
+ translateHook?: string;
5
+ userFacingAttributes?: string[];
6
+ ignorePatterns?: string[];
7
+ ignoreFiles?: string[];
8
+ }
9
+ type MessageIds = 'untranslatedText' | 'untranslatedAttribute' | 'untranslatedStringLiteral' | 'untranslatedTemplateLiteral';
10
+ export declare const requireTranslation: ESLintUtils.RuleModule<MessageIds, [Options], ESLintUtils.RuleListener>;
11
+ export {};
12
+ //# sourceMappingURL=require-translation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-translation.d.ts","sourceRoot":"","sources":["../../src/rules/require-translation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAY,MAAM,0BAA0B,CAAC;AAMjE,MAAM,WAAW,OAAO;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,KAAK,UAAU,GACX,kBAAkB,GAClB,uBAAuB,GACvB,2BAA2B,GAC3B,6BAA6B,CAAC;AAqBlC,eAAO,MAAM,kBAAkB,yEAgQ7B,CAAC"}
@@ -0,0 +1,260 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requireTranslation = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const createRule = utils_1.ESLintUtils.RuleCreator((name) => `https://github.com/18ways/eslint-plugin-translate/blob/main/docs/rules/${name}.md`);
6
+ const DEFAULT_USER_FACING_ATTRIBUTES = [
7
+ 'alt',
8
+ 'title',
9
+ 'aria-label',
10
+ 'aria-labelledby',
11
+ 'placeholder',
12
+ 'label',
13
+ ];
14
+ const DEFAULT_IGNORE_PATTERNS = [
15
+ '^.{1,3}$', // Very short strings (1-3 chars like IDs, icons, symbols)
16
+ '^[A-Z_]+$', // Constants (ALL_CAPS)
17
+ '^\\d+$', // Numbers only
18
+ '^[a-z]+://.*', // URLs
19
+ '^/.*', // Paths
20
+ '^#[a-fA-F0-9]{3,8}$', // Hex colors
21
+ '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$', // Emails
22
+ ];
23
+ exports.requireTranslation = createRule({
24
+ name: 'require-translation',
25
+ meta: {
26
+ type: 'suggestion',
27
+ docs: {
28
+ description: 'Require user-facing strings to be wrapped in translation components',
29
+ },
30
+ messages: {
31
+ untranslatedText: 'User-facing text should be wrapped in a <{{translateComponent}}> component: "{{text}}"',
32
+ untranslatedAttribute: 'User-facing attribute "{{attribute}}" should use translated content: "{{text}}"',
33
+ untranslatedStringLiteral: 'User-facing string literal should be translated: "{{text}}"',
34
+ untranslatedTemplateLiteral: 'User-facing template literal should be translated: "{{text}}"',
35
+ },
36
+ schema: [
37
+ {
38
+ type: 'object',
39
+ properties: {
40
+ translateComponent: {
41
+ type: 'string',
42
+ default: 'T',
43
+ },
44
+ translateHook: {
45
+ type: 'string',
46
+ default: 'useT',
47
+ },
48
+ userFacingAttributes: {
49
+ type: 'array',
50
+ items: { type: 'string' },
51
+ default: DEFAULT_USER_FACING_ATTRIBUTES,
52
+ },
53
+ ignorePatterns: {
54
+ type: 'array',
55
+ items: { type: 'string' },
56
+ default: DEFAULT_IGNORE_PATTERNS,
57
+ },
58
+ ignoreFiles: {
59
+ type: 'array',
60
+ items: { type: 'string' },
61
+ default: [],
62
+ },
63
+ },
64
+ additionalProperties: false,
65
+ },
66
+ ],
67
+ },
68
+ defaultOptions: [
69
+ {
70
+ translateComponent: 'T',
71
+ translateHook: 'useT',
72
+ userFacingAttributes: DEFAULT_USER_FACING_ATTRIBUTES,
73
+ ignorePatterns: DEFAULT_IGNORE_PATTERNS,
74
+ ignoreFiles: [],
75
+ },
76
+ ],
77
+ create(context, [options]) {
78
+ const translateComponent = options.translateComponent || 'T';
79
+ const userFacingAttributes = options.userFacingAttributes || DEFAULT_USER_FACING_ATTRIBUTES;
80
+ const ignorePatterns = options.ignorePatterns || DEFAULT_IGNORE_PATTERNS;
81
+ const ignoreFiles = options.ignoreFiles || [];
82
+ const filename = context.getFilename();
83
+ // Skip files that match ignore patterns
84
+ if (ignoreFiles.some((pattern) => new RegExp(pattern).test(filename))) {
85
+ return {};
86
+ }
87
+ function shouldIgnoreText(text) {
88
+ if (!text || typeof text !== 'string')
89
+ return true;
90
+ // Trim whitespace for checking
91
+ const trimmed = text.trim();
92
+ if (!trimmed)
93
+ return true;
94
+ // Check against ignore patterns
95
+ return ignorePatterns.some((pattern) => new RegExp(pattern).test(trimmed));
96
+ }
97
+ function isInsideTranslateComponent(node) {
98
+ let parent = node.parent;
99
+ while (parent) {
100
+ if (parent.type === 'JSXElement') {
101
+ const openingElement = parent.openingElement;
102
+ if (openingElement.name.type === 'JSXIdentifier' &&
103
+ openingElement.name.name === translateComponent) {
104
+ return true;
105
+ }
106
+ }
107
+ parent = parent.parent;
108
+ }
109
+ return false;
110
+ }
111
+ function isWithinTFunction(node) {
112
+ let parent = node.parent;
113
+ while (parent) {
114
+ if (parent.type === 'CallExpression') {
115
+ const callee = parent.callee;
116
+ if (callee.type === 'Identifier' && callee.name === 't') {
117
+ return true;
118
+ }
119
+ }
120
+ parent = parent.parent;
121
+ }
122
+ return false;
123
+ }
124
+ function containsJSXExpressions(text) {
125
+ return /\{.*\}/.test(text);
126
+ }
127
+ return {
128
+ JSXText(node) {
129
+ const text = node.value;
130
+ if (shouldIgnoreText(text))
131
+ return;
132
+ if (isInsideTranslateComponent(node))
133
+ return;
134
+ if (containsJSXExpressions(text))
135
+ return;
136
+ context.report({
137
+ node,
138
+ messageId: 'untranslatedText',
139
+ data: {
140
+ translateComponent,
141
+ text: text.trim(),
142
+ },
143
+ });
144
+ },
145
+ JSXAttribute(node) {
146
+ if (!node.name || node.name.type !== 'JSXIdentifier')
147
+ return;
148
+ const attributeName = node.name.name;
149
+ if (!userFacingAttributes.includes(attributeName))
150
+ return;
151
+ const value = node.value;
152
+ if (!value)
153
+ return;
154
+ if (value.type === 'Literal' && typeof value.value === 'string') {
155
+ const text = value.value;
156
+ if (shouldIgnoreText(text))
157
+ return;
158
+ context.report({
159
+ node: value,
160
+ messageId: 'untranslatedAttribute',
161
+ data: {
162
+ attribute: attributeName,
163
+ text,
164
+ },
165
+ });
166
+ }
167
+ else if (value.type === 'JSXExpressionContainer') {
168
+ // Check if the expression is a t() function call
169
+ if (value.expression.type === 'CallExpression' &&
170
+ value.expression.callee.type === 'Identifier' &&
171
+ value.expression.callee.name === 't') {
172
+ return; // This is already translated with t()
173
+ }
174
+ // Check if it's a literal string that should be translated
175
+ if (value.expression.type === 'Literal' && typeof value.expression.value === 'string') {
176
+ const text = value.expression.value;
177
+ if (shouldIgnoreText(text))
178
+ return;
179
+ context.report({
180
+ node: value.expression,
181
+ messageId: 'untranslatedAttribute',
182
+ data: {
183
+ attribute: attributeName,
184
+ text,
185
+ },
186
+ });
187
+ }
188
+ }
189
+ },
190
+ 'Literal[value=/\\w/]'(node) {
191
+ if (typeof node.value !== 'string')
192
+ return;
193
+ if (shouldIgnoreText(node.value))
194
+ return;
195
+ if (isInsideTranslateComponent(node))
196
+ return;
197
+ if (isWithinTFunction(node))
198
+ return;
199
+ // Skip if inside JSX attribute (handled by JSXAttribute rule)
200
+ let parent = node.parent;
201
+ while (parent) {
202
+ if (parent.type === 'JSXAttribute')
203
+ return;
204
+ parent = parent.parent;
205
+ }
206
+ // Only report if this appears to be user-facing content
207
+ if (node.parent?.type === 'JSXExpressionContainer' ||
208
+ (node.parent?.type === 'ReturnStatement' && /^[A-Z]/.test(node.value.charAt(0)))) {
209
+ context.report({
210
+ node,
211
+ messageId: 'untranslatedStringLiteral',
212
+ data: {
213
+ text: node.value,
214
+ },
215
+ });
216
+ }
217
+ },
218
+ TemplateLiteral(node) {
219
+ // Skip if inside translate component or t() function
220
+ if (isInsideTranslateComponent(node))
221
+ return;
222
+ if (isWithinTFunction(node))
223
+ return;
224
+ // Check if this is inside a JSX attribute
225
+ let parent = node.parent;
226
+ while (parent) {
227
+ if (parent.type === 'JSXAttribute') {
228
+ const attr = parent;
229
+ if (attr.name.type === 'JSXIdentifier') {
230
+ const attrName = attr.name.name;
231
+ // Allow template literals in non-user-facing attributes
232
+ // (className, style, key, id, etc. - anything not explicitly user-facing)
233
+ if (!userFacingAttributes.includes(attrName)) {
234
+ return;
235
+ }
236
+ }
237
+ }
238
+ parent = parent.parent;
239
+ }
240
+ // Check if template literal has only static text (no expressions)
241
+ if (node.expressions.length === 0 && node.quasis.length === 1) {
242
+ const text = node.quasis[0].value.cooked || '';
243
+ if (shouldIgnoreText(text))
244
+ return;
245
+ // Only report if in JSX content (JSXExpressionContainer)
246
+ if (node.parent?.type === 'JSXExpressionContainer') {
247
+ context.report({
248
+ node,
249
+ messageId: 'untranslatedTemplateLiteral',
250
+ data: {
251
+ text: text.substring(0, 50), // Limit display length
252
+ },
253
+ });
254
+ }
255
+ }
256
+ },
257
+ };
258
+ },
259
+ });
260
+ //# sourceMappingURL=require-translation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-translation.js","sourceRoot":"","sources":["../../src/rules/require-translation.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@18ways/eslint-plugin-translate",
3
+ "version": "0.0.0-alpha.185b0ef4fee2",
4
+ "description": "ESLint plugin to detect untranslated strings that should use 18ways translate functionality",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "test": "vitest run",
14
+ "test:watch": "vitest watch",
15
+ "lint": "eslint src --ext .ts",
16
+ "prepare": "bun run build"
17
+ },
18
+ "keywords": [
19
+ "eslint",
20
+ "plugin",
21
+ "translation",
22
+ "i18n",
23
+ "18ways",
24
+ "internationalization"
25
+ ],
26
+ "author": "18ways",
27
+ "license": "MIT",
28
+ "peerDependencies": {
29
+ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/eslint": "^8.56.0",
33
+ "@types/estree": "^1.0.5",
34
+ "@types/node": "^20.0.0",
35
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
36
+ "@typescript-eslint/parser": "^6.0.0",
37
+ "eslint": "^8.56.0",
38
+ "globby": "^11.1.0",
39
+ "typescript": "^5.0.0",
40
+ "vitest": "^3.2.4"
41
+ },
42
+ "dependencies": {
43
+ "@typescript-eslint/utils": "^6.0.0"
44
+ },
45
+ "engines": {
46
+ "node": ">=16.0.0"
47
+ },
48
+ "packageManager": "bun@1.3.8"
49
+ }