fix: extract only bindings imported from solid-translate (or i18n re-exports) - #8
Merged
Merged
Conversation
…exports)
The AST extractor treated any msg("...") call and any <T>/<Plural>
element as an extraction marker by name alone. A callback parameter named
msg (e.g. Solid's <Match>{(msg) => ...}</Match>) produced spurious
"msg() called without arguments" warnings, and a local function named
msg could get its string arguments wrongly extracted into the catalog.
Extraction now resolves the identifier's binding: imports must come from
"solid-translate" or an accepted re-export wrapper (default: any
specifier whose final path segment is solid-translate or i18n;
configurable via extractImportSources), aliased imports resolve to their
imported name, and locally bound identifiers (params, local consts,
local components, with scope shadowing tracked) are never extracted.
Unbound identifiers keep the old name-based behavior for snippet-style
sources.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
extractStringsFromSourcetreated anymsg("...")call and any<T>/<Plural>JSX element as an extraction marker by identifier name alone, with no check that the name is actually bound to a solid-translate import.Real-world false positive (hit in ditto-app): Solid's keyed
<Match>passes an accessor to its child callback —The
msghere is a callback parameter, yet the extractor flagged everymsg()call with a spuriousmsg() called without argumentswarning — and a local function namedmsgtaking a string literal would have its argument wrongly extracted into the translation catalog. The same applied to any local component that happened to be namedTorPlural.Fix
Extraction now resolves the identifier's binding before honoring it as a marker:
"solid-translate"itself, or (by default) any specifier whose final path segment issolid-translateori18n— covering host-app re-export wrappers like@/i18nor../lib/i18n. The accepted set is configurable via a newextractImportSources?: string[]option on both the Vite plugin config and the CLI config (an explicit list replaces thei18nheuristic;"solid-translate"is always accepted).import { msg as m }extractsm("x"),import { T as Trans }extracts<Trans>.const msg = ..., local components namedT, catch params, for-loop and block-scoped declarations — with scope shadowing tracked during the walk, so an inner shadow doesn't disable outer real usages.Applies to
msg()and to<T>/<Plural>element extraction (the other markers —<Var>,<Num>,<Currency>,<DateTime>— only ever appear as children inside<T>, where any element becomes a{n}slot regardless of name, and their canonical names are included in the binding-resolution set).Tests
New
tests/extract-imports.test.tscovering: callback-parammsg(no warning, no extraction), localconst msgfunction (not extracted), aliasedimport { msg as m }(extracted), re-export wrapperimport { msg } from "@/i18n"(extracted), local component namedT(not extracted), scope-shadowing boundaries, unrelated-module imports, the unbound-fallback compatibility case, and theimportSourcesoption semantics.bun test --conditions=browser(153 pass),bun run build, andtsc --noEmitare all green.🤖 Generated with Claude Code