Esempio n. 1
0
 private static bool Compile(
     IEnumerable <I18nTextSourceFile> srcFiles,
     I18nTextCompilerOptions options,
     Action <I18nTextCompilerOptions, IEnumerable <I18nTextCompileItem> > beforeCompile,
     Action <I18nTextCompilerOptions, I18nTextCompileItem, IEnumerable <string> > saveCode,
     CancellationToken cancellationToken)
 {
     try
     {
         var i18textSrc = I18nTextSourceFile.Parse(srcFiles, options, cancellationToken);
         OutputI18nTextJsonFiles(options, i18textSrc, cancellationToken);
         OutputTypesFiles(options, i18textSrc, beforeCompile, saveCode, cancellationToken);
         return(true);
     }
     catch (AggregateException e) when(e.InnerException is I18nTextCompileException compileException)
     {
         options.LogError(compileException);
         return(false);
     }
     catch (I18nTextCompileException compileException)
     {
         options.LogError(compileException);
         return(false);
     }
 }
Esempio n. 2
0
 public static bool Compile(
     IEnumerable <I18nTextSourceFile> srcFiles,
     I18nTextCompilerOptions options,
     Action <I18nTextCompilerOptions, I18nTextCompileItem, IEnumerable <string> > saveCode,
     CancellationToken cancellationToken)
 {
     return(Compile(srcFiles, options, beforeCompile: null, saveCode, cancellationToken));
 }
Esempio n. 3
0
        public override bool Execute()
        {
            try
            {
                if ((this.Include?.Length ?? 0) == 0)
                {
                    this.Log.LogMessage("No Source files were specified.");
                    return(true);
                }

                var baseDir = this.BaseDir ?? Path.GetDirectoryName(this.BuildEngine.ProjectFileOfTaskNode);

                var options = new I18nTextCompilerOptions(baseDir);
                options.I18nTextSourceDirectory = Path.Combine(baseDir, this.I18nTextSourceDirectory) ?? options.I18nTextSourceDirectory;
                options.TypesDirectory          = this.TypesDirectory ?? options.TypesDirectory;
                options.OutDirectory            = this.OutDirectory ?? options.OutDirectory;
                options.NameSpace           = string.IsNullOrEmpty(this.NameSpace) ? options.NameSpace : this.NameSpace;
                options.DisableSubNameSpace = this.DisableSubNameSpace;
                options.FallBackLanguage    = this.FallBackLanguage ?? options.FallBackLanguage;
                options.LogMessage          = msg => this.Log.LogMessage(msg);

                options.LogError = ex => this.Log.LogError(ex is I18nTextCompileException compilerEx ? $"IN{compilerEx.Code:D3}: {ex.Message}" : ex.Message);

                this.Log.LogMessage($"I18nTextSourceDirectory: [{options.I18nTextSourceDirectory}]");
                this.Log.LogMessage($"TypesDirectory: [{options.TypesDirectory}]");
                this.Log.LogMessage($"OutDirectory  : [{options.OutDirectory}]");
                this.Log.LogMessage($"NameSpace     : [{options.NameSpace}]");
                this.Log.LogMessage($"FallBackLanguage: [{options.FallBackLanguage}]");

                var srcFiles = this.Include
                               .Select(taskItem => (Path: Path.Combine(baseDir, taskItem.ItemSpec), Encoding: GetEncoding(taskItem)))
                               .Select(item => new I18nTextSourceFile(item.Path, item.Encoding))
                               .ToArray();

                foreach (var src in srcFiles)
                {
                    this.Log.LogMessage($"- {src.Path}, {src.Encoding.BodyName}");
                }

                var compiler     = new I18nTextCompiler();
                var successOrNot = compiler.Compile(srcFiles, options);
                return(successOrNot);
            }
            catch (Exception e)
            {
                this.Log.LogErrorFromException(e, showStackTrace: true, showDetail: true, file: null);
                return(false);
            }
        }
Esempio n. 4
0
        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);
                }
            });
Esempio n. 5
0
        private static void SaveTypeCodeToTypeFiles(I18nTextCompilerOptions options, I18nTextCompileItem compileItem, IEnumerable <string> typeCode)
        {
            var skipOutput = false;

            if (File.Exists(compileItem.TypeFilePath))
            {
                var prevTypeCode = File.ReadAllLines(compileItem.TypeFilePath);
                skipOutput = prevTypeCode.SequenceEqual(typeCode);
            }

            if (!skipOutput)
            {
                if (!Directory.Exists(options.TypesDirectory))
                {
                    Directory.CreateDirectory(options.TypesDirectory);
                }
                File.WriteAllLines(compileItem.TypeFilePath, typeCode);
            }
        }
Esempio n. 6
0
 public bool Compile(IEnumerable <I18nTextSourceFile> srcFiles, I18nTextCompilerOptions options)
 {
     try
     {
         var i18textSrc = ParseSourceFiles(srcFiles, options);
         OutputTypesFiles(options, i18textSrc);
         OutputI18nTextJsonFiles(options, i18textSrc);
         return(true);
     }
     catch (AggregateException e) when(e.InnerException is I18nTextCompileException compileException)
     {
         options.LogError(compileException.Message);
         return(false);
     }
     catch (I18nTextCompileException compileException)
     {
         options.LogError(compileException.Message);
         return(false);
     }
 }
Esempio n. 7
0
        /// <summary>
        /// Sweep old generated/should be purge type files.
        /// </summary>
        internal static void SweepTypeFilesShouldBePurged(I18nTextCompilerOptions options, IEnumerable <I18nTextCompileItem> compilerItems, CancellationToken cancellationToken)
        {
            if (Directory.Exists(options.TypesDirectory))
            {
                var existsTypeFiles      = Directory.GetFiles(options.TypesDirectory, "*.cs");
                var shouldBeSweepedFiles = existsTypeFiles.Except(compilerItems.Select(t => t.TypeFilePath));
                foreach (var shouldBeSweepedFile in shouldBeSweepedFiles)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    if (File.ReadLines(shouldBeSweepedFile).Any(line => line == GeneratedMarker))
                    {
                        File.Delete(shouldBeSweepedFile);
                    }
                }

                cancellationToken.ThrowIfCancellationRequested();
                if (!Directory.GetFileSystemEntries(options.TypesDirectory).Any())
                {
                    Directory.Delete(options.TypesDirectory, recursive: false);
                }
            }
        }
Esempio n. 8
0
        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;
                    }
                });
            });
Esempio n. 9
0
        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;
                    }
                });
            });
Esempio n. 10
0
        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);
            });
        }
Esempio n. 11
0
 public bool Compile(IEnumerable <I18nTextSourceFile> srcFiles, I18nTextCompilerOptions options)
 {
     return(Compile(srcFiles, options, beforeCompile: SweepTypeFilesShouldBePurged, saveCode: SaveTypeCodeToTypeFiles, CancellationToken.None));
 }
Esempio n. 12
0
 /// <summary>
 /// Sweep old generated/should be purge type files.
 /// </summary>
 private static void SweepTypeFilesShouldBePurged(I18nTextCompilerOptions options, IEnumerable <I18nTextCompileItem> compilerItems)
 {
     SweepTypeFilesShouldBePurged(options, compilerItems, CancellationToken.None);
 }