Skip to content

Remove some Limitations / PitfallsΒ #90

@BrunoJuchli

Description

@BrunoJuchli

Hi There

I have a proposal to improve the PoExtractor and would like to get some feedback from you whether you the proposed solution is agreeable with the project and whether you would accept a PR.

Motivation

My team discussed using this tool and we anticipate the limitations regarding name convention and msgctxt to lead to some friction:

  • the fact that the member name (T, S, H) is used to identity usage of IStringLocalizer
    • it's brittle. Spelling it differently means localization just stops working, without any errors.
    • our coding style says field members need to start with a lower case character. We'd have a choice of:
      • ignoring "warnings" in the IDE --> this lessens the values of IDE warnings overall
      • each and every time add a // ReSharper disable once InconsistentNaming required directive --> cumbersome.
  • deriving the msgctxt from the class the IStringLocalizer is used in creates a few scenarios where the PoExtractor uses a different msgctxt than OrchardCore.Localization will use. These can happen by accident. The code will still compile, and we'll only find out once someone reports localizations as missing - creating friction in the process. This can happen accidentally, for example, when you move some code using IStringLocalizer<T> to another class.
    • theoretically we could write an Analyzer ourselves to ensure code is conformant with the conventions used in the PoExtractor. However, that would duplicate some of what PoExtractor is doing - so not better to maintain. Furthermore, if we can write an analyzer which can judge conformity (correct name for IStringLocalizer<T>, T is correctly chosen), we can most likely also just remove the limitations with similar code. And we think that's worth more.

Solution Idea

What's missing in the current implementation is, instead of just reading the AST, also resolving types.
From some quick research it seems to me that for this we need a roslyn SemanticModel besides the SyntaxTree. And the SemanticModel requires a Compilation.

I've done a very dirty proof of concept:
See here
and here

The result of this is, that the field/property the IStringLocalizer<T> is assigned to can have any name.
The part of generating a different msgctxt depending on the type parameter T is not addressed, but from what I see can be done with the information already made available in this change.

I'm not really experienced with Roslyn, so there's a few questions-marks / risks:

  • maybe there's a better way to achieve the same
  • haven't tested how it works when the code doesn't compile
  • haven't tested whether/how it works when the source references another version of the Microsoft.Extensions.Localization, which defines the IStringLocalizer<T> interface
  • maybe a Compilation doesn't really mean compiling it... I just don't understand this well enough, yet ;-)

Having said that, I think it's not unlikely that it would only work on compiling (error-free) code (warnings would probably be fine).
If that limitation is fine, maybe the PoExtractor could be simplified by removing explicit support for razor (and even liquid?) templates by opening + building the whole project. My expectation here is that this would deal with generating the classes from .razor files automatically and the tool could then work on any class and not care for whether it's razor/liquid or whatnot.
I would, however, expect this to slow down processing time.

For us, both would be acceptable.

Alternative Solution

Instead of using Roslyn, and analyze source code, one could also analyze the IL with Mono.Cecil. From past experience, I would say, for the problem at hand, Mono.Cecil is simpler to work with than SyntaxTree + SemanticModel but:

  • only ever works on compiled code. The current solution does not need a compiled result, it doesn't even need code without errors / compiling code.
  • Cecil development seems to be on the backburner, and I'm not sure about continued support/development
  • don't know how well this integrates with AoT / native compilation
  • consider me biased because I have experience with Mono.CeCil but almost none with Roslyn

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions