eslint-plugin-lingui-typescript 1.8.4 → 1.8.6

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.
Files changed (42) hide show
  1. package/README.md +116 -127
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +6 -3
  4. package/dist/index.js.map +1 -1
  5. package/dist/rules/no-unlocalized-strings.d.ts.map +1 -1
  6. package/dist/rules/no-unlocalized-strings.js +256 -7
  7. package/dist/rules/no-unlocalized-strings.js.map +1 -1
  8. package/dist/rules/no-unlocalized-strings.test.js +82 -0
  9. package/dist/rules/no-unlocalized-strings.test.js.map +1 -1
  10. package/package.json +5 -5
  11. package/dist/rules/no-complex-expressions-in-message.d.ts +0 -7
  12. package/dist/rules/no-complex-expressions-in-message.d.ts.map +0 -1
  13. package/dist/rules/no-complex-expressions-in-message.js +0 -184
  14. package/dist/rules/no-complex-expressions-in-message.js.map +0 -1
  15. package/dist/rules/no-complex-expressions-in-message.test.d.ts +0 -2
  16. package/dist/rules/no-complex-expressions-in-message.test.d.ts.map +0 -1
  17. package/dist/rules/no-complex-expressions-in-message.test.js +0 -122
  18. package/dist/rules/no-complex-expressions-in-message.test.js.map +0 -1
  19. package/dist/rules/no-single-tag-message.d.ts +0 -2
  20. package/dist/rules/no-single-tag-message.d.ts.map +0 -1
  21. package/dist/rules/no-single-tag-message.js +0 -49
  22. package/dist/rules/no-single-tag-message.js.map +0 -1
  23. package/dist/rules/no-single-tag-message.test.d.ts +0 -2
  24. package/dist/rules/no-single-tag-message.test.d.ts.map +0 -1
  25. package/dist/rules/no-single-tag-message.test.js +0 -72
  26. package/dist/rules/no-single-tag-message.test.js.map +0 -1
  27. package/dist/rules/no-single-variable-message.d.ts +0 -2
  28. package/dist/rules/no-single-variable-message.d.ts.map +0 -1
  29. package/dist/rules/no-single-variable-message.js +0 -74
  30. package/dist/rules/no-single-variable-message.js.map +0 -1
  31. package/dist/rules/no-single-variable-message.test.d.ts +0 -2
  32. package/dist/rules/no-single-variable-message.test.d.ts.map +0 -1
  33. package/dist/rules/no-single-variable-message.test.js +0 -74
  34. package/dist/rules/no-single-variable-message.test.js.map +0 -1
  35. package/dist/rules/valid-t-call-location.d.ts +0 -5
  36. package/dist/rules/valid-t-call-location.d.ts.map +0 -1
  37. package/dist/rules/valid-t-call-location.js +0 -69
  38. package/dist/rules/valid-t-call-location.js.map +0 -1
  39. package/dist/rules/valid-t-call-location.test.d.ts +0 -2
  40. package/dist/rules/valid-t-call-location.test.d.ts.map +0 -1
  41. package/dist/rules/valid-t-call-location.test.js +0 -104
  42. package/dist/rules/valid-t-call-location.test.js.map +0 -1
