Skip to content

Commit 6a5cdaa

Browse files
committed
fix(no-unlocalized-strings): ignore directive prologues
Ignore JavaScript/React directive prologues like "use strict", "use client", and "use server" which were incorrectly flagged as unlocalized strings because they contain letters and spaces.
1 parent f389f43 commit 6a5cdaa

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

src/rules/no-unlocalized-strings.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,13 @@ ruleTester.run("no-unlocalized-strings", noUnlocalizedStrings, {
393393
{ code: 'import name from "hello"', filename: "test.tsx" },
394394
{ code: 'export * from "hello_export_all"', filename: "test.tsx" },
395395

396+
// JavaScript/React directive prologues
397+
{ code: '"use strict"', filename: "test.tsx" },
398+
{ code: '"use client"', filename: "test.tsx" },
399+
{ code: '"use server"', filename: "test.tsx" },
400+
{ code: '"use client"\nimport React from "react"', filename: "test.tsx" },
401+
{ code: '"use server"\nexport async function action() {}', filename: "test.tsx" },
402+
396403
// =========================================================================
397404
// Branded types with __linguiIgnore
398405
// =========================================================================

src/rules/no-unlocalized-strings.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,37 @@ function isInsideStylingConstant(node: TSESTree.Node): boolean {
853853
// Syntax Context Checks (non-user-facing locations)
854854
// ============================================================================
855855

856+
/** Known JavaScript/React directive prologues */
857+
const DIRECTIVE_PROLOGUES = new Set(["use strict", "use client", "use server"])
858+
859+
/**
860+
* Checks if a string literal is a JavaScript directive prologue.
861+
*
862+
* Directive prologues are special string literals at the start of a script/module:
863+
* - "use strict" - JavaScript strict mode
864+
* - "use client" - React Server Components client boundary
865+
* - "use server" - React Server Components server actions
866+
*/
867+
function isDirectivePrologue(node: TSESTree.Node): boolean {
868+
if (node.type !== AST_NODE_TYPES.Literal || typeof node.value !== "string") {
869+
return false
870+
}
871+
872+
// Check if this is a known directive
873+
if (!DIRECTIVE_PROLOGUES.has(node.value)) {
874+
return false
875+
}
876+
877+
// Directive prologues must be expression statements at the program level
878+
const parent = node.parent
879+
if (parent.type !== AST_NODE_TYPES.ExpressionStatement) {
880+
return false
881+
}
882+
883+
const grandparent = parent.parent
884+
return grandparent.type === AST_NODE_TYPES.Program
885+
}
886+
856887
/**
857888
* Checks if a string is in a TypeScript type context (not runtime code).
858889
*
@@ -1356,6 +1387,11 @@ export const noUnlocalizedStrings = createRule<[Options], MessageId>({
13561387
return
13571388
}
13581389

1390+
// JavaScript/React directive prologues: "use strict", "use client", "use server"
1391+
if (isDirectivePrologue(node)) {
1392+
return
1393+
}
1394+
13591395
// TypeScript type definition (not runtime)
13601396
if (isInTypeContext(node)) {
13611397
return

0 commit comments

Comments
 (0)