Cross-platform Localization - c#

With Xamarin Android, it possible to create localized strings for multi-language apps, as is shown in their Android documentation:
http://docs.xamarin.com/guides/android/application_fundamentals/resources_in_android/part_5_-_application_localization_and_string_resources
However, I have various try/catch blocks in my Model which send error messages back as strings. Ideally I'd like to keep the Model and Controller parts of my solution entirely cross platform but I can't see any way to effectively localize the messages without passing a very platform specific Android Context to the Model.
Does anyone have ideas about how this can be achieved?

I'm using .net resource files instead of the Android ones. They give me access to the strings from code, wherever it is.
The only thing I can't do automatically is reference those strings from layouts. To deal with that I've written a quick utility which parses the resx file and creates an Android resource file with the same values. It gets run before the Android project builds so all the strings are in place when it does.
Disclaimer: I haven't actually tested this with multiple languages yet.
This is the code for the utility:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace StringThing
{
class Program
{
static void Main(string[] args)
{
string sourceFile = args[0];
string targetFile = args[1];
Dictionary<string, string> strings = LoadDotNetStrings(sourceFile);
WriteToTarget(targetFile, strings);
}
static Dictionary<string, string> LoadDotNetStrings(string file)
{
var result = new Dictionary<string, string>();
XmlDocument doc = new XmlDocument();
doc.Load(file);
XmlNodeList nodes = doc.SelectNodes("//data");
foreach (XmlNode node in nodes)
{
string name = node.Attributes["name"].Value;
string value = node.ChildNodes[1].InnerText;
result.Add(name, value);
}
return result;
}
static void WriteToTarget(string targetFile, Dictionary<string, string> strings)
{
StringBuilder bob = new StringBuilder();
bob.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
bob.AppendLine("<resources>");
foreach (string key in strings.Keys)
{
bob.Append(" ");
bob.AppendLine(string.Format("<string name=\"{0}\">{1}</string>", key, strings[key]));
}
bob.AppendLine("</resources>");
System.IO.File.WriteAllText(targetFile, bob.ToString());
}
}
}

For Xamarin, you can also look at Vernacular https://github.com/rdio/vernacular
You can write code with minimal effort without worrying about the translation. Feed the generated IL to Vernacular to get translatable strings in iOS, Andorid, Windows Phone formats.

I've created a slightly ugly solution at Xamarin iOS localization using .NET which you might find helpful.

Related

How do I solve: The type or namespace Windows does not exist in namespace Microsoft?

