6
6
using System . Reflection ;
7
7
using System . Reflection . Emit ;
8
8
using System . Runtime . CompilerServices ;
9
- using Mono . Reflection ;
9
+ using Mono . Cecil ;
10
10
using Newtonsoft . Json ;
11
+ using OpCodes = Mono . Cecil . Cil . OpCodes ;
11
12
12
13
namespace CheapLoc
13
14
{
@@ -106,8 +107,87 @@ public static void ExportLocalizableForAssembly(Assembly assembly)
106
107
{
107
108
var types = assembly . GetTypes ( ) ;
108
109
110
+ var debugOutput = string . Empty ;
109
111
var outList = new Dictionary < string , LocEntry > ( ) ;
110
112
113
+ var assemblyDef = AssemblyDefinition . ReadAssembly ( assembly . Location ) ;
114
+
115
+ var toInspect = assemblyDef . MainModule . GetTypes ( )
116
+ . SelectMany ( t => t . Methods
117
+ . Where ( m => m . HasBody )
118
+ . Select ( m => new { t , m } ) ) ;
119
+
120
+ foreach ( var tm in toInspect )
121
+ {
122
+ var instructions = tm . m . Body . Instructions ;
123
+
124
+ foreach ( var instruction in instructions )
125
+ {
126
+ if ( instruction . OpCode == OpCodes . Call )
127
+ {
128
+ var methodInfo = instruction . Operand as MethodReference ;
129
+
130
+ if ( methodInfo != null )
131
+ {
132
+ var methodType = methodInfo . DeclaringType ;
133
+ var parameters = methodInfo . Parameters ;
134
+
135
+ if ( ! methodInfo . Name . Contains ( "Localize" ) )
136
+ continue ;
137
+
138
+ debugOutput += string . Format ( "->{0}.{1}.{2}({3});\n " ,
139
+ tm . t . FullName ,
140
+ methodType . Name ,
141
+ methodInfo . Name ,
142
+ string . Join ( ", " ,
143
+ parameters . Select ( p =>
144
+ p . ParameterType . FullName + " " + p . Name ) . ToArray ( ) )
145
+ ) ;
146
+
147
+ var entry = new LocEntry
148
+ {
149
+ Message = instruction . Previous . Operand as string ,
150
+ Description = $ "{ tm . t . Name } .{ tm . m . Name } "
151
+ } ;
152
+
153
+ var key = instruction . Previous . Previous . Operand as string ;
154
+
155
+ if ( string . IsNullOrEmpty ( key ) )
156
+ {
157
+ throw new Exception (
158
+ $ "Key was empty for message: { entry . Message } (from { entry . Description } )") ;
159
+ }
160
+
161
+ if ( outList . Any ( x => x . Key == key ) )
162
+ {
163
+ if ( outList . Any ( x => x . Key == key && x . Value . Message != entry . Message ) )
164
+ {
165
+ throw new Exception (
166
+ $ "Message with key { key } has previous appearance but other fallback text in { entry . Description } ") ;
167
+ }
168
+ }
169
+ else
170
+ {
171
+ debugOutput += $ " ->{ key } - { entry . Message } (from { entry . Description } )\n ";
172
+ outList . Add ( key , entry ) ;
173
+ }
174
+ }
175
+ }
176
+ }
177
+ }
178
+
179
+ File . WriteAllText ( "loc.log" , debugOutput ) ;
180
+ File . WriteAllText ( $ "{ GetAssemblyName ( assembly ) } _Localizable.json", JsonConvert . SerializeObject ( outList ,
181
+ new JsonSerializerSettings
182
+ {
183
+ Formatting = Formatting . Indented
184
+ } ) ) ;
185
+
186
+ return ;
187
+
188
+ /*
189
+ Old version, depended on Mono.Reflection/MethodBaseRocks
190
+
111
191
foreach (var type in types.Where(x => x.IsClass || x.IsAbstract))
112
192
{
113
193
var toParse = new List<MethodBase>();
@@ -117,7 +197,7 @@ public static void ExportLocalizableForAssembly(Assembly assembly)
117
197
foreach (var method in toParse)
118
198
try
119
199
{
120
- var instructions = MethodBodyReader . GetInstructions ( method ) ;
200
+ var instructions = method .GetInstructions();
121
201
122
202
foreach (var instruction in instructions)
123
203
if (instruction.OpCode == OpCodes.Call)
@@ -173,12 +253,7 @@ public static void ExportLocalizableForAssembly(Assembly assembly)
173
253
Debug.WriteLine($"Couldn't parse {method.Name}:\n{ex}");
174
254
}
175
255
}
176
-
177
- File . WriteAllText ( $ "{ GetAssemblyName ( assembly ) } _Localizable.json", JsonConvert . SerializeObject ( outList ,
178
- new JsonSerializerSettings
179
- {
180
- Formatting = Formatting . Indented
181
- } ) ) ;
256
+ */
182
257
}
183
258
184
259
/// <summary>
0 commit comments