static void Main(string[] args) { if (args.Length == 0 || args.Length == 1 && (args[0] == "-help" || args[0] == "-?")) { printHelp(); } var options = getOptions(args); checkOptions(options); ConverterLogger logger = ResxToJsonConverter.Convert(options); foreach (var item in logger.Log) { ConsoleColor color; switch (item.Severity) { case Severity.Trace: color = ConsoleColor.DarkGray; break; case Severity.Info: color = ConsoleColor.White; break; case Severity.Warning: color = ConsoleColor.Yellow; break; case Severity.Error: color = ConsoleColor.DarkRed; break; default: throw new ArgumentOutOfRangeException(); } var backupColor = Console.ForegroundColor; Console.ForegroundColor = color; Console.WriteLine(item.Message); Console.ForegroundColor = backupColor; } #if DEBUG Console.ReadLine(); #endif }
private static void writeOutput(string outputPath, string jsonText, ResxToJsonConverterOptions options, ConverterLogger logger) { Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); if (File.Exists(outputPath)) { var attrs = File.GetAttributes(outputPath); if ((attrs & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) { if (options.Overwrite == OverwriteModes.Skip) { logger.AddMsg(Severity.Error, "Cannot overwrite {0} file, skipping", outputPath); return; } // remove read-only attribute attrs = ~FileAttributes.ReadOnly & attrs; File.SetAttributes(outputPath, attrs); } // if existing file isn't readonly we just overwrite it } File.WriteAllText(outputPath, jsonText, Encoding.UTF8); logger.AddMsg(Severity.Info, "Created {0} file", outputPath); }
/// <summary> /// Get resources from set of resx files. /// Resources are groupped in bundles for each set of resx-files with same base name (like messages.resx, messages.en.resx, message.ru.resx) /// </summary> public static IDictionary<string, ResourceBundle> GetResources(IList<string> inputFiles, ConverterLogger logger) { var fileBundles = new Dictionary<string, ResourceFileBundle>(); foreach (var filePath in inputFiles) { string fileName = Path.GetFileName(filePath); string fileNameWithoutExt = Path.GetFileNameWithoutExtension(fileName); bool isBaseFile; int idx = fileNameWithoutExt.IndexOf(".", StringComparison.InvariantCulture); // All files with the same base name form a bundle string baseName = fileNameWithoutExt; CultureInfo culture = null; ResourceFileBundle bundle; if (idx == -1) { isBaseFile = true; } else { // file name contains "." - it can culture name or something else string suffix = fileNameWithoutExt.Substring(idx + 1); culture = getCulture(suffix); if (culture != null) { // the file is a culture-specific resource file isBaseFile = false; baseName = fileNameWithoutExt.Substring(0, idx); } else { isBaseFile = true; } } if (String.IsNullOrEmpty(baseName)) { throw new Exception("Could not extract baseName from the file name: '" + fileName + "'"); } if (!fileBundles.TryGetValue(baseName, out bundle)) { bundle = new ResourceFileBundle(); fileBundles[baseName] = bundle; } if (isBaseFile) { bundle.BaseName = baseName; bundle.BaseFile = filePath; } else { bundle.AddCultureFile(culture, filePath); } } var bundles = new Dictionary<string, ResourceBundle>(); // read values from resx files grouped in bundles foreach (ResourceFileBundle fileBundle in fileBundles.Values) { if (String.IsNullOrEmpty(fileBundle.BaseFile) || String.IsNullOrEmpty(fileBundle.BaseName)) { string locFiles = null; if (fileBundle.CultureFiles.Count > 0) { locFiles = string.Join(", ", fileBundle.CultureFiles.Select(p => p.Value)); } logger.AddMsg(Severity.Error, "Ignoring localized resources without base resx-file {0}", locFiles != null ? ": " + locFiles : ""); continue; } var bundle = new ResourceBundle(fileBundle.BaseName); bundle.AddResources(null, getKeyValuePairsFromResxFile(fileBundle.BaseFile)); foreach (KeyValuePair<CultureInfo, string> pair in fileBundle.CultureFiles) { var values = getKeyValuePairsFromResxFile(pair.Value); bundle.AddResources(pair.Key, values); } bundles[fileBundle.BaseName] = bundle; } return bundles; }
/// <summary> /// Get resources from resx files found in specified folders. /// Resources with groupped in bundles for each set of resx-files with same base name (like messages.resx, messages.en.resx, message.ru.resx) /// </summary> public static IDictionary<string, ResourceBundle> GetResources(ICollection<string> directories, bool recursive, ConverterLogger logger) { var files = new List<string>(); foreach (string directory in directories) { if (!Directory.Exists(directory)) { continue; } string[] resourceFiles = Directory.GetFiles(directory, "*.resx", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); files .AddRange(resourceFiles); } return GetResources(files, logger); }
public static ConverterLogger Convert(ResxToJsonConverterOptions options) { var logger = new ConverterLogger(); IDictionary <string, ResourceBundle> bundles = null; if (options.InputFiles.Count > 0) { bundles = ResxHelper.GetResources(options.InputFiles, logger); } if (options.InputFolders.Count > 0) { var bundles2 = ResxHelper.GetResources(options.InputFolders, options.Recursive, logger); if (bundles == null) { bundles = bundles2; } else { // join two bundles collection foreach (var pair in bundles2) { bundles[pair.Key] = pair.Value; } } } if (bundles == null || bundles.Count == 0) { logger.AddMsg(Severity.Warning, "No resx files were found"); return(logger); } logger.AddMsg(Severity.Trace, "Found {0} resx bundles", bundles.Count); if (bundles.Count > 1 && !String.IsNullOrEmpty(options.OutputFile)) { // join multiple resx resources into a single js-bundle var bundleMerge = new ResourceBundle(Path.GetFileNameWithoutExtension(options.OutputFile)); foreach (var pair in bundles) { bundleMerge.MergeWith(pair.Value); } logger.AddMsg(Severity.Trace, "As 'outputFile' option was specified all bundles were merged into single bundle '{0}'", bundleMerge.BaseName); bundles = new Dictionary <string, ResourceBundle> { { bundleMerge.BaseName, bundleMerge } }; } foreach (ResourceBundle bundle in bundles.Values) { JsonResources jsonResources = generateJsonResources(bundle, options); string baseFileName; string baseDir; if (!string.IsNullOrEmpty(options.OutputFile)) { baseFileName = Path.GetFileName(options.OutputFile); baseDir = Path.GetDirectoryName(options.OutputFile); } else { baseFileName = bundle.BaseName.ToLowerInvariant() + GetOutputFileExtension(options.OutputFormat); baseDir = options.OutputFolder; } if (string.IsNullOrEmpty(baseDir)) { baseDir = Environment.CurrentDirectory; } logger.AddMsg(Severity.Trace, "Processing '{0}' bundle (contains {1} resx files)", bundle.BaseName, bundle.Cultures.Count); string dirPath = options.OutputFormat == OutputFormat.i18next ? Path.Combine(baseDir, options.FallbackCulture) : baseDir; string outputPath = Path.Combine(dirPath, baseFileName); string jsonText = stringifyJson(jsonResources.BaseResources, options); writeOutput(outputPath, jsonText, options, logger); if (jsonResources.LocalizedResources.Count > 0) { foreach (KeyValuePair <string, JObject> pair in jsonResources.LocalizedResources) { dirPath = Path.Combine(baseDir, pair.Key); outputPath = Path.Combine(dirPath, baseFileName); jsonText = stringifyJson(pair.Value, options); writeOutput(outputPath, jsonText, options, logger); } } } return(logger); }
public static ConverterLogger Convert(ResxToJsonConverterOptions options) { var logger = new ConverterLogger(); IDictionary<string, ResourceBundle> bundles = null; if (options.InputFiles.Count > 0) { bundles = ResxHelper.GetResources(options.InputFiles, logger); } if (options.InputFolders.Count > 0) { var bundles2 = ResxHelper.GetResources(options.InputFolders, options.Recursive, logger); if (bundles == null ) { bundles = bundles2; } else { // join two bundles collection foreach (var pair in bundles2) { bundles[pair.Key] = pair.Value; } } } if (bundles == null || bundles.Count == 0) { logger.AddMsg(Severity.Warning, "No resx files were found"); return logger; } logger.AddMsg(Severity.Trace, "Found {0} resx bundles", bundles.Count); if (bundles.Count > 1 && !String.IsNullOrEmpty(options.OutputFile)) { // join multiple resx resources into a single js-bundle var bundleMerge = new ResourceBundle(Path.GetFileNameWithoutExtension(options.OutputFile)); foreach (var pair in bundles) { bundleMerge.MergeWith(pair.Value); } logger.AddMsg(Severity.Trace, "As 'outputFile' option was specified all bundles were merged into single bundle '{0}'", bundleMerge.BaseName); bundles = new Dictionary<string, ResourceBundle> {{bundleMerge.BaseName, bundleMerge}}; } foreach (ResourceBundle bundle in bundles.Values) { JsonResources jsonResources = generateJsonResources(bundle, options); string baseFileName; string baseDir; if (!string.IsNullOrEmpty(options.OutputFile)) { baseFileName = Path.GetFileName(options.OutputFile); baseDir = Path.GetDirectoryName(options.OutputFile); } else { baseFileName = bundle.BaseName.ToLowerInvariant() + GetOutputFileExtension(options.OutputFormat); baseDir = options.OutputFolder; } if (string.IsNullOrEmpty(baseDir)) { baseDir = Environment.CurrentDirectory; } logger.AddMsg(Severity.Trace, "Processing '{0}' bundle (contains {1} resx files)", bundle.BaseName, bundle.Cultures.Count); string dirPath = options.OutputFormat == OutputFormat.i18next ? Path.Combine(baseDir, options.FallbackCulture) : baseDir; string outputPath = Path.Combine(dirPath, baseFileName); string jsonText = stringifyJson(jsonResources.BaseResources, options); writeOutput(outputPath, jsonText, options, logger); if (jsonResources.LocalizedResources.Count > 0) { foreach (KeyValuePair<string, JObject> pair in jsonResources.LocalizedResources) { dirPath = Path.Combine(baseDir, pair.Key); outputPath = Path.Combine(dirPath, baseFileName); jsonText = stringifyJson(pair.Value, options); writeOutput(outputPath, jsonText, options, logger); } } } return logger; }
private static void writeOutput(string outputPath, string jsonText, ResxToJsonConverterOptions options, ConverterLogger logger) { Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); if (File.Exists(outputPath)) { var attrs = File.GetAttributes(outputPath); if ((attrs & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) { if (options.Overwrite == OverwriteModes.Skip) { logger.AddMsg(Severity.Error, "Cannot overwrite {0} file, skipping", outputPath); return; } // remove read-only attribute attrs = ~FileAttributes.ReadOnly & attrs; File.SetAttributes(outputPath, attrs); } // if existing file isn't readonly we just overwrite it } File.WriteAllText(outputPath, jsonText, Encoding.UTF8); logger.AddMsg(Severity.Info, "Created {0} file", outputPath); }
/// <summary> /// Get resources from set of resx files. /// Resources are groupped in bundles for each set of resx-files with same base name (like messages.resx, messages.en.resx, message.ru.resx) /// </summary> public static IDictionary <string, ResourceBundle> GetResources(IList <string> inputFiles, ConverterLogger logger) { var fileBundles = new Dictionary <string, ResourceFileBundle>(); foreach (var filePath in inputFiles) { string fileName = Path.GetFileName(filePath); string fileNameWithoutExt = Path.GetFileNameWithoutExtension(fileName); bool isBaseFile; int idx = fileNameWithoutExt.IndexOf(".", StringComparison.InvariantCulture); // All files with the same base name form a bundle string baseName = fileNameWithoutExt; CultureInfo culture = null; ResourceFileBundle bundle; if (idx == -1) { isBaseFile = true; } else { // file name contains "." - it can culture name or something else string suffix = fileNameWithoutExt.Substring(idx + 1); culture = getCulture(suffix); if (culture != null) { // the file is a culture-specific resource file isBaseFile = false; baseName = fileNameWithoutExt.Substring(0, idx); } else { isBaseFile = true; } } if (String.IsNullOrEmpty(baseName)) { throw new Exception("Could not extract baseName from the file name: '" + fileName + "'"); } if (!fileBundles.TryGetValue(baseName, out bundle)) { bundle = new ResourceFileBundle(); fileBundles[baseName] = bundle; } if (isBaseFile) { bundle.BaseName = baseName; bundle.BaseFile = filePath; } else { bundle.AddCultureFile(culture, filePath); } } var bundles = new Dictionary <string, ResourceBundle>(); // read values from resx files grouped in bundles foreach (ResourceFileBundle fileBundle in fileBundles.Values) { if (String.IsNullOrEmpty(fileBundle.BaseFile) || String.IsNullOrEmpty(fileBundle.BaseName)) { string locFiles = null; if (fileBundle.CultureFiles.Count > 0) { locFiles = string.Join(", ", fileBundle.CultureFiles.Select(p => p.Value)); } logger.AddMsg(Severity.Error, "Ignoring localized resources without base resx-file {0}", locFiles != null ? ": " + locFiles : ""); continue; } var bundle = new ResourceBundle(fileBundle.BaseName); bundle.AddResources(null, getKeyValuePairsFromResxFile(fileBundle.BaseFile)); foreach (KeyValuePair <CultureInfo, string> pair in fileBundle.CultureFiles) { var values = getKeyValuePairsFromResxFile(pair.Value); bundle.AddResources(pair.Key, values); } bundles[fileBundle.BaseName] = bundle; } return(bundles); }
/// <summary> /// Get resources from resx files found in specified folders. /// Resources with groupped in bundles for each set of resx-files with same base name (like messages.resx, messages.en.resx, message.ru.resx) /// </summary> public static IDictionary <string, ResourceBundle> GetResources(ICollection <string> directories, bool recursive, ConverterLogger logger) { var files = new List <string>(); foreach (string directory in directories) { if (!Directory.Exists(directory)) { continue; } string[] resourceFiles = Directory.GetFiles(directory, "*.resx", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); files.AddRange(resourceFiles); } return(GetResources(files, logger)); }