How do I solve this missing dependency? Googling around for this problem, it seems rare. I see similar ones like The type or namespace name 'Windows' does not exist in the namespace 'System' but nowhere do I see someone explain this particular message.
Log files naturally recorded by windows at locations such as C:\Windows\System32\WDI\LogFiles\BootPerfDiagLogger.etl record useful forensic security info, such as every process that ran persistently at boot.
My goal is to parse these files into some intermediary structure like XML or JSON so I can import the data to Python.
I wanted to parse Windows ETL files in Python for forensic / security data science. I thought this would be easy since there's a Python library for it but upon running that library, it doesn't work and is probably no longer maintained.
Luckily I found a Microsoft dev blog on parsing ETL files with the same classes Windows exposes to allow Windows Performance Analyzer to do it.
The example code shown was like:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Windows.EventTracing;
using Microsoft.Windows.EventTracing.Disk;
using Microsoft.Windows.EventTracing.Processes;
class FileOperation
{
public IProcess IssuingProcess;
public string Operation;
public string Path;
public long Size;
public decimal Duration;
}
class Program
{
public static void Main(string[] args)
{
var etlFileName = args[0];
var diskTrace = Path.GetFileNameWithoutExtension(etlFileName) + "-disk.csv";
var fileTrace = Path.GetFileNameWithoutExtension(etlFileName) + "-file.csv";
using (ITraceProcessor trace = TraceProcessor.Create(etlFileName))
{
var pendingDisk = trace.UseDiskIOData();
var pendingFile = trace.UseFileIOData();
trace.Process();
ProcessDisk(pendingDisk.Result, diskTrace);
ProcessFile(pendingFile.Result, fileTrace);
}
}
I won't include the ProcessDisk and ProcessFile classes here because those seem to be geared toward whatever debugging purpose the writer had. Rather, I'm interested in trace. Based on the methods I see called: UseDiskIOData, UseFileIOData, presumably there is a longer list of methods like that I could use to access all available data for each trace.
My immediate goal with this question is just to view what methods exist on the trace object.
So I did some research on how you look at all properties on an object in C#, and there are plenty of answers, that's probably not a problem:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.Windows.EventTracing;
using Microsoft.Windows.EventTracing.Disk;
using Microsoft.Windows.EventTracing.Processes;
class Program
{
public static void Main(string[] args)
{
var etlFileName = args[0];
#var diskTrace = Path.GetFileNameWithoutExtension(etlFileName) + "-disk.csv";
#var fileTrace = Path.GetFileNameWithoutExtension(etlFileName) + "-file.csv";
using (ITraceProcessor trace = TraceProcessor.Create(etlFileName))
{
Type myType = trace.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
foreach (PropertyInfo prop in props)
{
object propValue = prop.GetValue(trace, null);
// Do something with propValue
Console.WriteLine(propValue);
}
#var pendingDisk = trace.UseDiskIOData();
#var pendingFile = trace.UseFileIOData();
#trace.Process();
#ProcessDisk(pendingDisk.Result, diskTrace);
#ProcessFile(pendingFile.Result, fileTrace);
}
}
But what I did have a problem with is this:
The type or namespace Windows does not exist in namespace Microsoft
As I said, I looked around for solutions to this and found nothing.

JSON deserialization into List<string>

I guess this is easy, but I am new and cannot find a fast answer to this:
I want to obtain a list of file names (List<string>) in a .Net 2.0 desktop app, using WebClient requesting to a WebAPI REST service.
So, I have this code in the desktop app:
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.Accept] = "application/json";
var resultString = client.DownloadString("http://localhost:3788/api/file?src=X&dest=Y");
}
and a WebAPI action like this in the service:
public IEnumerable<string> GetFiles([FromUri]string src, [FromUri]string dest)
{
// some code here
}
How would I convert the resultString, which is a JSON String, to a List<String> ?
Do I have to use JsonDataContractSerializer?
Look at this SO question and answer. The code there outlines what you would do. The key is to reference the Newtonsoft.Json namespace (add it from a NuGet package) and use the DeserializeObject generic method. The answer shows other things you can do with results.

How would one simulate proxy functions without the HttpListener or TCPListener components in C#?

