eslint-plugin-i18next
Advanced tools
Comparing version 5.2.1 to 6.0.0-0
@@ -5,2 +5,15 @@ # Changelog | ||
## [6.0.0-0](https://github.com/edvardchen/eslint-plugin-i18next/compare/v5.2.1...v6.0.0-0) (2022-05-15) | ||
### Features | ||
* make mode defaults to jsx-text-only ([7cc75ab](https://github.com/edvardchen/eslint-plugin-i18next/commit/7cc75ab)) | ||
* support callees option ([1934216](https://github.com/edvardchen/eslint-plugin-i18next/commit/1934216)) | ||
* support option jsx-attributes ([08ae48b](https://github.com/edvardchen/eslint-plugin-i18next/commit/08ae48b)) | ||
* support option jsx-components ([99af7e1](https://github.com/edvardchen/eslint-plugin-i18next/commit/99af7e1)) | ||
* support option mode ([3193108](https://github.com/edvardchen/eslint-plugin-i18next/commit/3193108)) | ||
* support option object-properties ([484fcfb](https://github.com/edvardchen/eslint-plugin-i18next/commit/484fcfb)) | ||
* support option words ([874a694](https://github.com/edvardchen/eslint-plugin-i18next/commit/874a694)) | ||
### 5.2.1 (2022-05-05) | ||
@@ -7,0 +20,0 @@ |
# disallow literal string (no-literal-string) | ||
This rule aims to avoid developers to display literal string to users | ||
in those projects which need to support [multi-language](https://www.i18next.com/). | ||
This rule aims to avoid developers to display literal string directly to users without translating them. | ||
## Rule Details | ||
It will find out all literal strings and validate them. | ||
Example of incorrect code: | ||
Examples of **incorrect** code for this rule: | ||
```js | ||
```jsx | ||
/*eslint i18next/no-literal-string: "error"*/ | ||
const a = 'foo'; | ||
<div>hello world</div> | ||
``` | ||
Examples of **correct** code for this rule: | ||
Example of correct code: | ||
```js | ||
```jsx | ||
/*eslint i18next/no-literal-string: "error"*/ | ||
// safe to assign string to const variables whose name are UPPER_CASE | ||
var FOO = 'foo'; | ||
// UPPER_CASE properties are valid no matter if they are computed or not | ||
var a = { | ||
BAR: 'bar', | ||
[FOO]: 'foo' | ||
}; | ||
// also safe to use strings themselves are UPPCASE_CASE | ||
var foo = 'FOO'; | ||
<div>{i18next.t('HELLO_KEY')}</div> | ||
``` | ||
### i18n | ||
## Options | ||
This rule allows to call i18next translate function. | ||
The option's typing definition looks like: | ||
**Correct** code: | ||
```js | ||
/*eslint i18next/no-literal-string: "error"*/ | ||
var bar = i18next.t('bar'); | ||
var bar2 = i18n.t('bar'); | ||
```typescript | ||
type MySchema = { | ||
[key in | ||
| 'words' | ||
| 'jsx-components' | ||
| 'jsx-attributes' | ||
| 'callees' | ||
| 'object-properties' | ||
| 'class-properties']?: { | ||
include?: string[]; | ||
exclude?: string[]; | ||
}; | ||
} & { | ||
mode?: 'jsx-text-only' | 'jsx-only' | 'all'; | ||
message?: string; | ||
'should-validate-template'?: boolean; | ||
}; | ||
``` | ||
### Redux/Vuex | ||
### `exclude` and `include` | ||
This rule also works with those state managers like | ||
[Redux](https://redux.js.org/) and [Vuex](https://vuex.vuejs.org/). | ||
Instead of expanding options immoderately, a standard and scalable way to set options is provided | ||
**Correct** code: | ||
You cam use `exclude` and `include` of each options to control which should be validated and which should be ignored. | ||
```js | ||
/*eslint i18next/no-literal-string: "error"*/ | ||
var bar = store.dispatch('bar'); | ||
var bar2 = store.commit('bar'); | ||
``` | ||
The values of these two fields are treated as regular expressions. | ||
## Options | ||
1. If both are used, both conditions need to be satisfied | ||
2. If both are emitted, it will be validated | ||
### ignore | ||
For selectors, | ||
The `ignore` option specifies exceptions not to check for | ||
literal strings that match one of regexp paterns. | ||
- `words` controls plain text | ||
- `jsx-components` controls JSX elements | ||
- `jsx-attributes` controls JSX elements' attributes | ||
- `callees` controls function calls | ||
- `object-properties` controls objects' properties | ||
- `class-properties` controls classes' properties | ||
Examples of correct code for the `{ "ignore": ['foo'] }` option: | ||
Other options, | ||
```js | ||
/*eslint i18next/no-literal-string: ["error", {"ignore": ["foo"]}]*/ | ||
const a = 'afoo'; | ||
``` | ||
- `mode` provides a straightforward way to decides the range you want to validate literal strings. | ||
It defaults to `jsx-text-only` which only forbids to write plain text in JSX markup | ||
- `jsx-only` validates the JSX attributes as well | ||
- `all` validates all literal strings | ||
- `message` defines the custom error message | ||
- `should-validate-template` decides if we should validate the string templates | ||
### ignoreCallee | ||
You can see [the default options here](../../lib/options/defaults.json) | ||
THe `ignoreCallee` option speficies exceptions not check for | ||
function calls whose names match one of regexp patterns. | ||
Examples of correct code for the `{ "ignoreCallee": ["foo"] }` option: | ||
```js | ||
/*eslint i18next/no-literal-string: ["error", { "ignoreCallee": ["foo"] }]*/ | ||
const bar = foo('bar'); | ||
``` | ||
## When Not To Use It | ||
Your project maybe not need to support multi-language or you dont care to spread literal string anywhre. | ||
Your project maybe not need to support multi-language or you don't care to spread literal string anywhere. |
@@ -7,8 +7,48 @@ /** | ||
const _ = require('lodash'); | ||
const { | ||
isUpperCase, | ||
generateFullMatchRegExp, | ||
getNearestAncestor, | ||
isAllowedDOMAttr, | ||
shouldSkip, | ||
} = require('../helper'); | ||
function isValidFunctionCall(context, options, { callee }) { | ||
if (callee.type === 'Import') return true; | ||
const sourceText = context.getSourceCode().getText(callee); | ||
return shouldSkip(options.callees, sourceText); | ||
} | ||
function isValidLiteral(options, { value }) { | ||
if (typeof value !== 'string') { | ||
return true; | ||
} | ||
const trimed = value.trim(); | ||
if (!trimed) return true; | ||
if (shouldSkip(options.words, value)) return true; | ||
} | ||
function isValidTypeScriptAnnotation(esTreeNodeToTSNodeMap, typeChecker, node) { | ||
const tsNode = esTreeNodeToTSNodeMap.get(node); | ||
const typeObj = typeChecker.getTypeAtLocation(tsNode.parent); | ||
// var a: 'abc' = 'abc' | ||
if (typeObj.isStringLiteral()) { | ||
return true; | ||
} | ||
// var a: 'abc' | 'name' = 'abc' | ||
if (typeObj.isUnion()) { | ||
const found = typeObj.types.some(item => { | ||
if (item.isStringLiteral() && item.value === node.value) { | ||
return true; | ||
} | ||
}); | ||
return found; | ||
} | ||
} | ||
//------------------------------------------------------------------------------ | ||
@@ -25,51 +65,3 @@ // Rule Definition | ||
}, | ||
schema: [ | ||
{ | ||
type: 'object', | ||
properties: { | ||
ignore: { | ||
type: 'array', | ||
// string or regexp | ||
}, | ||
ignoreAttribute: { | ||
type: 'array', | ||
items: { | ||
type: 'string', | ||
}, | ||
}, | ||
ignoreCallee: { | ||
type: 'array', | ||
// string or regexp | ||
}, | ||
ignoreProperty: { | ||
type: 'array', | ||
items: { | ||
type: 'string', | ||
}, | ||
}, | ||
ignoreComponent: { | ||
type: 'array', | ||
items: { | ||
type: 'string', | ||
}, | ||
}, | ||
markupOnly: { | ||
type: 'boolean', | ||
}, | ||
message: { | ||
type: 'string', | ||
}, | ||
onlyAttribute: { | ||
type: 'array', | ||
items: { | ||
type: 'string', | ||
}, | ||
}, | ||
validateTemplate: { | ||
type: 'boolean', | ||
}, | ||
}, | ||
additionalProperties: false, | ||
}, | ||
], | ||
schema: [require('../options/schema.json')], | ||
}, | ||
@@ -79,22 +71,15 @@ | ||
// variables should be defined here | ||
const { parserServices } = context; | ||
const options = _.defaults( | ||
{}, | ||
context.options[0], | ||
require('../options/defaults.json') | ||
); | ||
const { | ||
parserServices, | ||
options: [ | ||
{ | ||
onlyAttribute = [], | ||
markupOnly: _markupOnly, | ||
validateTemplate, | ||
ignoreComponent = [], | ||
ignoreAttribute = [], | ||
ignoreProperty = [], | ||
ignoreCallee = [], | ||
ignore = [], | ||
message = 'disallow literal string', | ||
} = {}, | ||
], | ||
} = context; | ||
const whitelists = [ | ||
/^[0-9!-/:-@[-`{-~]+$/, // ignore not-word string | ||
...ignore, | ||
].map(item => new RegExp(item)); | ||
mode, | ||
'should-validate-template': validateTemplate, | ||
message, | ||
} = options; | ||
const onlyValidateJSX = ['jsx-only', 'jsx-text-only'].includes(mode); | ||
@@ -107,2 +92,6 @@ //---------------------------------------------------------------------- | ||
function endIndicator() { | ||
indicatorStack.pop(); | ||
} | ||
/** | ||
@@ -115,87 +104,6 @@ * detect if current "scope" is valid | ||
function match(str) { | ||
return whitelists.some(item => item.test(str)); | ||
} | ||
const popularCallee = [ | ||
/^i18n(ext)?$/, | ||
't', | ||
'require', | ||
'addEventListener', | ||
'removeEventListener', | ||
'postMessage', | ||
'getElementById', | ||
// | ||
// ─── VUEX CALLEE ──────────────────────────────────────────────────────────────── | ||
// | ||
'dispatch', | ||
'commit', | ||
// ──────────────────────────────────────────────────────────────────────────────── | ||
'includes', | ||
'indexOf', | ||
'endsWith', | ||
'startsWith', | ||
]; | ||
const validCalleeList = [...popularCallee, ...ignoreCallee].map( | ||
generateFullMatchRegExp | ||
); | ||
function isValidFunctionCall({ callee }) { | ||
let calleeName = callee.name; | ||
if (callee.type === 'Import') return true; | ||
const sourceText = context.getSourceCode().getText(callee); | ||
return validCalleeList.some(item => { | ||
return item.test(sourceText); | ||
}); | ||
} | ||
const ignoredClassProperties = ['displayName']; | ||
const userJSXAttrs = [ | ||
'className', | ||
'styleName', | ||
'style', | ||
'type', | ||
'key', | ||
'id', | ||
'width', | ||
'height', | ||
...ignoreAttribute, | ||
]; | ||
function isValidAttrName(name) { | ||
if (onlyAttribute.length) { | ||
// only validate those attributes in onlyAttribute option | ||
return !onlyAttribute.includes(name); | ||
} | ||
return userJSXAttrs.includes(name); | ||
} | ||
// Ignore the Trans component for react-i18next compatibility | ||
const ignoredComponents = ['Trans', ...ignoreComponent]; | ||
//---------------------------------------------------------------------- | ||
// Public | ||
//---------------------------------------------------------------------- | ||
const visited = new WeakSet(); | ||
function getNearestAncestor(node, type) { | ||
let temp = node.parent; | ||
while (temp) { | ||
if (temp.type === type) { | ||
return temp; | ||
} | ||
temp = temp.parent; | ||
} | ||
return temp; | ||
} | ||
function isString(node) { | ||
return typeof node.value === 'string'; | ||
} | ||
const { esTreeNodeToTSNodeMap, program } = parserServices; | ||
@@ -206,29 +114,23 @@ let typeChecker; | ||
function isValidLiteral(str) { | ||
const trimed = str.trim(); | ||
if (!trimed) return true; | ||
function report(node) { | ||
context.report({ | ||
node, | ||
message: `${message}: ${context.getSourceCode().getText(node.parent)}`, | ||
}); | ||
} | ||
// allow statements like const a = "FOO" | ||
if (isUpperCase(trimed)) return true; | ||
function validateBeforeReport(node) { | ||
if (isValidScope()) return; | ||
if (isValidLiteral(options, node)) return; | ||
if (match(trimed)) return true; | ||
} | ||
function validateLiteralNode(node) { | ||
// make sure node is string literal | ||
if (!isString(node)) return; | ||
if (isValidLiteral(node.value)) { | ||
if ( | ||
typeChecker && | ||
isValidTypeScriptAnnotation(esTreeNodeToTSNodeMap, typeChecker, node) | ||
) { | ||
return; | ||
} | ||
context.report({ node, message }); | ||
report(node); | ||
} | ||
// onlyAttribute would turn on markOnly | ||
const markupOnly = _markupOnly || !!onlyAttribute.length; | ||
function endIndicator() { | ||
indicatorStack.pop(); | ||
} | ||
const scriptVisitor = { | ||
@@ -270,3 +172,3 @@ // | ||
indicatorStack.push( | ||
ignoredComponents.includes(node.openingElement.name.name) | ||
shouldSkip(options['jsx-components'], node.openingElement.name.name) | ||
); | ||
@@ -276,8 +178,18 @@ }, | ||
'JSXElement Literal'(node) { | ||
if (mode === 'jsx-only') { | ||
validateBeforeReport(node); | ||
} | ||
}, | ||
'JSXElement > Literal'(node) { | ||
scriptVisitor.JSXText(node); | ||
if (mode === 'jsx-text-only') { | ||
validateBeforeReport(node); | ||
} | ||
}, | ||
'JSXFragment > Literal'(node) { | ||
scriptVisitor.JSXText(node); | ||
if (onlyValidateJSX) { | ||
validateBeforeReport(node); | ||
} | ||
}, | ||
@@ -289,3 +201,3 @@ | ||
// allow <MyComponent className="active" /> | ||
if (isValidAttrName(attrName)) { | ||
if (shouldSkip(options['jsx-attributes'], attrName)) { | ||
indicatorStack.push(true); | ||
@@ -305,23 +217,5 @@ return; | ||
'JSXAttribute > Literal:exit'(node) { | ||
if (markupOnly) { | ||
if (isValidScope()) return; | ||
validateLiteralNode(node); | ||
} | ||
}, | ||
'JSXExpressionContainer > Literal:exit'(node) { | ||
scriptVisitor['JSXAttribute > Literal:exit'](node); | ||
}, | ||
// @typescript-eslint/parser would parse string literal as JSXText node | ||
JSXText(node) { | ||
if (isValidScope()) return; | ||
const trimed = node.value.trim(); | ||
if (!trimed || match(trimed)) { | ||
return; | ||
} | ||
context.report({ node, message }); | ||
validateBeforeReport(node); | ||
}, | ||
@@ -353,3 +247,3 @@ // ───────────────────────────────────────────────────────────────── | ||
indicatorStack.push( | ||
!!(node.key && ignoredClassProperties.includes(node.key.name)) | ||
!!(node.key && shouldSkip(options['class-properties'], node.key.name)) | ||
); | ||
@@ -366,7 +260,8 @@ }, | ||
Property(node) { | ||
const result = | ||
ignoreProperty.includes(node.key.name) || | ||
// name if key is Identifier; value if key is Literal | ||
// dont care whether if this is computed or not | ||
isUpperCase(node.key.name || node.key.value); | ||
// pick up key.name if key is Identifier or key.value if key is Literal | ||
// dont care whether if this is computed or not | ||
const result = shouldSkip( | ||
options['object-properties'], | ||
node.key.name || node.key.value | ||
); | ||
indicatorStack.push(result); | ||
@@ -390,3 +285,3 @@ }, | ||
NewExpression(node) { | ||
indicatorStack.push(isValidFunctionCall(node)); | ||
indicatorStack.push(isValidFunctionCall(context, options, node)); | ||
}, | ||
@@ -396,3 +291,3 @@ 'NewExpression:exit': endIndicator, | ||
CallExpression(node) { | ||
indicatorStack.push(isValidFunctionCall(node)); | ||
indicatorStack.push(isValidFunctionCall(context, options, node)); | ||
}, | ||
@@ -419,6 +314,4 @@ 'CallExpression:exit': endIndicator, | ||
quasis.some(({ value: { raw } }) => { | ||
const trimed = raw.trim(); | ||
if (!trimed) return; | ||
if (match(trimed)) return; | ||
context.report({ node, message }); | ||
if (isValidLiteral(options, { value: raw })) return; | ||
report(node); | ||
return true; // break | ||
@@ -429,2 +322,7 @@ }); | ||
'Literal:exit'(node) { | ||
// skip if it only validates jsx | ||
// checking if a literal is contained in a JSX element is hard to be performant | ||
// instead, we validate in jsx-related visitors | ||
if (onlyValidateJSX) return; | ||
// ignore `var a = { "foo": 123 }` | ||
@@ -434,8 +332,3 @@ if (node.parent.key === node) { | ||
} | ||
if (markupOnly) { | ||
return; | ||
} | ||
if (node.parent && node.parent.type === 'JSXElement') return; | ||
if (isValidScope()) return; | ||
validateLiteralNode(node); | ||
validateBeforeReport(node); | ||
}, | ||
@@ -442,0 +335,0 @@ }; |
{ | ||
"name": "eslint-plugin-i18next", | ||
"version": "5.2.1", | ||
"version": "6.0.0-0", | ||
"description": "ESLint plugin for i18n", | ||
@@ -24,3 +24,3 @@ "keywords": [ | ||
"test:watch": "npm t -- --watch", | ||
"test": "mocha tests --recursive" | ||
"test": "mocha --timeout 50000 tests/lib/rules/no-literal-string/" | ||
}, | ||
@@ -27,0 +27,0 @@ "dependencies": { |
315
README.md
@@ -5,6 +5,8 @@ # eslint-plugin-i18next | ||
> For old versions below v6, plz refer [this document](./v5.md) | ||
## Installation | ||
```bash | ||
npm install eslint-plugin-i18next --save-dev | ||
npm install eslint-plugin-i18next@next --save-dev | ||
``` | ||
@@ -42,316 +44,25 @@ | ||
This rule aims to avoid developers to display literal string to users | ||
in those projects which need to support [multi-language](https://www.i18next.com/). | ||
This rule aims to avoid developers to display literal string directly to users without translating them. | ||
> <span style="color: lightcoral">Note:</span> Disable auto-fix because key in the call `i18next.t(key)` ussally was not the same as the literal | ||
> <span style="color: lightcoral">Note:</span> Disable auto-fix because key in the call `i18next.t(key)` usually was not the same as the literal | ||
### Rule Details | ||
Example of incorrect code: | ||
**It will find out all literal strings and validate them.** | ||
Examples of **incorrect** code for this rule: | ||
```js | ||
/*eslint i18next/no-literal-string: "error"*/ | ||
const a = 'foo'; | ||
<div>hello world</div> | ||
``` | ||
Examples of **correct** code for this rule: | ||
Example of correct code: | ||
```js | ||
/*eslint i18next/no-literal-string: "error"*/ | ||
// safe to assign string to const variables whose name are UPPER_CASE | ||
var FOO = 'foo'; | ||
// UPPER_CASE properties are valid no matter if they are computed or not | ||
var a = { | ||
BAR: 'bar', | ||
[FOO]: 'foo' | ||
}; | ||
// also safe to use strings themselves are UPPCASE_CASE | ||
var foo = 'FOO'; | ||
<div>{i18next.t('HELLO_KEY')}</div> | ||
``` | ||
#### i18n | ||
More options can be found [here](./docs/rules/no-literal-string.md) | ||
This rule allows to call i18next translate function. | ||
### Breaking change | ||
**Correct** code: | ||
```js | ||
/*eslint i18next/no-literal-string: "error"*/ | ||
var bar = i18next.t('bar'); | ||
var bar2 = i18n.t('bar'); | ||
``` | ||
Maybe you use other internationalization libraries | ||
not [i18next](https://www.i18next.com/). You can use like this: | ||
```js | ||
/*eslint i18next/no-literal-string: ["error", { "ignoreCallee": ["yourI18n"] }]*/ | ||
const bar = yourI18n('bar'); | ||
// or | ||
/*eslint i18next/no-literal-string: ["error", { "ignoreCallee": ["yourI18n.method"] }]*/ | ||
const bar = yourI18n.method('bar'); | ||
``` | ||
#### HTML Markup | ||
All literal strings in html template are typically mistakes. For JSX example: | ||
```HTML | ||
<div>foo</div> | ||
``` | ||
They should be translated by [i18next translation api](https://www.i18next.com/): | ||
```HTML | ||
<div>{i18next.t('foo')}</div> | ||
``` | ||
Same for [Vue template](https://vuejs.org/v2/guide/syntax.html): | ||
```HTML | ||
<!-- incorrect --> | ||
<template> | ||
foo | ||
</template> | ||
<!-- correct --> | ||
<template> | ||
{{ i18next.t('foo') }} | ||
</template> | ||
``` | ||
It would allow most reasonable usages of string that would rarely be shown to user, like following examples. | ||
Click on them to see details. | ||
<details> | ||
<summary> | ||
react-i18next | ||
</summary> | ||
This plugin are compatible with [react-i18next](https://react.i18next.com/) | ||
```tsx | ||
// correct | ||
<Trans> | ||
<span>bar</span> | ||
</Trans> | ||
``` | ||
</details> | ||
<details> | ||
<summary> | ||
Redux/Vuex | ||
</summary> | ||
This rule also works with those state managers like | ||
[Redux](https://redux.js.org/) and [Vuex](https://vuex.vuejs.org/). | ||
**Correct** code: | ||
```js | ||
var bar = store.dispatch('bar'); | ||
var bar2 = store.commit('bar'); | ||
``` | ||
</details> | ||
<details> | ||
<summary> | ||
Typescript | ||
</summary> | ||
This plugin would not complain on those reasonable usages of string. | ||
The following cases are considered as **correct**: | ||
```typescript | ||
var a: Type['member']; | ||
var a: Omit<T, 'key'>; | ||
enum E { | ||
A = 1 | ||
} | ||
var a = E['A']; | ||
var a: { t: 'button' } = { t: 'button' }; | ||
var a: 'abc' | 'name' = 'abc'; | ||
``` | ||
We require type information to work properly, so you need to add some options in your `.eslintrc`: | ||
```js | ||
"parserOptions": { | ||
// path of your tsconfig.json | ||
"project": "./tsconfig.json" | ||
} | ||
``` | ||
See | ||
[here](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#usage) | ||
for more deteils. | ||
</details> | ||
<details> | ||
<summary> | ||
Import/Export | ||
</summary> | ||
The following cases are **allowed**: | ||
```typescript | ||
import mod from 'm'; | ||
import('mod'); | ||
require('mod'); | ||
export { named } from 'm'; | ||
export * from 'm'; | ||
``` | ||
</details> | ||
<details> | ||
<summary> | ||
String Comparison | ||
</summary> | ||
String comparison is fine. | ||
```typescript | ||
// correct | ||
name === 'Android' || name === 'iOS'; | ||
``` | ||
</details> | ||
<details> | ||
<summary> | ||
SwithCase | ||
</summary> | ||
Skip switchcase statement: | ||
```typescript | ||
// correct | ||
switch (type) { | ||
case 'foo': | ||
break; | ||
case 'bar': | ||
break; | ||
} | ||
``` | ||
</details> | ||
### Options | ||
### markupOnly | ||
If `markupOnly` option turn on, only JSX text and strings used as JSX attributes will be validated. | ||
JSX text: | ||
```jsx | ||
// incorrect | ||
<div>hello world</div> | ||
<div>{"hello world"}</div> | ||
``` | ||
Strings as JSX attribute: | ||
```jsx | ||
// incorrect | ||
<div foo="foo"></div> | ||
<div foo={"foo"}></div> | ||
``` | ||
### onlyAttribute | ||
Only check the `JSX` attributes that listed in this option. **This option would turn on `markupOnly`.** | ||
```jsx | ||
// correct | ||
const foo = 'bar'; | ||
<div foo="foo"></div> | ||
// incorrect | ||
<div>foo</div> | ||
/*eslint i18next/no-literal-string: ["error", {"onlyAttribute": ["foo"]}]*/ | ||
// incorrect | ||
<div foo="foo"></div> | ||
``` | ||
#### ignore | ||
The `ignore` option specifies exceptions not to check for | ||
literal strings that match one of regexp paterns. | ||
Examples of correct code for the `{ "ignore": ['foo'] }` option: | ||
```js | ||
/*eslint i18next/no-literal-string: ["error", {"ignore": ["foo"]}]*/ | ||
const a = 'afoo'; | ||
``` | ||
#### ignoreCallee | ||
THe `ignoreCallee` option speficies exceptions not check for | ||
function calls whose names match one of regexp patterns. | ||
Examples of correct code for the `{ "ignoreCallee": ["foo"] }` option: | ||
```js | ||
/*eslint i18next/no-literal-string: ["error", { "ignoreCallee": ["foo"] }]*/ | ||
const bar = foo('bar'); | ||
``` | ||
#### ignoreAttribute | ||
The `ignoreAttribute` option specifies exceptions not to check for JSX attributes that match one of ignored attributes. | ||
Examples of correct code for the `{ "ignoreAttribute": ["foo"] }` option: | ||
```jsx | ||
/*eslint i18next/no-literal-string: ["error", { "ignoreAttribute": ["foo"] }]*/ | ||
const element = <div foo="bar" />; | ||
``` | ||
#### ignoreProperty | ||
The `ignoreProperty` option specifies exceptions not to check for object properties that match one of ignored properties. | ||
Examples of correct code for the `{ "ignoreProperty": ["foo"] }` option: | ||
```jsx | ||
/*eslint i18next/no-literal-string: ["error", { "ignoreProperty": ["foo"] }]*/ | ||
const a = { foo: 'bar' }; | ||
``` | ||
#### ignoreComponent | ||
The `ignoreComponent` option specifies exceptions not to check for string literals inside a list of named components. It includes `<Trans>` per default. | ||
Examples of correct code for the `{ "ignoreComponent": ["Icon"] }` option: | ||
```jsx | ||
/*eslint i18next/no-literal-string: ["error", { "ignoreComponent": ["Icon"] }]*/ | ||
<Icon>arrow<Icon/> | ||
``` | ||
#### validateTemplate | ||
Indicate whether to validate [template strings](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) or not. Default `false` | ||
```js | ||
/*eslint i18next/no-literal-string: ["error", { "validateTemplate": true }]*/ | ||
// incorrect | ||
var foo = `hello world`; | ||
``` | ||
By default, it wil only validate the plain text in JSX markup instead of all literal strings in previous versions. | ||
[You can change it easily](./docs/rules/no-literal-string.md) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
57186
37
1144
2
67
1
1