package/README.md CHANGED
@@ -5,119 +5,77 @@
5
5
  [![CI](https://github.com/sebastian-software/eslint-plugin-lingui-typescript/actions/workflows/ci.yml/badge.svg)](https://github.com/sebastian-software/eslint-plugin-lingui-typescript/actions/workflows/ci.yml)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
7
 
8
- > 🔍 Type-aware ESLint rules for [Lingui](https://lingui.dev/) catch unlocalized strings with zero configuration using TypeScript's type system.
8
+ ESLint rules for [Lingui](https://lingui.dev/) that use TypeScript's type system to tell technical strings from user-facing text. No whitelists to maintain. No false positives to suppress. No configuration to tweak.
9
9
 
10
- **[📖 Documentation & Examples](https://sebastian-software.github.io/eslint-plugin-lingui-typescript/)**
10
+ **[Documentation & Examples](https://sebastian-software.github.io/eslint-plugin-lingui-typescript/)**
11
11
 
12
- ## Why TypeScript?
12
+ ## The problem with pattern-based i18n linting
13
13
 
14
- Traditional i18n linters rely on heuristics and manual whitelists to distinguish user-visible text from technical strings. This leads to false positives and constant configuration tweaking.
14
+ i18n linters that rely on pattern matching can't tell a CSS class name from a button label, or a DOM event name from an error message. You end up maintaining long ignore lists and still get false positives every time someone calls a new API:
15
15
 
16
- This plugin leverages TypeScript's type system to **automatically** recognize technical strings:
16
+ ```ts
17
+ // Pattern-based linters flag all of these as "missing translation"
18
+ document.createElement("div") // It's a DOM tag name
19
+ element.addEventListener("click", handler) // It's an event name
20
+ fetch(url, { mode: "cors" }) // It's a typed option
21
+ const status: "idle" | "loading" = "idle" // It's a string literal union
22
+ <Box className="flex items-center" /> // It's a CSS class
23
+ ```
24
+
25
+ You add each one to a whitelist. The whitelist grows. New team members hit the same false positives all over again.
26
+
27
+ ## How this plugin solves it
28
+
29
+ This plugin reads TypeScript's type information instead of guessing. When a string flows into a parameter typed as `keyof HTMLElementTagNameMap`, or is assigned to a variable typed as `"idle" | "loading" | "error"`, the plugin knows it's technical. You don't configure anything.
17
30
 
18
31
  ```ts
19
- // Automatically ignored - TypeScript knows these are technical
20
- document.createElement("div") // keyof HTMLElementTagNameMap
21
- element.addEventListener("click", handler) // keyof GlobalEventHandlersEventMap
22
- fetch(url, { mode: "cors" }) // RequestMode
32
+ // Automatically ignored TypeScript provides the context
33
+ document.createElement("div") // keyof HTMLElementTagNameMap
34
+ element.addEventListener("click", handler) // keyof GlobalEventHandlersEventMap
35
+ fetch(url, { mode: "cors" }) // RequestMode
23
36
  date.toLocaleDateString("de-DE", { weekday: "long" }) // Intl.DateTimeFormatOptions
24
37
 
25
38
  type Status = "idle" | "loading" | "error"
26
- const status: Status = "loading" // String literal union
39
+ const status: Status = "loading" // String literal union
27
40
 
28
- // Automatically ignored - styling props, constants, and numeric strings
29
- <Box containerClassName="flex items-center" /> // *ClassName, *Color, *Style, etc.
30
- <div className={clsx("px-4", "py-2")} /> // className utilities (clsx, cn, etc.)
31
- <Calendar classNames={{ day: "bg-white" }} /> // nested classNames objects
32
- const colorClasses = { active: "bg-green-100" } // *Classes, *Colors, *Styles, etc.
33
- const price = "1,00€" // No letters = technical
41
+ // Styling props and utility patterns recognized automatically
42
+ <Box containerClassName="flex items-center" /> // *ClassName, *Color, *Style
43
+ <div className={clsx("px-4", "py-2")} /> // className utilities (clsx, cn)
44
+ <Calendar classNames={{ day: "bg-white" }} /> // Nested classNames objects
45
+ const colorClasses = { active: "bg-green-100" } // *Classes, *Colors, *Styles
46
+ const price = "1,00€" // No letters = not user-facing
34
47
 
35
- // Reported - actual user-visible text
48
+ // Reported these actually need translation
36
49
  const message = "Welcome to our app"
37
50
  <button>Save changes</button>
38
51
  ```
39
52
 
40
- **No configuration needed** for DOM APIs, Intl methods, string literal unions, styling props, or numeric strings. TypeScript + smart heuristics handle it!
41
-
42
- ### Smart Lingui Detection
43
-
44
- The plugin uses TypeScript's symbol resolution to verify that `t`, `Trans`, `msg`, etc. actually come from Lingui packages — not just any function with the same name:
53
+ The plugin also verifies that `t`, `Trans`, and other macros actually come from `@lingui/*` packages through TypeScript's symbol resolution, not just name matching:
45
54
 
46
55
  ```ts
47
56
  import { t } from "@lingui/macro"
48
- const label = t`Save` // Recognized as Lingui
57
+ const label = t`Save` // Recognized as Lingui
49
58
 
50
- // Your own function with the same name
51
- const t = (key: string) => translations[key]
52
- const label = t("save") // ❌ Not confused with Lingui
59
+ const t = (key: string) => map[key]
60
+ const label = t("save") // Not confused with Lingui
53
61
  ```
54
62
 
55
- ## Features
56
-
57
- - 🔍 Detects incorrect usage of Lingui translation macros
58
- - 📝 Enforces simple, safe expressions inside translated messages
59
- - 🎯 Detects missing localization of user-visible text
60
- - 🧠 Zero-config recognition of technical strings via TypeScript types
61
- - 🎨 Auto-ignores styling props (`*ClassName`, `*Color`, `*Style`, `*Icon`, `*Image`, `*Size`, `*Id`)
62
- - 📦 Auto-ignores styling variables (`colorClasses`, `STATUS_COLORS`, `buttonStyles`, etc.)
63
- - 🔧 Auto-ignores styling helper functions (`getStatusColor`, `getButtonClass`, etc.)
64
- - 🔢 Auto-ignores numeric/symbolic strings without letters (`"1,00€"`, `"12:30"`)
65
- - 🏷️ Branded types for custom ignore patterns (loggers, analytics, etc.)
66
- - 🔒 Verifies Lingui macros actually come from `@lingui/*` packages (no false positives from similarly-named functions)
67
-
68
- ## Branded Types for Custom Ignore Patterns
69
-
70
- For cases not covered by automatic detection (like custom loggers or analytics), this plugin exports branded types you can use to mark strings as "no translation needed":
71
-
72
- ```ts
73
- import { unlocalized } from "eslint-plugin-lingui-typescript/types"
74
-
75
- // Wrap your logger to ignore all string arguments
76
- function createLogger(prefix = "[App]") {
77
- return unlocalized({
78
- debug: (...args: unknown[]) => console.debug(prefix, ...args),
79
- info: (...args: unknown[]) => console.info(prefix, ...args),
80
- warn: (...args: unknown[]) => console.warn(prefix, ...args),
81
- error: (...args: unknown[]) => console.error(prefix, ...args),
82
- })
83
- }
84
-
85
- const logger = createLogger()
86
- logger.info("Server started on port", 3000) // ✅ Automatically ignored
87
- logger.error("Connection failed:", error) // ✅ Automatically ignored
88
- ```
63
+ ## Getting started
89
64
 
90
- ### Available Types
65
+ ### Requirements
91
66
 
92
- | Type | Use Case |
93
- |------|----------|
94
- | `UnlocalizedFunction<T>` | Wrap functions/objects to ignore all string arguments |
95
- | `unlocalized(value)` | Helper function for automatic type inference |
96
- | `UnlocalizedText` | Generic technical strings |
97
- | `UnlocalizedLog` | Logger message parameters (string only) |
98
- | `UnlocalizedStyle` | Style values (colors, fonts, spacing) |
99
- | `UnlocalizedClassName` | CSS class names |
100
- | `UnlocalizedEvent` | Analytics/tracking event names |
101
- | `UnlocalizedKey` | Storage keys, query keys |
102
-
103
- See the [no-unlocalized-strings documentation](docs/rules/no-unlocalized-strings.md#branded-types) for detailed examples.
104
-
105
- ## Requirements
106
-
107
- - Node.js ≥ 24
108
- - ESLint ≥ 9
109
- - TypeScript ≥ 5
67
+ - Node.js >= 24, ESLint >= 9, TypeScript >= 5
110
68
  - `typescript-eslint` with type-aware linting enabled
111
69
 
112
- ## Installation
70
+ ### Installation
113
71
 
114
72
  ```bash
115
73
  npm install --save-dev eslint-plugin-lingui-typescript
116
74
  ```
117
75
 
118
- ## Usage
76
+ ### Configuration
119
77
 
120
- This plugin requires TypeScript and type-aware linting. Configure your `eslint.config.ts`:
78
+ Add the recommended config to your `eslint.config.ts`:
121
79
 
122
80
  ```ts
123
81
  import eslint from "@eslint/js"
@@ -139,7 +97,7 @@ export default [
139
97
  ]
140
98
  ```
141
99
 
142
- Or configure rules manually:
100
+ Or pick individual rules:
143
101
 
144
102
  ```ts
145
103
  {
@@ -153,81 +111,112 @@ Or configure rules manually:
153
111
  }
154
112
  ```
155
113
 
114
+ That's it. The plugin starts working immediately — DOM APIs, Intl methods, string literal unions, styling props, and numeric strings are all handled out of the box.
115
+
156
116
  ## Rules
157
117
 
158
118
  | Rule | Description | Recommended |
159
119
  |------|-------------|:-----------:|
160
- | [no-unlocalized-strings](docs/rules/no-unlocalized-strings.md) | Detects user-visible strings not wrapped in Lingui macros. Uses TypeScript types to automatically ignore technical strings like string literal unions, DOM APIs, and Intl methods. | ✅ |
161
- | [no-single-variables-to-translate](docs/rules/no-single-variables-to-translate.md) | Disallows messages that consist only of variables without surrounding text. Such messages provide no context for translators. | ✅ |
162
- | [no-single-tag-to-translate](docs/rules/no-single-tag-to-translate.md) | Disallows `<Trans>` components that contain only a single JSX element without text. The wrapped element should have surrounding text for context. | ✅ |
163
- | [no-nested-macros](docs/rules/no-nested-macros.md) | Prevents nesting Lingui macros inside each other (e.g., `t` inside `<Trans>`). Nested macros create invalid message catalogs and confuse translators. | ✅ |
164
- | [no-expression-in-message](docs/rules/no-expression-in-message.md) | Restricts embedded expressions to simple identifiers only. Complex expressions like `${user.name}` or `${formatPrice(x)}` must be extracted to named variables first. | ✅ |
165
- | [t-call-in-function](docs/rules/t-call-in-function.md) | Ensures `t` macro calls are inside functions or class properties, not at module scope. Module-level calls execute before i18n is initialized and won't update on locale change. | ✅ |
166
- | [consistent-plural-format](docs/rules/consistent-plural-format.md) | Enforces consistent plural value format — either `#` hash syntax or `${var}` template literals throughout the codebase. | ✅ |
120
+ | [no-unlocalized-strings](docs/rules/no-unlocalized-strings.md) | Detects user-visible strings not wrapped in Lingui macros. Uses TypeScript types to automatically ignore technical strings. | ✅ |
121
+ | [no-single-variables-to-translate](docs/rules/no-single-variables-to-translate.md) | Disallows messages that consist only of variables without surrounding text translators need context. | ✅ |
122
+ | [no-single-tag-to-translate](docs/rules/no-single-tag-to-translate.md) | Disallows `<Trans>` components that contain only a single JSX element without text. | ✅ |
123
+ | [no-nested-macros](docs/rules/no-nested-macros.md) | Prevents nesting Lingui macros inside each other. Nested macros create invalid message catalogs. | ✅ |
124
+ | [no-expression-in-message](docs/rules/no-expression-in-message.md) | Restricts embedded expressions to simple identifiers. Complex expressions must be extracted to named variables. | ✅ |
125
+ | [t-call-in-function](docs/rules/t-call-in-function.md) | Ensures `t` macro calls live inside functions, not at module scope where i18n isn't initialized yet. | ✅ |
126
+ | [consistent-plural-format](docs/rules/consistent-plural-format.md) | Enforces consistent plural value format — either `#` hash syntax or `${var}` template literals. | ✅ |
167
127
  | [text-restrictions](docs/rules/text-restrictions.md) | Enforces project-specific text restrictions with custom patterns and messages. Requires configuration. | — |
168
128
 
129
+ ## Branded types for edge cases
130
+
131
+ For strings that automatic detection can't cover (custom loggers, analytics events, internal keys), the plugin exports branded types:
132
+
133
+ ```ts
134
+ import { unlocalized } from "eslint-plugin-lingui-typescript/types"
135
+
136
+ const logger = unlocalized({
137
+ debug: (...args: unknown[]) => console.debug(...args),
138
+ info: (...args: unknown[]) => console.info(...args),
139
+ error: (...args: unknown[]) => console.error(...args),
140
+ })
141
+
142
+ logger.info("Server started on port", 3000) // Automatically ignored
143
+ logger.error("Connection failed:", error) // Automatically ignored
144
+ ```
145
+
146
+ | Type | Use Case |
147
+ |------|----------|
148
+ | `UnlocalizedFunction<T>` | Wrap functions/objects to ignore all string arguments |
149
+ | `unlocalized(value)` | Helper function for automatic type inference |
150
+ | `UnlocalizedText` | Generic technical strings |
151
+ | `UnlocalizedLog` | Logger message parameters |
152
+ | `UnlocalizedStyle` | Style values (colors, fonts, spacing) |
153
+ | `UnlocalizedClassName` | CSS class names |
154
+ | `UnlocalizedEvent` | Analytics/tracking event names |
155
+ | `UnlocalizedKey` | Storage keys, query keys |
156
+
157
+ See the [no-unlocalized-strings documentation](docs/rules/no-unlocalized-strings.md#branded-types) for detailed examples.
158
+
169
159
  ## Migrating from eslint-plugin-lingui
170
160
 
171
- This plugin is a TypeScript-focused alternative to the official [eslint-plugin-lingui](https://github.com/lingui/eslint-plugin-lingui). Rule names are compatible where possible, making migration straightforward.
161
+ This plugin is a drop-in alternative to the official [eslint-plugin-lingui](https://github.com/lingui/eslint-plugin-lingui). Rule names are compatible, making migration straightforward.
172
162
 
173
- ### Key Differences
163
+ ### What changes
174
164
 
175
- | Feature | eslint-plugin-lingui | eslint-plugin-lingui-typescript |
165
+ | | eslint-plugin-lingui | This plugin |
176
166
  |---------|---------------------|--------------------------------|
177
- | **Type-aware detection** | Heuristics only | Uses TypeScript types |
178
- | **String literal unions** | Manual whitelist | Auto-detected |
179
- | **DOM API strings** | Manual whitelist | Auto-detected |
180
- | **Intl method arguments** | Manual whitelist | Auto-detected |
181
- | **Styling props** (`*ClassName`, etc.) | Manual whitelist | Auto-detected |
182
- | **Styling constants** (`*_COLORS`, etc.) | Manual whitelist | Auto-detected |
183
- | **Numeric strings** (`"1,00€"`) | Manual whitelist | Auto-detected |
184
- | **Custom ignore patterns** | `ignoreFunctions` only | Branded types (`unlocalized()`) |
185
- | **Lingui macro verification** | Name-based only | Verifies package origin |
186
- | **ESLint version** | 8.x | 9.x (flat config) |
187
- | **Config format** | Legacy `.eslintrc` | Flat config only |
167
+ | **Detection method** | Heuristics + manual whitelists | TypeScript type system |
168
+ | **String literal unions** | Manual whitelist | Auto-detected |
169
+ | **DOM API strings** | Manual whitelist | Auto-detected |
170
+ | **Intl method arguments** | Manual whitelist | Auto-detected |
171
+ | **Styling props** | Manual whitelist | Auto-detected |
172
+ | **Styling constants** | Manual whitelist | Auto-detected |
173
+ | **Numeric strings** | Manual whitelist | Auto-detected |
174
+ | **Custom ignore patterns** | `ignoreFunctions` only | Branded types (`unlocalized()`) |
175
+ | **Macro verification** | Name-based | Package-origin verification |
176
+ | **ESLint** | v8 legacy config | v9 flat config |
188
177
 
189
- ### Why Switch?
178
+ ### Why switch?
190
179
 
191
- 1. **Less configuration**: TypeScript's type system automatically identifies technical strings — no need to maintain long whitelists of ignored functions and patterns.
180
+ **Less configuration.** TypeScript's type system handles what used to require dozens of whitelist entries.
192
181
 
193
- 2. **Fewer false positives**: Strings typed as literal unions (like `"loading" | "error"`) are automatically recognized as non-translatable.
182
+ **Fewer false positives.** Strings typed as literal unions are recognized as non-translatable without any setup.
194
183
 
195
- 3. **Modern ESLint**: Built for ESLint 9's flat config from the ground up.
184
+ **Modern ESLint.** Built for ESLint 9 flat config from the ground up.
196
185
 
197
- ### Rule Mapping and Options Compatibility
186
+ ### Rule mapping
198
187
 
199
188
  | eslint-plugin-lingui | eslint-plugin-lingui-typescript | Options |
200
189
  |---------------------|--------------------------------|---------|
201
190
  | `lingui/no-unlocalized-strings` | `lingui-ts/no-unlocalized-strings` | ⚠️ Different (see below) |
202
- | `lingui/t-call-in-function` | `lingui-ts/t-call-in-function` | ✅ None |
203
- | `lingui/no-single-variables-to-translate` | `lingui-ts/no-single-variables-to-translate` | ✅ None |
204
- | `lingui/no-expression-in-message` | `lingui-ts/no-expression-in-message` | ✅ None |
205
- | `lingui/no-single-tag-to-translate` | `lingui-ts/no-single-tag-to-translate` | ✅ None |
191
+ | `lingui/t-call-in-function` | `lingui-ts/t-call-in-function` | ✅ Compatible |
192
+ | `lingui/no-single-variables-to-translate` | `lingui-ts/no-single-variables-to-translate` | ✅ Compatible |
193
+ | `lingui/no-expression-in-message` | `lingui-ts/no-expression-in-message` | ✅ Compatible |
194
+ | `lingui/no-single-tag-to-translate` | `lingui-ts/no-single-tag-to-translate` | ✅ Compatible |
206
195
  | `lingui/text-restrictions` | `lingui-ts/text-restrictions` | ✅ Compatible (`rules`), + `minLength` |
207
196
  | `lingui/consistent-plural-format` | `lingui-ts/consistent-plural-format` | ✅ Compatible (`style`) |
208
197
  | `lingui/no-trans-inside-trans` | `lingui-ts/no-nested-macros` | ✅ Extended (all macros) |
209
198
 
210
199
  ### Options Changes for `no-unlocalized-strings`
211
200
 
212
- The `no-unlocalized-strings` rule has different options because TypeScript types replace most manual configuration:
201
+ TypeScript types replace most manual configuration:
213
202
 
214
203
  | Original Option | This Plugin | Notes |
215
204
  |-----------------|-------------|-------|
216
- | `useTsTypes` | — | Always enabled (TypeScript required) |
205
+ | `useTsTypes` | — | Always enabled |
217
206
  | `ignore` (array of regex) | `ignorePattern` (single regex) | Simplified |
218
- | `ignoreFunctions` | `ignoreFunctions` | Simplified (Console/Error auto-detected) |
219
- | `ignoreNames` (with regex support) | `ignoreNames` | Simplified (no regex, plain strings only) |
207
+ | `ignoreFunctions` | `ignoreFunctions` | Simplified (Console/Error auto-detected) |
208
+ | `ignoreNames` (with regex support) | `ignoreNames` | Plain strings only |
220
209
  | — | `ignoreProperties` | New: separate option for JSX attributes and object properties |
221
- | `ignoreMethodsOnTypes` | — | Not needed (TypeScript handles this automatically) |
210
+ | `ignoreMethodsOnTypes` | — | Not needed (handled by TypeScript) |
222
211
 
223
- **What you can remove from your config:**
212
+ **What you can drop from your config:**
224
213
  - `useTsTypes: true` — always enabled
225
214
  - Most `ignoreFunctions` entries for DOM APIs — auto-detected via types
226
215
  - Most `ignoreNames` entries for typed parameters — auto-detected via types
227
216
  - Most `ignoreProperties` entries (like `type`, `role`, `href`) — auto-detected via types
228
217
  - `ignoreMethodsOnTypes` — handled automatically
229
218
 
230
- ### Migration Steps
219
+ ### Migration steps
231
220
 
232
221
  1. Remove the old plugin:
233
222
  ```bash
@@ -252,17 +241,17 @@ The `no-unlocalized-strings` rule has different options because TypeScript types
252
241
 
253
242
  4. Update rule names in your config (change prefix from `lingui/` to `lingui-ts/`).
254
243
 
255
- 5. Review your ignore lists — many entries may no longer be needed thanks to type-aware detection.
244
+ 5. Review your ignore lists — many entries are no longer needed.
256
245
 
257
246
  ## Contributing
258
247
 
259
- Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md) before submitting a PR.
248
+ Contributions are welcome. Please read our [Contributing Guide](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md) before submitting a PR.
260
249
 
261
- ## Related Projects
250
+ ## Related projects
262
251
 
263
- - [Lingui](https://lingui.dev/) The excellent i18n library this plugin is built for. Provides powerful macros like `t`, `<Trans>`, and `plural` for seamless internationalization.
264
- - [eslint-plugin-lingui](https://github.com/lingui/eslint-plugin-lingui) The official Lingui ESLint plugin. Great for JavaScript projects; this plugin extends the concept with TypeScript type-awareness.
265
- - [typescript-eslint](https://typescript-eslint.io/) The foundation that makes type-aware linting possible. This plugin builds on their excellent tooling.
252
+ - [Lingui](https://lingui.dev/) The i18n library this plugin is built for
253
+ - [eslint-plugin-lingui](https://github.com/lingui/eslint-plugin-lingui) The official Lingui ESLint plugin for JavaScript projects
254
+ - [typescript-eslint](https://typescript-eslint.io/) The foundation that makes type-aware linting possible
266
255
 
267
256
  ## License
268
257
 
@@ -270,4 +259,4 @@ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md)
270
259
 
271
260
  ---
272
261
 
273
- Made with ❤️ by [Sebastian Software](https://www.sebastian-software.de)
262
+ Made with care by [Sebastian Software](https://www.sebastian-software.de)
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAeH,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;aAeK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CACvC,CAAA;AAqBD,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkBH,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;aAeK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CACvC,CAAA;AAqBD,eAAe,MAAM,CAAA"}
package/dist/index.js CHANGED
@@ -4,9 +4,12 @@
4
4
  * @packageDocumentation
5
5
  */
6
6
  import { consistentPluralFormat } from "./rules/consistent-plural-format.js";
7
- // Read version from package.json at build time
8
- // This is resolved by TypeScript with resolveJsonModule or by the bundler
9
- const PLUGIN_VERSION = "1.8.4"; // Synced with package.json during release
7
+ import { readFileSync } from "node:fs";
8
+ import { dirname, resolve } from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), "../package.json");
11
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
12
+ const PLUGIN_VERSION = packageJson.version ?? "0.0.0";
10
13
  import { noExpressionInMessage } from "./rules/no-expression-in-message.js";
11
14
  import { noNestedMacros } from "./rules/no-nested-macros.js";
12
15
  import { noSingleTagToTranslate } from "./rules/no-single-tag-to-translate.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAA;AAE5E,+CAA+C;AAC/C,0EAA0E;AAC1E,MAAM,cAAc,GAAG,OAAO,CAAA,CAAC,0CAA0C;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAA;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAC9E,OAAO,EAAE,4BAA4B,EAAE,MAAM,6CAA6C,CAAA;AAC1F,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAA;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAE/D,MAAM,MAAM,GAAG;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,iCAAiC;QACvC,OAAO,EAAE,cAAc;KACxB;IACD,KAAK,EAAE;QACL,0BAA0B,EAAE,sBAAsB;QAClD,0BAA0B,EAAE,qBAAqB;QACjD,kBAAkB,EAAE,cAAc;QAClC,4BAA4B,EAAE,sBAAsB;QACpD,kCAAkC,EAAE,4BAA4B;QAChE,wBAAwB,EAAE,oBAAoB;QAC9C,mBAAmB,EAAE,gBAAgB;QACrC,oBAAoB,EAAE,eAAe;KACtC;IACD,OAAO,EAAE,EAA6B;CACvC,CAAA;AAED,sCAAsC;AACtC,MAAM,CAAC,OAAO,GAAG;IACf,kBAAkB,EAAE;QAClB,OAAO,EAAE;YACP,WAAW,EAAE,MAAM;SACpB;QACD,KAAK,EAAE;YACL,oCAAoC,EAAE,OAAO;YAC7C,oCAAoC,EAAE,OAAO;YAC7C,4BAA4B,EAAE,OAAO;YACrC,sCAAsC,EAAE,OAAO;YAC/C,4CAA4C,EAAE,OAAO;YACrD,kCAAkC,EAAE,OAAO;YAC3C,8BAA8B,EAAE,OAAO;YACvC,gEAAgE;SACjE;KACF;CACF,CAAA;AAED,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAA;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAA;AAC3F,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAyB,CAAA;AAC7F,MAAM,cAAc,GAAG,WAAW,CAAC,OAAO,IAAI,OAAO,CAAA;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAA;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAC9E,OAAO,EAAE,4BAA4B,EAAE,MAAM,6CAA6C,CAAA;AAC1F,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAA;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAE/D,MAAM,MAAM,GAAG;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,iCAAiC;QACvC,OAAO,EAAE,cAAc;KACxB;IACD,KAAK,EAAE;QACL,0BAA0B,EAAE,sBAAsB;QAClD,0BAA0B,EAAE,qBAAqB;QACjD,kBAAkB,EAAE,cAAc;QAClC,4BAA4B,EAAE,sBAAsB;QACpD,kCAAkC,EAAE,4BAA4B;QAChE,wBAAwB,EAAE,oBAAoB;QAC9C,mBAAmB,EAAE,gBAAgB;QACrC,oBAAoB,EAAE,eAAe;KACtC;IACD,OAAO,EAAE,EAA6B;CACvC,CAAA;AAED,sCAAsC;AACtC,MAAM,CAAC,OAAO,GAAG;IACf,kBAAkB,EAAE;QAClB,OAAO,EAAE;YACP,WAAW,EAAE,MAAM;SACpB;QACD,KAAK,EAAE;YACL,oCAAoC,EAAE,OAAO;YAC7C,oCAAoC,EAAE,OAAO;YAC7C,4BAA4B,EAAE,OAAO;YACrC,sCAAsC,EAAE,OAAO;YAC/C,4CAA4C,EAAE,OAAO;YACrD,kCAAkC,EAAE,OAAO;YAC3C,8BAA8B,EAAE,OAAO;YACvC,gEAAgE;SACjE;KACF;CACF,CAAA;AAED,eAAe,MAAM,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"no-unlocalized-strings.d.ts","sourceRoot":"","sources":["../../src/rules/no-unlocalized-strings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,WAAW,EAAiB,MAAM,0BAA0B,CAAA;AAQrF,MAAM,WAAW,OAAO;IACtB,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAiyCD,eAAO,MAAM,oBAAoB,2FAsM/B,CAAA"}
1
+ {"version":3,"file":"no-unlocalized-strings.d.ts","sourceRoot":"","sources":["../../src/rules/no-unlocalized-strings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,WAAW,EAAiB,MAAM,0BAA0B,CAAA;AAQrF,MAAM,WAAW,OAAO;IACtB,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAykDD,eAAO,MAAM,oBAAoB,2FA4M/B,CAAA"}