You really need to divide the problem into some discrete sub-problems:
- Implement a mechanism to load templates from some type of configuration file or database.
- Implement a mechanism to parse the templates and extract the substitution markers from them.
- Implement a mechanism that interprets and evaluates substitution markers against objects in your program dynamically.
- Optionally, implement a mechanism that allows substitution markers to be statically evaluated either during compilation or at application startup.
So, here's some advice on each of the sub-problems:
Template Repository: I would consider going with a simple mechanism initially, but one that would allow you sys admins to make changes without risking messing anything else up. I would probably rule out web/app config files for this reason - and use either a settings file or (if your app already uses it) a database table. You may want to give each template a stable internal identifier as well as a customizable name. The code would rely on the stable identifier while the name is just a convenient way for admins to organize these templates.
Parsing Markers: This is one place where regular expressions seem to be a reasonable choice. It's not terribly difficult to parse out patterns of the form $(...) correctly.
Interpreting/Evaluating Markers: This is one of the more complicated parts of your problem. Unless performance is of paramount concern, I would probably use reflection and a bit of string manipulation to do the job. If you can constraint the substitution markers to only ever refer to public properties of your ORM objects, that would make life a lot simpler too. You could then just split the string based on '.' characters and then use iterative logic to fetch the value of the corresponding property until you get to the final value.
Compile/Runtime Validation: This is a tall order. You definitely want to get all of the other pieces working first. Once you do, one way of implementing this may be to load all templates at app startup, visit each one and make sure that the markers in the templates all exist in the object types in your ORM. Since it looks like you are already prefixing the object type name into the marker, this should be possible. Unfortunately, you probably can't reuse the same logic that evaluates markers to validate them - since for validation you don't have instances of the types - just their type information.