How can I simulate the functions/actions of a proxy server but without calling elements like HttpListener or TcpListener? How can I generate them from within my C# application?
I've been able to get as far as getting actual data streamed back to my WebBrowser element in my C# application but upon viewing the results, it gives me errors. The reason being is because I'm viewing the LITERAL string and there are JS/CSS components within the resulting HTML stream that makes references to objects via relative URIs. Obviously, my solution thinks they're local and, as such, can't resolve them.
I'm missing proxy-like functions where it should just hand off the stream back to my mock browser and display properly. However, looking at sample proxy server codes built on C#, they're all built as servers using listeners. I'd like it to be something that I can instantiate locally without the need to create a listening interface.
Now, you may be wondering why I'm trying to do this? Well, there are a couple of reasons:
To be able to inject headers ad-hoc so I can test internal web servers
To run as a headless (no GUI) component that can take either HTTP or HTTPS streams from other .NET components and inject headers from, yet, other .NET components.
Some other back-end stuff that I think might but won't know until I have this in place.
Here's what I have so far:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using HtmlAgilityPack;
using System.Net;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
WebClient client = new WebClient();
var baseUrl = new Uri(textBox1.Text);
client.Headers.Add("Token1", textBox2.Text);
client.Headers.Add("Token2",textBox3.Text);
byte[] requestHTML = client.DownloadData(textBox1.Text);
string sourceHTML = new UTF8Encoding().GetString(requestHTML);
HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();
htmlDoc.LoadHtml(sourceHTML);
//"//*[#background or #lowsrc or #src or #href]"
foreach (HtmlNode link in htmlDoc.DocumentNode.SelectNodes("//*[#href]"))
{
//Console.Out.WriteLine(link.ToString());
if (!string.IsNullOrEmpty(link.Attributes["href"].Value))
{
HtmlAttribute att = link.Attributes["href"];
Console.WriteLine("Before: " + att.Value);
//Console.Out.WriteLine(att.Value.ToString());
Console.WriteLine(new Uri(baseUrl, att.Value));
link.Attributes["href"].Value = new Uri(baseUrl, att.Value).ToString();
Console.WriteLine("After: " + link.Attributes["href"].Value);
//att.Value = this.AbsoluteUrlByRelative(att.Value);
}
}
foreach (HtmlNode link2 in htmlDoc.DocumentNode.SelectNodes("//*[#src]"))
{
//Console.Out.WriteLine(link.ToString());
if (!string.IsNullOrEmpty(link2.Attributes["src"].Value))
{
HtmlAttribute att = link2.Attributes["src"];
Console.WriteLine("Before: " + att.Value);
// //Console.Out.WriteLine(att.Value.ToString());
Console.WriteLine(new Uri(baseUrl, att.Value));
if (!att.Value.Contains("/WS"))
{
Console.WriteLine("HIT ME!");
var output = "/WS/" + att.Value;
link2.Attributes["src"].Value = new Uri(baseUrl, output).ToString();
Console.WriteLine("After HIT: " + link2.Attributes["src"].Value);
}
else
{
link2.Attributes["src"].Value = new Uri(baseUrl, att.Value).ToString();
Console.WriteLine("After: " + link2.Attributes["src"].Value);
}
// //att.Value = this.AbsoluteUrlByRelative(att.Value);
}
}
Console.WriteLine(htmlDoc.DocumentNode.OuterHtml);
Console.WriteLine("+========================+");
webBrowser1.DocumentText = htmlDoc.DocumentNode.OuterHtml;
}
}
}
Again, this is just prototyped code so forgive the wacky spacing and commenting. In the end, it will be more formal. Right now, this monkey is killing my back.
How about using something like NMock or similar? It would mean having to introduce interfaces so that the mocks can be injected, but still beats doing it almost any other way, IMHO...
From the NMock site:
NMock is a dynamic mock object library for .NET. Mock objects make it
easier to test single components—often single classes—without relying
on real implementations of all of the other components. This means we
can test just one class, rather than a whole tree of objects, and can
pinpoint bugs much more clearly. Mock objects are often used during
Test Driven Development.
You would mock the proxy server more or less like this:
var mocks = new Mockery();
var mockProxyServer = mocks.NewMock<IMyProxyServer>();
That's all you need to do. As you can see, it's interface-dependent. But usually all that I've needed to do is Refactor->Extract Interfaces from the relevant class in VS.
Setting up the simulation is usually done within the context of the unit test, like:
public class TransferFundsPresenterTest
{
private Mockery mocks;
private IMyProxyServer mockProxyServer
[SetUp]
public void SetUp()
{
mocks = new Mockery();
mockProxyServer = mocks.NewMock<IMyProxyServer>();
}
[Test]
public void TestProxyFunction()
{
Expect.Once.On(mockProxyServer).
Method("ProxyFunctionA").
With("1234"). // <-- simulate the input params here
Will(Return.Value("Test")); // <-- simulate the output from server here
}
This is just a basic example. You can do a lot more, it's a very flexible library.
You really should take a look at the NMock site, it's pretty easy to get fully up to speed with the library.
http://www.nmock.org/index.html

Tool for parsing querystrings, creating URL encoded params etc?

before writing my own :-)
I was wondering if anyone knows a tool to parse a URL and extract all the params into a easier viewable format, a grid maybe? (these urls are extremely long :- )
And also if it allows you to construct the querystring for standard text and automates the URL ENCODING etc.
Must be one available, i have searched high and low and can't find anything.
Thanks in advance
The ParseQueryString method is pretty handy for those tasks.
I was wondering if anyone knows a tool to parse a URL and extract all
the params into a easier viewable format, a grid maybe? (these urls
are extremely long :- )
using System;
using System.Web;
class Program
{
static void Main()
{
var uri = new Uri("http://foo.com/?param1=value1&param2=value2");
var values = HttpUtility.ParseQueryString(uri.Query);
foreach (string key in values.Keys)
{
Console.WriteLine("key: {0}, value: {1}", key, values[key]);
}
}
}
And also if it allows you to construct the querystring for standard
text and automates the URL ENCODING etc.
using System;
using System.Web;
class Program
{
static void Main()
{
var values = HttpUtility.ParseQueryString(string.Empty);
values["param1"] = "value1";
values["param2"] = "value2";
var builder = new UriBuilder("http://foo.com");
builder.Query = values.ToString();
var url = builder.ToString();
Console.WriteLine(url);
}
}

