Polyglot teams that share a backend service with a Windows or .NET desktop client frequently end up with the same user-facing strings duplicated in two formats: Java .properties on the JVM side, .resx on the .NET side. Properties files are flat ASCII (or ISO-8859-1, historically) with key=value lines, optional key:value separators, and # or ! comments. RESX is XML with <data name="…" xml:space="preserve"> elements, a fixed resmimetype and version resheader at the top, and Unicode-aware encoding. The dialects look unrelated until you have to keep both files in sync by hand and discover that every escape rule differs.
i18n-convert parses the Properties file, accepts both = and : as key-value separators (per the JDK spec), trims significant whitespace correctly, and emits a well-formed RESX document with the required resmimetype and version resheaders. Each Properties entry becomes a <data name="…" xml:space="preserve"><value>…</value></data> block, and any consecutive # or ! comment lines preceding an entry are merged into a <comment> sibling that .NET tooling like Visual Studio's resource editor will display. Keys containing dots — a very common Java namespacing convention — are preserved verbatim because .resx permits them in the name attribute. Empty values produce a self-closing <value></value> rather than being dropped, so the key remains addressable from .NET code.
Command
i18n-convert simple.properties --to resx -o Resources.resx
Input
# Application messages
greeting = Hello, World!
farewell = Goodbye!
app.title=My Application
empty.value=
Output
<?xml version="1.0" encoding="utf-8"?>
<root>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<data name="greeting" xml:space="preserve">
<value>Hello, World!</value>
<comment>Application messages</comment>
</data>
<data name="farewell" xml:space="preserve">
<value>Goodbye!</value>
</data>
<data name="app.title" xml:space="preserve">
<value>My Application</value>
</data>
<data name="empty.value" xml:space="preserve">
<value></value>
</data>
</root>