|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionAn ASP.NET project I'm working on requires localization in different languages. It's nice to use .NET Resource files (.resx), because they are really integrated with the framework and you do not have to worry about explicitly managing the resources. Resource files are, though, really un-maintainable. When you edit the resource files in Visual Studio, ore use the "Generate Local Resources" function, it only updates the default language resources. For example, the file Default.aspx.resx, and not all the translated files, for example, Default.aspx.it-IT.resx. This is obviously a big problem, since you have to update them one by one, manually. RESX Synchronizer allows you to synchronize resource files, adding new keys and removing the deleted ones. It also processes a set of resource files, the "master" file, and all its translated "brothers". How it WorksThis tool uses the two classes We'll use the name of "source file" to indicate the "master" resource file, for example, Default.aspx.resx, and the name of "destination file" to indicate a "brother" resource file, for example, Default.aspx.it-IT.resx, which must be synchronized. The tool must perform two operations in order to get the files synchronized:
The core of the tool is the class public class Synchronizer {
string sourceFile, destinationFile;
public Synchronizer(string sFile, string dFile) {
sourceFile = sFile;
destinationFile = dFile;
}
public void SyncronizeResources(bool backup,
bool addOnly, bool verbose,
out int added,out int removed) {
added = 0;
removed = 0;
if(backup) {
string destDir = Path.GetDirectoryName(destinationFile);
string file = Path.GetFileName(destinationFile);
File.Copy(destinationFile, destDir +
"\\Backup of " + file, true);
}
string tempFile = Path.GetDirectoryName(destinationFile) +
"\\__TempOutput.resx";
// Load files in memory
MemoryStream sourceStream = new MemoryStream(),
destinationStream = new MemoryStream();
FileStream fs;
int read;
byte[] buffer = new byte[1024];
fs = new FileStream(sourceFile, FileMode.Open,
FileAccess.Read, FileShare.Read);
read = 0;
do {
read = fs.Read(buffer, 0, buffer.Length);
sourceStream.Write(buffer, 0, read);
} while(read > 0);
fs.Close();
fs = new FileStream(destinationFile, FileMode.Open,
FileAccess.Read, FileShare.Read);
read = 0;
do {
read = fs.Read(buffer, 0, buffer.Length);
destinationStream.Write(buffer, 0, read);
} while(read > 0);
fs.Close();
sourceStream.Position = 0;
destinationStream.Position = 0;
// Create resource readers
ResXResourceReader source = new ResXResourceReader(sourceStream);
// Enable support for Data Nodes, important for the comments
source.UseResXDataNodes = true;
ResXResourceReader destination =
new ResXResourceReader(destinationStream);
destination.UseResXDataNodes = true;
// Create resource writer
if(File.Exists(tempFile)) File.Delete(tempFile);
ResXResourceWriter writer = new ResXResourceWriter(tempFile);
// Compare source and destination:
// for each key in source, check if it is present in destination
// if not, add to the output
// for each key in destination, check if it is present in source
// if so, add it to the output
// Find new keys and add them to the output
foreach(DictionaryEntry d in source) {
bool found = false;
foreach(DictionaryEntry dd in destination) {
if(d.Key.ToString().Equals(dd.Key.ToString())) {
// Found key
found = true;
break;
}
}
if(!found) {
// Add the key
ResXDataNode node = d.Value as ResXDataNode;
writer.AddResource(node);
added++;
if(verbose) {
Console.WriteLine("Added new key '" + d.Key.ToString() +
"' with value '" +
d.Value.ToString() + "'\n");
}
}
}
if(addOnly) {
foreach(DictionaryEntry d in destination) {
ResXDataNode node = d.Value as ResXDataNode;
writer.AddResource(node);
}
}
else {
int tot = 0;
int rem = 0;
// Find un-deleted keys and add them to the output
foreach(DictionaryEntry d in destination) {
bool found = false;
tot++;
foreach(DictionaryEntry dd in source) {
if(d.Key.ToString().Equals(dd.Key.ToString())) {
// Found key
found = true;
}
}
if(found) {
// Add the key
ResXDataNode node = d.Value as ResXDataNode;
writer.AddResource(node);
rem++;
}
else if(verbose) {
Console.WriteLine("Removed deleted key '" +
d.Key.ToString() +
"' with value '" +
d.Value.ToString() + "'\n");
}
}
removed = tot - rem;
}
source.Close();
destination.Close();
writer.Close();
// Copy tempFile into destinationFile
File.Copy(tempFile, destinationFile, true);
File.Delete(tempFile);
}
}
The two operations described above are implemented in the two The
The Command-Line ToolThe Usage of the Command-Line ToolSince the tool is still in a development stage, I don't want to report here the usage instructions which might be obsolete in a few days, so I point you to the official page of the tool, available at this address. History
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||