Skip to content

Commit cd98a87

Browse files
committed
docs: add branded types documentation to README and rule docs
1 parent 1f38b6b commit cd98a87

File tree

2 files changed

+61
-2
lines changed

2 files changed

+61
-2
lines changed

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,46 @@ const label = t("save") // ❌ Not confused with Lingui
6060
- 📦 Auto-ignores styling variables (`colorClasses`, `STATUS_COLORS`, `buttonStyles`, etc.)
6161
- 🔧 Auto-ignores styling helper functions (`getStatusColor`, `getButtonClass`, etc.)
6262
- 🔢 Auto-ignores numeric/symbolic strings without letters (`"1,00€"`, `"12:30"`)
63+
- 🏷️ Branded types for custom ignore patterns (loggers, analytics, etc.)
6364
- 🔒 Verifies Lingui macros actually come from `@lingui/*` packages (no false positives from similarly-named functions)
6465

66+
## Branded Types for Custom Ignore Patterns
67+
68+
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":
69+
70+
```ts
71+
import { unlocalized } from "eslint-plugin-lingui-typescript/types"
72+
73+
// Wrap your logger to ignore all string arguments
74+
function createLogger(prefix = "[App]") {
75+
return unlocalized({
76+
debug: (...args: unknown[]) => console.debug(prefix, ...args),
77+
info: (...args: unknown[]) => console.info(prefix, ...args),
78+
warn: (...args: unknown[]) => console.warn(prefix, ...args),
79+
error: (...args: unknown[]) => console.error(prefix, ...args),
80+
})
81+
}
82+
83+
const logger = createLogger()
84+
logger.info("Server started on port", 3000) // ✅ Automatically ignored
85+
logger.error("Connection failed:", error) // ✅ Automatically ignored
86+
```
87+
88+
### Available Types
89+
90+
| Type | Use Case |
91+
|------|----------|
92+
| `UnlocalizedFunction<T>` | Wrap functions/objects to ignore all string arguments |
93+
| `unlocalized(value)` | Helper function for automatic type inference |
94+
| `UnlocalizedText` | Generic technical strings |
95+
| `UnlocalizedLog` | Logger message parameters (string only) |
96+
| `UnlocalizedStyle` | Style values (colors, fonts, spacing) |
97+
| `UnlocalizedClassName` | CSS class names |
98+
| `UnlocalizedEvent` | Analytics/tracking event names |
99+
| `UnlocalizedKey` | Storage keys, query keys |
100+
101+
See the [no-unlocalized-strings documentation](docs/rules/no-unlocalized-strings.md#branded-types) for detailed examples.
102+
65103
## Requirements
66104

67105
- Node.js ≥ 24
@@ -141,6 +179,7 @@ This plugin is a TypeScript-focused alternative to the official [eslint-plugin-l
141179
| **Styling props** (`*ClassName`, etc.) | Manual whitelist | ✅ Auto-detected |
142180
| **Styling constants** (`*_COLORS`, etc.) | Manual whitelist | ✅ Auto-detected |
143181
| **Numeric strings** (`"1,00€"`) | Manual whitelist | ✅ Auto-detected |
182+
| **Custom ignore patterns** | `ignoreFunctions` only | ✅ Branded types (`unlocalized()`) |
144183
| **Lingui macro verification** | Name-based only | ✅ Verifies package origin |
145184
| **ESLint version** | 8.x | 9.x (flat config) |
146185
| **Config format** | Legacy `.eslintrc` | Flat config only |

docs/rules/no-unlocalized-strings.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,13 +515,33 @@ interface ButtonProps {
515515

516516
### How It Works
517517

518-
These types use TypeScript's branded type pattern:
518+
These types use TypeScript's branded type pattern with two different markers:
519+
520+
**Parameter-level branding** (`__linguiIgnore`):
519521

520522
```ts
521523
type UnlocalizedLog = string & { readonly __linguiIgnore?: "UnlocalizedLog" }
522524
```
523525

524-
The `__linguiIgnore` property is a phantom type marker—it never exists at runtime. The rule checks for this property in the contextual type to determine if a string should be ignored.
526+
The rule checks if the parameter's contextual type has this property.
527+
528+
**Function-level branding** (`__linguiIgnoreArgs`):
529+
530+
```ts
531+
type UnlocalizedFunction<T> = T & { readonly __linguiIgnoreArgs?: true }
532+
```
533+
534+
The rule checks if the object/function being called has this property. If so, all string arguments are ignored.
535+
536+
**The `unlocalized()` helper:**
537+
538+
```ts
539+
function unlocalized<T>(value: T): UnlocalizedFunction<T> {
540+
return value as UnlocalizedFunction<T>
541+
}
542+
```
543+
544+
This is an identity function—it returns the input unchanged at runtime. But it changes the compile-time type to include the `__linguiIgnoreArgs` brand, enabling automatic type inference without manual annotations.
525545

526546
## When Not To Use It
527547

0 commit comments

Comments
 (0)