private static void OutputI18nTextJsonFiles(I18nTextCompilerOptions options, I18nTextSource i18textSrc, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (!i18textSrc.Types.Any()) { return; } if (!Directory.Exists(options.OutDirectory)) { Directory.CreateDirectory(options.OutDirectory); } var types = i18textSrc.Types .SelectMany(type => type.Value.Langs.Select(lang => (lang, jsonPath: Path.Combine(options.OutDirectory, options.NameSpace + "." + type.Key + "." + lang.Key + ".json")))) .ToArray(); // Sweep old generated/should be purge text json files. var existsTextJsonFiles = Directory.GetFiles(options.OutDirectory, "*.json"); var shouldBeSweepedFiles = existsTextJsonFiles.Except(types.Select(t => t.jsonPath)); foreach (var shouldBeSweepedFile in shouldBeSweepedFiles) { cancellationToken.ThrowIfCancellationRequested(); File.Delete(shouldBeSweepedFile); } Parallel.ForEach(types, new ParallelOptions { CancellationToken = cancellationToken }, ((KeyValuePair <string, I18nTextTable> lang, string jsonPath)arg) => { var textTable = new SortedDictionary <string, string>(arg.lang.Value); var jsonText = JsonConvert.SerializeObject(textTable, Formatting.Indented); cancellationToken.ThrowIfCancellationRequested(); var skipOutput = false; if (File.Exists(arg.jsonPath)) { var prevJsonText = File.ReadAllText(arg.jsonPath); cancellationToken.ThrowIfCancellationRequested(); skipOutput = prevJsonText == jsonText; } if (!skipOutput) { File.WriteAllText(arg.jsonPath, jsonText); } });
private static I18nTextSource ParseSourceFiles(IEnumerable <I18nTextSourceFile> srcFiles, I18nTextCompilerOptions options) { var i18textSrc = new I18nTextSource(); if (!srcFiles.Any()) { return(i18textSrc); } Parallel.ForEach(srcFiles, srcFile => { var fnameParts = Path.GetFileNameWithoutExtension(srcFile.Path).Split('.'); var typeName = string.Join(".", fnameParts.Take(fnameParts.Length - 1)); var langCode = fnameParts.Last(); var srcText = File.ReadAllText(srcFile.Path, srcFile.Encoding); var textTable = DeserializeSrcText(srcText, Path.GetExtension(srcFile.Path).ToLower()); var type = i18textSrc.Types.GetOrAdd(typeName, new I18nTextType()); type.Langs[langCode] = textTable; }); Parallel.ForEach(i18textSrc.Types.Values, type => { type.TextKeys = type.Langs .SelectMany(lang => lang.Value) .Select(tt => tt.Key) .OrderBy(key => key) .Distinct() .ToList(); Parallel.ForEach(type.Langs, lang => { var textTable = lang.Value; foreach (var textKey in type.TextKeys.Where(k => !textTable.ContainsKey(k))) { var text = type.Langs.Keys .OrderBy(langCode => langCode.StartsWith("en") ? "0" : langCode) .Select(langCode => type.Langs[langCode].TryGetValue(textKey, out var t) ? t : null) .FirstOrDefault(t => t != null); textTable[textKey] = text ?? textKey; } }); });
private static I18nTextSource ParseSourceFiles(IEnumerable <I18nTextSourceFile> srcFiles, I18nTextCompilerOptions options) { var i18textSrc = new I18nTextSource(); if (!srcFiles.Any()) { return(i18textSrc); } var i18nSrcDir = options.I18nTextSourceDirectory; if (!i18nSrcDir.EndsWith(Path.DirectorySeparatorChar.ToString())) { i18nSrcDir += Path.DirectorySeparatorChar; } ConvertPath convertPath; if (options.DisableSubNameSpace) { convertPath = delegate(string srcPath) { return(Path.GetFileName(srcPath)); }; } else { convertPath = delegate(string srcPath) { return(srcPath.StartsWith(i18nSrcDir) ? srcPath.Substring(i18nSrcDir.Length) : Path.GetFileName(srcPath)); }; } Parallel.ForEach(srcFiles, srcFile => { var srcName = convertPath(srcFile.Path); var fnameParts = srcName.Split('.', Path.DirectorySeparatorChar); var typeName = string.Join(".", fnameParts.Take(fnameParts.Length - 2)); var langCode = fnameParts[fnameParts.Length - 2]; var srcText = File.ReadAllText(srcFile.Path, srcFile.Encoding); var textTable = DeserializeSrcText(srcText, Path.GetExtension(srcFile.Path).ToLower()); var type = i18textSrc.Types.GetOrAdd(typeName, new I18nTextType()); type.Langs[langCode] = textTable; }); Parallel.ForEach(i18textSrc.Types.Values, type => { type.TextKeys = type.Langs .SelectMany(lang => lang.Value) .Select(tt => tt.Key) .OrderBy(key => key) .Distinct() .ToList(); Parallel.ForEach(type.Langs, lang => { var textTable = lang.Value; foreach (var textKey in type.TextKeys.Where(k => !textTable.ContainsKey(k))) { var text = type.Langs.Keys .OrderBy(langCode => langCode.StartsWith("en") ? "0" : langCode) .Select(langCode => type.Langs[langCode].TryGetValue(textKey, out var t) ? t : null) .FirstOrDefault(t => t != null); textTable[textKey] = text ?? textKey; } }); });
private static void OutputTypesFiles( I18nTextCompilerOptions options, I18nTextSource i18textSrc, Action <I18nTextCompilerOptions, IEnumerable <I18nTextCompileItem> > beforeCompile, Action <I18nTextCompilerOptions, I18nTextCompileItem, IEnumerable <string> > saveCode, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (!i18textSrc.Types.Any()) { return; } var i18nTextCompilerItems = i18textSrc.Types.Select(type => { var typeFullName = options.NameSpace + "." + type.Key; var typeNameParts = typeFullName.Split('.'); var typeNamespace = string.Join(".", typeNameParts.Take(typeNameParts.Length - 1)); var typeName = typeNameParts.Last(); var typeFilePath = Path.Combine(options.TypesDirectory, typeFullName + ".cs"); return(new I18nTextCompileItem(type, typeNamespace, typeName, typeFilePath)); }).ToArray(); beforeCompile?.Invoke(options, i18nTextCompilerItems); cancellationToken.ThrowIfCancellationRequested(); Parallel.ForEach(i18nTextCompilerItems, new ParallelOptions { CancellationToken = cancellationToken }, comilerItem => { var langs = comilerItem.Type.Value.Langs; var langParts = options.FallBackLanguage.Split('-'); var fallbackLangs = langParts.Length > 1 ? new[] { options.FallBackLanguage, langParts[0] } : new[] { options.FallBackLanguage }; var fallbackLang = fallbackLangs.FirstOrDefault(lang => langs.ContainsKey(lang)); if (fallbackLang == null) { throw new I18nTextCompileException(DiagnosticCode.FallbackLangNotFound, $"Could not find an I18n source text file of fallback language '{options.FallBackLanguage}', for '{options.NameSpace}.{comilerItem.Type.Key}'."); } var textTable = langs[fallbackLang]; var hash = GenerateHash(comilerItem.Type.Value); cancellationToken.ThrowIfCancellationRequested(); var typeCode = new List <string>(); typeCode.Add(GeneratedMarker); typeCode.Add($"namespace {comilerItem.TypeNamespace}"); typeCode.Add("{"); typeCode.Add($" public partial class {comilerItem.TypeName} : global::Toolbelt.Blazor.I18nText.Interfaces.I18nTextFallbackLanguage, global::Toolbelt.Blazor.I18nText.Interfaces.I18nTextLateBinding, global::Toolbelt.Blazor.I18nText.Interfaces.I18nTextTableHash"); typeCode.Add(" {"); typeCode.Add($" string global::Toolbelt.Blazor.I18nText.Interfaces.I18nTextTableHash.Hash => \"{hash}\";"); typeCode.Add(""); typeCode.Add($" string global::Toolbelt.Blazor.I18nText.Interfaces.I18nTextFallbackLanguage.FallBackLanguage => \"{options.FallBackLanguage}\";"); typeCode.Add(""); typeCode.Add(" public string this[string key] => global::Toolbelt.Blazor.I18nText.I18nTextExtensions.GetFieldValue(this, key);"); typeCode.Add(""); var is1stLine = true; foreach (var textKey in comilerItem.Type.Value.TextKeys) { if (!is1stLine) { typeCode.Add(""); } typeCode.Add($" /// <summary>\"{EscapeForXMLDocSummary(textTable[textKey])}\"</summary>"); typeCode.Add($" public string {textKey};"); is1stLine = false; } typeCode.Add(" }"); typeCode.Add("}"); saveCode?.Invoke(options, comilerItem, typeCode); }); }