Skip to content

fix(LC0091): namespace-aware translation IDs for SDK 18.0.38.52553#391

Merged
Arthurvdv merged 2 commits into
mainfrom
fix/lc0091-namespace-translation-ids
Jul 8, 2026
Merged

fix(LC0091): namespace-aware translation IDs for SDK 18.0.38.52553#391
Arthurvdv merged 2 commits into
mainfrom
fix/lc0091-namespace-translation-ids

Conversation

@Arthurvdv

@Arthurvdv Arthurvdv commented Jul 8, 2026

Copy link
Copy Markdown
Member

Problem

With AL SDK 18.0.38.52553, 9 LC0091 (TranslatableTextShouldBeTranslated) tests fail — all HasDiagnostic* cases. The analyzer emits no LC0091 where it should.

Root cause (version drift)

LanguageFileUtilities.GetLanguageSymbolId(ISymbol, IRootTypeSymbol?) and GetLabelTextConstLanguageSymbolId(ISymbol, IRootTypeSymbol?) gained an optional bool useNamespaces = false parameter in 18.0.38.52553 (part of the TranslationsWithNamespaces compiler feature). C# bakes optional-parameter defaults into the call site at compile time. The analyzer is built once against the lowest net10.0 SDK (18.0.36.x, 2-param) and, in CI, runs against 18.0.38.52553 (binary reference) — so the baked 2-param overload no longer exists at runtime → MissingMethodException → no LC0091. NoDiagnostic cases pass trivially. A local ProjectReference build compiles+runs against the same SDK and does not reproduce it.

Fix

Translation IDs are now computed through runtime reflection so no arity is baked into the call site, and that reflection lives in a dedicated ALCops.Common.Reflection.TranslationIdHelper (public ComputeTranslationId(ISymbol, IRootTypeSymbol?, bool isLabelConst)):

  • New SDKs (feature present): internal GetTranslationFileId(...) + public UseTranslationsWithNamespaces(ISymbol). Produces namespace-aware trans-unit IDs (namespace-prefixed, unhashed segments joined by " - ", hashed only when > 400 chars) that match the compiler — avoiding false positives on namespace-enabled projects.
  • Older SDKs (methods absent): fall back to the public 2-param methods.

Design split:

  • Mechanism → ALCops.Common: the Lazy<MethodInfo?> probes, GetTranslationFileId/fallback branching and useNamespaces detection sit in TranslationIdHelper, alongside SymbolHelper / EnumProvider — matching the project convention that all SDK-version-compat reflection is centralized in Common, so future SDK bumps only touch one place. Guarded with #if !NETSTANDARD2_1 (the underlying SDK methods don't exist there; LC0091 is an inert stub on netstandard2.1).
  • Policy → analyzer: the analyzer keeps translation concerns only — which symbols to inspect, isLabelConst decisions, null-guarding and reporting — and calls TranslationIdHelper.ComputeTranslationId(...).
  • Added EnumProvider.SymbolKind.NamedType for the label-const path (mirrors GetLabelTextConstLanguageSymbolId, which forces NamedType).

Tests

Added version-gated (RequireMinimumVersion("18.0.38.52553")) namespace regression tests that enable the feature via CompilationOptions.WithCompilerFeatures(TranslationsWithNamespaces) (resolved reflectively so the test project still compiles on older SDKs):

  • HasDiagnosticWithNamespaces — empty XLIFF, feature on → namespace-mode path reports.
  • NoDiagnosticWithNamespaces — translated XLIFF with the namespace-aware id Namespace MyCompany.App - Table MyTable - Property Caption → no false positive.

Local validation

  • 18.0.36.33307 (pinned): 262 passed, 2 namespace tests correctly skipped.
  • 18.0.38.52553 (temporarily installed, then reverted): 264 passed — including both namespace tests (new GetTranslationFileId reflection path).

Cross-version coverage is handled by the CI matrix.

Docs

Updated .github/instructions/lc0091-translatable-text-should-be-translated.instructions.md (design decisions, known issues, test coverage).

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Arthurvdv and others added 2 commits July 8, 2026 10:27
…8.52553

AL 18.0.38.52553 added an optional `useNamespaces` parameter to
`LanguageFileUtilities.GetLanguageSymbolId` and
`GetLabelTextConstLanguageSymbolId` (part of the TranslationsWithNamespaces
compiler feature). C# bakes optional-parameter call sites at compile time,
so the analyzer (built against the lowest net10.0 SDK and run against
18.0.38.52553 in CI) hit MissingMethodException and emitted no LC0091 —
failing all 9 HasDiagnostic tests.

Compute translation IDs via runtime reflection so no arity is baked into
the call site:
- New SDKs: internal GetTranslationFileId(...) + UseTranslationsWithNamespaces(ISymbol),
  producing namespace-aware trans-unit IDs that match the compiler (no false
  positives on namespace-enabled projects).
- Older SDKs: fall back to the public 2-param methods.

Add EnumProvider.SymbolKind.NamedType for the label-const path. Add
version-gated (RequireMinimumVersion 18.0.38.52553) namespace regression
tests that enable the feature via CompilationOptions.WithCompilerFeatures:
HasDiagnostic (empty XLIFF) and NoDiagnostic (translated XLIFF with the
namespace-aware ID). Update the LC0091 instruction file.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract the SDK-version-compat reflection for computing XLIFF trans-unit IDs
out of the TranslatableTextShouldBeTranslated analyzer into a dedicated
ALCops.Common.Reflection.TranslationIdHelper. This keeps all SDK-version-compat
reflection in one place (alongside SymbolHelper, EnumProvider), so future SDK
bumps only require changes in Common. The analyzer now calls
TranslationIdHelper.ComputeTranslationId and retains only translation policy
(which symbols to inspect, isLabelConst decisions, null-guarding).

No behavior change: LC0091 tests unchanged (14 passed, 2 namespace tests
skipped on SDK 18.0.36; validated green on 18.0.38.52553 previously).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Arthurvdv
Arthurvdv merged commit 872069e into main Jul 8, 2026
49 checks passed
@Arthurvdv
Arthurvdv deleted the fix/lc0091-namespace-translation-ids branch July 8, 2026 12:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant