/// <summary>
        /// Initializes a new instance of the <see cref="LanguageGeneratorManager"/> class.
        /// </summary>
        /// <param name="resourceExplorer">resourceExplorer to manage LG files from.</param>
        public LanguageGeneratorManager(ResourceExplorer resourceExplorer)
        {
            this.resourceExplorer  = resourceExplorer;
            multilanguageResources = MultiLanguageResourceLoader.Load(resourceExplorer);

            // load all LG resources
            foreach (var resource in this.resourceExplorer.GetResources("lg"))
            {
                LanguageGenerators[resource.Id] = GetTemplateEngineLanguageGenerator(resource);
            }

            // listen for resource changes
            this.resourceExplorer.Changed += ResourceExplorer_Changed;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="TemplateEngineLanguageGenerator"/> class.
        /// </summary>
        /// <param name="lgText">lg template text.</param>
        /// <param name="id">optional label for the source of the templates (used for labeling source of template errors).</param>
        /// <param name="resourceMapping">template resource loader delegate (locale) -> <see cref="ImportResolverDelegate"/>.</param>
        public TemplateEngineLanguageGenerator(string lgText, string id, Dictionary <string, IList <IResource> > resourceMapping)
        {
            this.Id        = id ?? DEFAULTLABEL;
            var(_, locale) = MultiLanguageResourceLoader.ParseLGFileName(id);
            var fallbackLocale = MultiLanguageResourceLoader.FallbackLocale(locale, resourceMapping.Keys.ToList());

            foreach (var mapping in resourceMapping)
            {
                // if no locale present in id, enumarate every locale found
                // if locale is present, use that one
                if (string.Equals(fallbackLocale, string.Empty) || string.Equals(fallbackLocale, mapping.Key))
                {
                    var engine = new TemplateEngine().AddText(lgText ?? string.Empty, Id, LanguageGeneratorManager.ResourceExplorerResolver(mapping.Key, resourceMapping));
                    multiLangEngines.Add(mapping.Key, engine);
                }
            }
        }
        private TemplateEngine InitTemplateEngine(ITurnContext turnContext)
        {
            var locale = turnContext.Activity.Locale?.ToLower() ?? string.Empty;

            if (multiLangEngines.Count > 0)
            {
                var fallbackLocale = MultiLanguageResourceLoader.FallbackLocale(locale, multiLangEngines.Keys.ToList());
                engine = multiLangEngines[fallbackLocale];
            }
            else
            {
                // Do not rewrite to ??= (C# 8.0 new feature). It will break in linux/mac
                engine = engine ?? new TemplateEngine();
            }

            return(engine);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="TemplateEngineLanguageGenerator"/> class.
        /// </summary>
        /// <param name="filePath">lg template file absolute path.</param>
        /// <param name="resourceMapping">template resource loader delegate (locale) -> <see cref="ImportResolverDelegate"/>.</param>
        public TemplateEngineLanguageGenerator(string filePath, Dictionary <string, IList <IResource> > resourceMapping)
        {
            filePath = PathUtils.NormalizePath(filePath);
            this.Id  = Path.GetFileName(filePath);

            var(_, locale) = MultiLanguageResourceLoader.ParseLGFileName(Id);
            var fallbackLocale = MultiLanguageResourceLoader.FallbackLocale(locale, resourceMapping.Keys.ToList());

            foreach (var mapping in resourceMapping)
            {
                // if no locale present in id, enumarate every locale found
                // if locale is present, use that one
                if (string.Equals(fallbackLocale, string.Empty) || string.Equals(fallbackLocale, mapping.Key))
                {
                    var engine = new TemplateEngine().AddFile(filePath, LanguageGeneratorManager.ResourceExplorerResolver(mapping.Key, resourceMapping));
                    multiLangEngines.Add(mapping.Key, engine);
                }
            }
        }
        public static ImportResolverDelegate ResourceExplorerResolver(string locale, Dictionary <string, IList <IResource> > resourceMapping)
        {
            return((string source, string id) =>
            {
                var fallbackLocale = MultiLanguageResourceLoader.FallbackLocale(locale, resourceMapping.Keys.ToList());
                var resources = resourceMapping[fallbackLocale];

                var resourceName = Path.GetFileName(PathUtils.NormalizePath(id));

                var resource = resources.FirstOrDefault(u => MultiLanguageResourceLoader.ParseLGFileName(u.Id).prefix.ToLower() == MultiLanguageResourceLoader.ParseLGFileName(resourceName).prefix.ToLower());
                if (resource == null)
                {
                    throw new Exception($"There is no matching LG resource for {resourceName}");
                }
                else
                {
                    var content = resource.ReadTextAsync().GetAwaiter().GetResult();
                    return (content, resource.Id);
                }
            });
        }