Skip to content

Commit ca680a2

Browse files
committed
Switch to Mono.Cecil
1 parent 7cdd754 commit ca680a2

File tree

6 files changed

+118
-457
lines changed

6 files changed

+118
-457
lines changed

CheapLoc.Test/TestForm.Designer.cs

Lines changed: 20 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CheapLoc.Test/TestForm.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,10 @@ private void Button1_Click(object sender, EventArgs e)
2727
{
2828
MessageBox.Show(Loc.Localize("MsgBoxText", "A box! Nice!"));
2929
}
30+
31+
private void button2_Click(object sender, EventArgs e)
32+
{
33+
Loc.ExportLocalizable();
34+
}
3035
}
3136
}

CheapLoc.Test/de_DE.json

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
{
2-
3-
"1": {
4-
"Key": "LabelTest",
5-
"Message": "Das hier ist ein Test-Label!"
2+
"LabelTest": {
3+
"message": "Hier ist ein Label.",
4+
"description": "TestForm..ctor"
65
},
7-
"2": {
8-
"Key": "ButtonTest",
9-
"Message": "Du hast"
6+
"ButtonTest": {
7+
"message": "Klick mich!",
8+
"description": "TestForm..ctor"
109
},
11-
"3": {
12-
"Key": "MsgBoxText",
13-
"Message": "Eine Box! Knorke."
10+
"MsgBoxText": {
11+
"message": "Eine Box! Super!",
12+
"description": "TestForm.Button1_Click"
1413
}
1514
}

CheapLoc/CheapLoc.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
<DocumentationFile>bin\Release\CheapLoc.xml</DocumentationFile>
3434
</PropertyGroup>
3535
<ItemGroup>
36+
<PackageReference Include="Mono.Cecil" Version="0.11.3" />
3637
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
3738
</ItemGroup>
3839
</Project>

CheapLoc/Loc.cs

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
using System.Reflection;
77
using System.Reflection.Emit;
88
using System.Runtime.CompilerServices;
9-
using Mono.Reflection;
9+
using Mono.Cecil;
1010
using Newtonsoft.Json;
11+
using OpCodes = Mono.Cecil.Cil.OpCodes;
1112

1213
namespace CheapLoc
1314
{
@@ -106,8 +107,87 @@ public static void ExportLocalizableForAssembly(Assembly assembly)
106107
{
107108
var types = assembly.GetTypes();
108109

110+
var debugOutput = string.Empty;
109111
var outList = new Dictionary<string, LocEntry>();
110112

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+
111191
foreach (var type in types.Where(x => x.IsClass || x.IsAbstract))
112192
{
113193
var toParse = new List<MethodBase>();
@@ -117,7 +197,7 @@ public static void ExportLocalizableForAssembly(Assembly assembly)
117197
foreach (var method in toParse)
118198
try
119199
{
120-
var instructions = MethodBodyReader.GetInstructions(method);
200+
var instructions = method.GetInstructions();
121201
122202
foreach (var instruction in instructions)
123203
if (instruction.OpCode == OpCodes.Call)
@@ -173,12 +253,7 @@ public static void ExportLocalizableForAssembly(Assembly assembly)
173253
Debug.WriteLine($"Couldn't parse {method.Name}:\n{ex}");
174254
}
175255
}
176-
177-
File.WriteAllText($"{GetAssemblyName(assembly)}_Localizable.json", JsonConvert.SerializeObject(outList,
178-
new JsonSerializerSettings
179-
{
180-
Formatting = Formatting.Indented
181-
}));
256+
*/
182257
}
183258

184259
/// <summary>

0 commit comments

Comments
 (0)