Is it possible to serialize a C# code block?

I'm using C# with .NET 3.5. Is it possible to serialize a block of code, transmit it somewhere, deserialize it, and then execute it?
An example usage of this would be:
Action<object> pauxPublish = delegate(object o)
{
if (!(o is string))
{
return;
}
Console.WriteLine(o.ToString());
};
Transmitter.Send(pauxPublish);
With some remote program doing:
var action = Transmitter.Recieve();
action("hello world");
My end goal is to be able to execute arbitrary code in a different process (which has no prior knowledge of the code).
YES!!!
We have done this for a very real case of performance. Doing this at runtime or using a DSL was not an option due to performance.
We compile the code into an assembly, and rip the IL out of the method. We then get all the metadata associated with this method and serialize the whole mess via XML, compress it, and put it in our database.
At re-hydration time, we re-constitute the IL with the metadata using the DynamicMethod class, and execute it.
We do this because of speed. We have thousands of little blocks of code. Unfortunately, to compile a block of code and run it on the fly takes at least 250 ms, which is way too slow for us. We took this approach, and it is working REALLY well. At run-time, it takes an unmeasurable amount of time to reconstitute the method and run it.
Only thing to keep an eye on... Signed assemblies and Unsigned assemblies cannot mix the serialized method data.
You could try to use IronPython in your project. It's trivial to do what you are asking in Python. The Python code could call your C# methods. As for security, you could execute the code in a restricted environment of some kind (one example is RestrictedPython).
Generally speaking that sounds like a really bad idea and a big security hole.
You don't want another process to execute any code. Understand what you really need another process to do and build a little DSL around it.
You could also send it as a string then use the CodeDomProvider to compile it, same result. I have an example bit of code thus:
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.CSharp;
namespace DynamicCodeApplication
{
class azCodeCompiler
{
private List<string> assemblies;
public azCodeCompiler()
{
assemblies = new List<string>();
scanAndCacheAssemblies();
}
public Assembly BuildAssembly(string code)
{
CodeDomProvider prov = CodeDomProvider.CreateProvider("CSharp");
string[] references = new string[] { }; // Intentionally empty, using csc.rsp
CompilerParameters cp = new CompilerParameters(references)
{
GenerateExecutable = false,
GenerateInMemory = true
};
string path = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
cp.CompilerOptions = "#" + path + #"\csc.rsp";
CompilerResults cr = prov.CompileAssemblyFromSource(cp, code);
foreach (CompilerError err in cr.Errors)
{
Console.WriteLine(err.ToString());
}
return cr.CompiledAssembly;
}
public object ExecuteCode(string code,
string namespacename, string classname,
string functionname, bool isstatic, params object[] args)
{
object returnval = null;
Assembly asm = BuildAssembly(code);
object instance = null;
Type type = null;
if (isstatic)
{
type = asm.GetType(namespacename + "." + classname);
}
else
{
instance = asm.CreateInstance(namespacename + "." + classname);
type = instance.GetType();
}
MethodInfo method = type.GetMethod(functionname);
returnval = method.Invoke(instance, args);
return returnval;
}
private void scanAndCacheAssemblies()
{
/*
foreach (string str in Directory.GetFiles(#"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727"))
{
if (str.Contains(".dll"))
{
foreach (string st in str.Split(new char[] { '\\' }))
{
if (st.Contains(".dll"))
{
assemblies.Add(st);
}
}
}
}
* */
assemblies.Add("Accessibility.dll");
assemblies.Add("AspNetMMCExt.dll");
assemblies.Add("cscompmgd.dll");
assemblies.Add("CustomMarshalers.dll");
assemblies.Add("IEExecRemote.dll");
assemblies.Add("IEHost.dll");
assemblies.Add("IIEHost.dll");
assemblies.Add("Microsoft.Build.Conversion.dll");
assemblies.Add("Microsoft.Build.Engine.dll");
assemblies.Add("Microsoft.Build.Framework.dll");
assemblies.Add("Microsoft.Build.Tasks.dll");
assemblies.Add("Microsoft.Build.Utilities.dll");
assemblies.Add("Microsoft.Build.VisualJSharp.dll");
assemblies.Add("Microsoft.CompactFramework.Build.Tasks.dll");
assemblies.Add("Microsoft.JScript.dll");
assemblies.Add("Microsoft.VisualBasic.Compatibility.Data.dll");
assemblies.Add("Microsoft.VisualBasic.Compatibility.dll");
assemblies.Add("Microsoft.VisualBasic.dll");
assemblies.Add("Microsoft.VisualBasic.Vsa.dll");
assemblies.Add("Microsoft.Vsa.dll");
assemblies.Add("Microsoft.Vsa.Vb.CodeDOMProcessor.dll");
assemblies.Add("Microsoft_VsaVb.dll");
assemblies.Add("mscorlib.dll");
assemblies.Add("sysglobl.dll");
assemblies.Add("System.configuration.dll");
assemblies.Add("System.Configuration.Install.dll");
assemblies.Add("System.Data.dll");
assemblies.Add("System.Data.OracleClient.dll");
assemblies.Add("System.Data.SqlXml.dll");
assemblies.Add("System.Deployment.dll");
assemblies.Add("System.Design.dll");
assemblies.Add("System.DirectoryServices.dll");
assemblies.Add("System.DirectoryServices.Protocols.dll");
assemblies.Add("System.dll");
assemblies.Add("System.Drawing.Design.dll");
assemblies.Add("System.Drawing.dll");
assemblies.Add("System.EnterpriseServices.dll");
assemblies.Add("System.Management.dll");
assemblies.Add("System.Messaging.dll");
assemblies.Add("System.Runtime.Remoting.dll");
assemblies.Add("System.Runtime.Serialization.Formatters.Soap.dll");
assemblies.Add("System.Security.dll");
assemblies.Add("System.ServiceProcess.dll");
assemblies.Add("System.Transactions.dll");
assemblies.Add("System.Web.dll");
assemblies.Add("System.Web.Mobile.dll");
assemblies.Add("System.Web.RegularExpressions.dll");
assemblies.Add("System.Web.Services.dll");
assemblies.Add("System.Windows.Forms.dll");
assemblies.Add("System.XML.dll");
assemblies.Add("vjscor.dll");
assemblies.Add("vjsjbc.dll");
assemblies.Add("vjslib.dll");
assemblies.Add("vjslibcw.dll");
assemblies.Add("vjssupuilib.dll");
assemblies.Add("vjsvwaux.dll");
assemblies.Add("vjswfc.dll");
assemblies.Add("VJSWfcBrowserStubLib.dll");
assemblies.Add("vjswfccw.dll");
assemblies.Add("vjswfchtml.dll");
assemblies.Add("Accessibility.dll");
assemblies.Add("AspNetMMCExt.dll");
assemblies.Add("cscompmgd.dll");
assemblies.Add("CustomMarshalers.dll");
assemblies.Add("IEExecRemote.dll");
assemblies.Add("IEHost.dll");
assemblies.Add("IIEHost.dll");
assemblies.Add("Microsoft.Build.Conversion.dll");
assemblies.Add("Microsoft.Build.Engine.dll");
assemblies.Add("Microsoft.Build.Framework.dll");
assemblies.Add("Microsoft.Build.Tasks.dll");
assemblies.Add("Microsoft.Build.Utilities.dll");
assemblies.Add("Microsoft.Build.VisualJSharp.dll");
assemblies.Add("Microsoft.CompactFramework.Build.Tasks.dll");
assemblies.Add("Microsoft.JScript.dll");
assemblies.Add("Microsoft.VisualBasic.Compatibility.Data.dll");
assemblies.Add("Microsoft.VisualBasic.Compatibility.dll");
assemblies.Add("Microsoft.VisualBasic.dll");
assemblies.Add("Microsoft.VisualBasic.Vsa.dll");
assemblies.Add("Microsoft.Vsa.dll");
assemblies.Add("Microsoft.Vsa.Vb.CodeDOMProcessor.dll");
assemblies.Add("Microsoft_VsaVb.dll");
assemblies.Add("mscorlib.dll");
assemblies.Add("sysglobl.dll");
assemblies.Add("System.configuration.dll");
assemblies.Add("System.Configuration.Install.dll");
assemblies.Add("System.Data.dll");
assemblies.Add("System.Data.OracleClient.dll");
assemblies.Add("System.Data.SqlXml.dll");
assemblies.Add("System.Deployment.dll");
assemblies.Add("System.Design.dll");
assemblies.Add("System.DirectoryServices.dll");
assemblies.Add("System.DirectoryServices.Protocols.dll");
assemblies.Add("System.dll");
assemblies.Add("System.Drawing.Design.dll");
assemblies.Add("System.Drawing.dll");
assemblies.Add("System.EnterpriseServices.dll");
assemblies.Add("System.Management.dll");
assemblies.Add("System.Messaging.dll");
assemblies.Add("System.Runtime.Remoting.dll");
assemblies.Add("System.Runtime.Serialization.Formatters.Soap.dll");
assemblies.Add("System.Security.dll");
assemblies.Add("System.ServiceProcess.dll");
assemblies.Add("System.Transactions.dll");
assemblies.Add("System.Web.dll");
assemblies.Add("System.Web.Mobile.dll");
assemblies.Add("System.Web.RegularExpressions.dll");
assemblies.Add("System.Web.Services.dll");
assemblies.Add("System.Windows.Forms.dll");
assemblies.Add("System.XML.dll");
assemblies.Add("vjscor.dll");
assemblies.Add("vjsjbc.dll");
assemblies.Add("vjslib.dll");
assemblies.Add("vjslibcw.dll");
assemblies.Add("vjssupuilib.dll");
assemblies.Add("vjsvwaux.dll");
assemblies.Add("vjswfc.dll");
assemblies.Add("VJSWfcBrowserStubLib.dll");
assemblies.Add("vjswfccw.dll");
assemblies.Add("vjswfchtml.dll");
return;
}
}
}
Compile it into a separate assembly, send the assembly, have the other process load it.
You might want to consider security implications.
Update: another idea would be to generate an expression tree and use this library to serialize it:
http://www.codeplex.com/metalinq/
It is an interesting challenge, but you should probably describe why you want to do this, since there is a lot of different approaches depending on your objective. As humpohl points out, there is also some pretty serious security issues.
"Serialized code" could just be source code or a compiled assembly, depending on your requirements. You probably don't need to use a seperate code serialization format.
If you want to generate code dynamically and pass that on, you could generate code using CodeDOM and compile it. However, you most likely dont need to generate completely arbitrary code.
Another option is using the DLR, and constraining the code to execute...

Categories