コード例 #1
0
        public static bool TryFindFile(
            string directory,
            string fileName,
            string extension,
            ICultureExpression requestedCulture,
            IHostingEnvironment env,
            ICultureOption cultureOption,
            out IFileCultureInfo result)
        {
            // match requested
            if (TryFindFile(directory, fileName, extension, env, requestedCulture, out result))
            {
                return(true);
            }

            // match default
            if (TryFindFile(directory, fileName, extension, env, cultureOption.DefaultCulture, out result))
            {
                return(true);
            }

            // match no language
            string    targetName = $"{fileName}.{extension}";
            IFileInfo file       = env.ContentRootFileProvider.GetFileInfo(Path.Combine(directory, targetName));

            if (file.Exists && !file.IsDirectory)
            {
                result = new FileCultureInfo($"{directory}/{targetName}", targetName, fileName, extension, null);
                return(true);
            }

            // match failed
            result = null;
            return(false);
        }
コード例 #2
0
 public void Match <T>(ICultureExpression requestedCulture, ICultureExpression defaultCulture, IEnumerable <T> codedItems) where T : ICodedItem
 {
     foreach (T codedItem in codedItems)
     {
         codedItem.DisplayName = Match(requestedCulture, defaultCulture, codedItem.Code, codedItem.DefaultName);
     }
 }
コード例 #3
0
        public IList <IFileCultureInfo> Get(ICultureExpression requestedCulture, string directory, string extension)
        {
            string culture = requestedCulture.DisplayName;
            CultureFileCollectionPage culturePage = cultureCache.Get(culture, key => RetrivationResult <CultureFileCollectionPage> .Create(new CultureFileCollectionPage(requestedCulture, perCultureCacheSize)));

            return(culturePage.Get(directory, extension, env));
        }
コード例 #4
0
 public SetCultureFilterResult(string cultureSpecifier, ICultureExpression culture, string pathBase, string action)
 {
     CultureSpecifier = cultureSpecifier;
     PathBase         = pathBase;
     Action           = action;
     Culture          = culture;
 }
コード例 #5
0
        public static void Match <T>(this ICodeMatchingService service, ICultureExpression requestedCulture, T codedItem) where T : ICodedItem
        {
            HttpContext      httpContext   = service.HttpContext;
            IServiceProvider services      = httpContext.RequestServices;
            ICultureOption   cultureOption = services.GetRequiredService <ICultureOption>();

            service.Match(requestedCulture, cultureOption.DefaultCulture, codedItem);
        }
コード例 #6
0
 public bool Equals(ICultureExpression other)
 {
     if (other == null)
     {
         return(false);
     }
     return(DisplayName.Equals(other.DisplayName));
 }
コード例 #7
0
        public static string Match(this ICodeMatchingService service, ICultureExpression requestedCulture, string code, string defaultName)
        {
            HttpContext      httpContext   = service.HttpContext;
            IServiceProvider services      = httpContext.RequestServices;
            ICultureOption   cultureOption = services.GetRequiredService <ICultureOption>();

            return(service.Match(requestedCulture, cultureOption.DefaultCulture, code, defaultName));
        }
コード例 #8
0
 public int CompareTo(ICultureExpression other)
 {
     if (other == null)
     {
         return(-1);
     }
     return(DisplayName.CompareTo(other.DisplayName));
 }
コード例 #9
0
 public FileCultureInfo(string relativePath, string fileName, string fileNameWithoutCulture, string extension, ICultureExpression culture)
 {
     RelativePath           = relativePath;
     FileName               = fileName;
     FileNameWithoutCulture = fileNameWithoutCulture;
     Extension              = extension;
     Culture = culture;
 }
コード例 #10
0
        public static IList <IFileCultureInfo> FindFiles(
            string parentPath,
            string extension,
            ICultureExpression requestedCulture,
            HttpContext httpContext)
        {
            IHostingEnvironment env = httpContext.RequestServices.GetRequiredService <IHostingEnvironment>();

            return(FindFiles(parentPath, extension, requestedCulture, env));
        }
コード例 #11
0
 public static ICultureExpression RemoveRegion(this ICultureExpression culture)
 {
     if (culture.IsAllRegion)
     {
         return(culture);
     }
     else
     {
         return(new CultureExpression(culture.Language, "*"));
     }
 }
コード例 #12
0
        public static bool TryFindFile(
            string directory,
            string fileName,
            string extension,
            ICultureExpression requestedCulture,
            HttpContext httpContext,
            out IFileCultureInfo result)
        {
            IHostingEnvironment env    = httpContext.RequestServices.GetRequiredService <IHostingEnvironment>();
            ICultureOption      option = httpContext.RequestServices.GetRequiredService <ICultureOption>();

            return(TryFindFile(directory, fileName, extension, requestedCulture, env, option, out result));
        }
コード例 #13
0
        public static bool IsCultureSupported(this ICultureOption cultureOption, ICultureExpression culture, out ICultureExpression supportedCulture)
        {
            ICultureExpression result;

            if (culture.IsAllRegion)
            {
                result           = cultureOption.SupportedCultures.FirstOrDefault(exp => exp.Language.Equals(culture.Language));
                supportedCulture = result;
                return(supportedCulture != null);
            }
            result           = cultureOption.SupportedCultures.FirstOrDefault(exp => exp.Language.Equals(culture.Language) && exp.Region.Equals(culture.Region));
            supportedCulture = result;
            return(supportedCulture != null);
        }
コード例 #14
0
        public string Get(HttpContext httpContext, string code, string defaultName, ICultureExpression requestedCulture)
        {
            string      culture     = requestedCulture.DisplayName;
            CulturePage culturePage = cultureCache.Get(culture, key =>
            {
                string basePath = matchingOption.ResourceDirectory;
                IList <IFileCultureInfo> files = ResourceRequestHelper.FindFiles(basePath, "json", requestedCulture, httpContext);
                if (files.Count <= 0)
                {
                    files = ResourceRequestHelper.FindFiles(basePath, "json", cultureOption.DefaultCulture, httpContext);
                }
                if (files.Count <= 0)
                {
                    return(RetrivationResult <CulturePage> .Create(new EmptyCulturePage()));
                }

                string filePath;
                IHostingEnvironment env = httpContext.RequestServices.GetRequiredService <IHostingEnvironment>();
                IFileProvider provider  = env.ContentRootFileProvider;
                SetRecord values        = new SetRecord();
                foreach (IFileCultureInfo file in files.Reverse())
                {
                    filePath          = file.RelativePath;
                    IFileInfo current = provider.GetFileInfo(filePath);
                    try
                    {
                        using (Stream fileStream = current.CreateReadStream())
                        {
                            SetRecord fileContent = (SetRecord)Hake.Extension.ValueRecord.Json.Converter.ReadJson(fileStream, !matchingOption.IsCaseSensitive);
                            CombineSetRecord(values, fileContent);
                        }
                    }
                    catch
                    {
                    }
                }
                return(RetrivationResult <CulturePage> .Create(new CulturePage(perCultureCapacity, values)));
            });

            return(culturePage.ContentCache.Get(code, key =>
            {
                if (culturePage.Values.TryReadAs <string>($"{key}.name", out string value) &&
                    value != null)
                {
                    return RetrivationResult <string> .Create(value);
                }
                return RetrivationResult <string> .SupressResult(defaultName);
            }));
        }
コード例 #15
0
        private void InvokeMiddleware(HttpContext context, ICultureContext cultureContext)
        {
            ICultureExpression cultureExpression = ExtractLanguageFromUrl(context, cultureContext, out string urlSpecifier, out string action);

            cultureContext.UrlCultureSpecifier = urlSpecifier;
            if (cultureExpression == null)
            {
                cultureExpression = ExtractLanguageFromHeader(context, cultureContext);
            }
            if (cultureExpression == null)
            {
                cultureExpression = cultureContext.CultureOption.DefaultCulture;
            }
            cultureContext.Action         = action;
            cultureContext.CurrentCulture = cultureExpression;
        }
コード例 #16
0
        public static bool IsCultureSupported(this ICultureOption cultureOption, ICultureExpression culture)
        {
            if (culture.IsAllRegion)
            {
                return(cultureOption.SupportedCultures.Any(exp => exp.Language.Equals(culture.Language)));
            }

            return(cultureOption.SupportedCultures.Any(exp =>
            {
                if (exp.IsAllRegion)
                {
                    return exp.Language.Equals(culture.Language);
                }
                return exp.Language.Equals(culture.Language) && exp.Region.Equals(culture.Region);
            }));
        }
コード例 #17
0
 public static bool TryParseCultureExpression(this string language, out ICultureExpression expression)
 {
     if (language.Length == 2)
     {
         expression = new CultureExpression(language.ToLower(), "*");
         return(true);
     }
     else if (language.Length == 4 && language.EndsWith("-*"))
     {
         expression = new CultureExpression(language.Substring(0, 2).ToLower(), "*");
         return(true);
     }
     else if (language.Length == 5 && (language[2] == '-' || language[2] == '_'))
     {
         expression = new CultureExpression(language.Substring(0, 2).ToLower(), language.Substring(3, 2).ToUpper());
         return(true);
     }
     expression = null;
     return(false);
 }
コード例 #18
0
 public string Match(ICultureExpression requestedCulture, ICultureExpression defaultCulture, string code, string defaultName)
 {
     return(matchingCache.Get(HttpContext, code, defaultName, requestedCulture));
 }
コード例 #19
0
 public CultureMatchingPageResult(ICultureExpression requestedCulture)
 {
     _requestedCulture = requestedCulture;
 }
コード例 #20
0
 internal CultureOption(string defaultCulture, IEnumerable <string> supportedCultures)
 {
     this.defaultCulture    = defaultCulture.ParseCultureExpression();
     this.supportedCultures = new SortedSet <ICultureExpression>(supportedCultures.Select(exp => exp.ParseCultureExpression()), new CultureExpressionComparer()).ToList();
 }
コード例 #21
0
 public void Match <T>(ICultureExpression requestedCulture, ICultureExpression defaultCulture, T codedItem) where T : ICodedItem
 {
     codedItem.DisplayName = Match(requestedCulture, defaultCulture, codedItem.Code, codedItem.DefaultName);
 }
コード例 #22
0
 internal LocalizedViewRenderContext(ICultureExpression requestedCulture, ICultureExpression renderedCulture, string urlCultureSpecifier)
 {
     RequestedCulture    = requestedCulture;
     RenderedCulture     = renderedCulture;
     UrlCultureSpecifier = urlCultureSpecifier;
 }
コード例 #23
0
        public static IList <IFileCultureInfo> FindFiles(
            string directory,
            string extension,
            ICultureExpression requestedCulture,
            IHostingEnvironment env)
        {
            string filePath;
            string targetName;
            string fileNameWithoutCulture;
            string nameNoExt;
            string culture;
            string filter;
            string relativeParent;
            int    subLength;
            int    lastIndex;
            string endsWithFilter = $".{extension}";
            IEnumerable <IFileInfo> files;
            IEnumerable <IFileInfo> dirs;

            IFileProvider           provider = env.ContentRootFileProvider;
            IDirectoryContents      contents = provider.GetDirectoryContents(directory);
            List <IFileCultureInfo> result   = new List <IFileCultureInfo>();
            SortedSet <string>      models   = new SortedSet <string>();

            if (requestedCulture.IsAllRegion)
            {
                // find by name
                // **.en.ext
                culture   = requestedCulture.Language;
                filter    = $".{culture}.{extension}";
                files     = contents.Where(x => !x.IsDirectory && x.Name.EndsWith(filter));
                subLength = filter.Length;
                foreach (IFileInfo file in files)
                {
                    targetName             = file.Name;
                    filePath               = $"{directory}/{targetName}"; // Path.Combine(parentPath, fileName)
                    fileNameWithoutCulture = targetName.Substring(0, targetName.Length - subLength);
                    result.Add(new FileCultureInfo(filePath, targetName, fileNameWithoutCulture, extension, requestedCulture));
                    models.Add(fileNameWithoutCulture);
                }

                // try find directory named with language
                // en/**.ext
                IFileInfo dir = contents.FirstOrDefault(x => x.IsDirectory && x.Name.Equals(culture));
                if (dir != null)
                {
                    relativeParent = $"{directory}/{culture}";
                    IDirectoryContents directoryContents = provider.GetDirectoryContents(relativeParent);
                    files = directoryContents.Where(x => !x.IsDirectory && x.Name.EndsWith(endsWithFilter));
                    foreach (IFileInfo file in files)
                    {
                        targetName             = file.Name;
                        filePath               = $"{relativeParent}/{targetName}";// Path.Combine(relatedParent, fileName)
                        fileNameWithoutCulture = Path.GetFileNameWithoutExtension(targetName);
                        if (!models.Contains(fileNameWithoutCulture))
                        {
                            result.Add(new FileCultureInfo(filePath, targetName, fileNameWithoutCulture, extension, requestedCulture));
                            models.Add(fileNameWithoutCulture);
                        }
                    }
                }

                // find the regions having the same language
                // **.en-**.ext
                filter = $@"\.{culture}-[a-zA-Z]{{2}}\.{extension}$";
                Regex reg = new Regex(filter);
                files = contents.Where(x => !x.IsDirectory && reg.IsMatch(x.Name));
                foreach (IFileInfo file in files)
                {
                    targetName             = file.Name;
                    nameNoExt              = Path.GetFileNameWithoutExtension(targetName);
                    lastIndex              = nameNoExt.LastIndexOf('.');
                    fileNameWithoutCulture = targetName.Substring(0, lastIndex);
                    filePath = $"{directory}/{targetName}"; //Path.Combine(parentPath, fileName)
                    culture  = nameNoExt.Substring(lastIndex + 1);
                    if (!models.Contains(fileNameWithoutCulture))
                    {
                        result.Add(new FileCultureInfo(filePath, targetName, fileNameWithoutCulture, extension, culture.ParseCultureExpression()));
                        models.Add(fileNameWithoutCulture);
                    }
                }

                // try find directory named with regions having the same language
                // en-**/**.ext
                filter = $"^{culture}-[a-zA-Z]{{2}}$";
                reg    = new Regex(filter);
                dirs   = contents.Where(x => x.IsDirectory && reg.IsMatch(x.Name));
                foreach (IFileInfo langDir in dirs)
                {
                    culture = langDir.Name;
                    ICultureExpression cultureExp = culture.ParseCultureExpression();
                    relativeParent = $"{directory}/{culture}"; //Path.Combine(parentPath, culture)

                    IDirectoryContents directoryContents = provider.GetDirectoryContents(relativeParent);
                    files = directoryContents.Where(x => !x.IsDirectory && x.Name.EndsWith(endsWithFilter));
                    foreach (IFileInfo file in files)
                    {
                        targetName             = file.Name;
                        filePath               = $"{relativeParent}/{targetName}"; //Path.Combine(relatedParent, fileName)
                        fileNameWithoutCulture = Path.GetFileNameWithoutExtension(targetName);
                        if (!models.Contains(fileNameWithoutCulture))
                        {
                            result.Add(new FileCultureInfo(filePath, targetName, fileNameWithoutCulture, extension, cultureExp));
                            models.Add(fileNameWithoutCulture);
                        }
                    }
                }
            }
            else
            {
                // find by name
                // **.en-US.ext
                culture   = requestedCulture.DisplayName;
                filter    = $".{culture}.{extension}";
                files     = contents.Where(x => !x.IsDirectory && x.Name.EndsWith(filter));
                subLength = filter.Length;
                foreach (IFileInfo file in files)
                {
                    targetName             = file.Name;
                    filePath               = $"{directory}/{targetName}"; //Path.Combine(parentPath, fileName)
                    fileNameWithoutCulture = targetName.Substring(0, targetName.Length - subLength);
                    result.Add(new FileCultureInfo(filePath, targetName, fileNameWithoutCulture, extension, requestedCulture));
                    models.Add(fileNameWithoutCulture);
                }

                // try find directory named with culture name
                // en-US/**.ext
                dirs = contents.Where(x => x.IsDirectory && x.Name.Equals(culture));
                foreach (IFileInfo langDir in dirs)
                {
                    relativeParent = $"{directory}/{culture}"; //Path.Combine(parentPath, culture)

                    IDirectoryContents directoryContents = provider.GetDirectoryContents(relativeParent);
                    files = directoryContents.Where(x => !x.IsDirectory && x.Name.EndsWith(endsWithFilter));
                    foreach (IFileInfo file in files)
                    {
                        targetName             = file.Name;
                        filePath               = $"{relativeParent}/{targetName}"; //Path.Combine(relatedParent, fileName)
                        fileNameWithoutCulture = Path.GetFileNameWithoutExtension(targetName);
                        if (!models.Contains(fileNameWithoutCulture))
                        {
                            result.Add(new FileCultureInfo(filePath, targetName, fileNameWithoutCulture, extension, requestedCulture));
                            models.Add(fileNameWithoutCulture);
                        }
                    }
                }

                // find the regions having the same language
                // **.en.ext
                culture = requestedCulture.Language;
                ICultureExpression cultureExp = culture.ParseCultureExpression();
                filter    = $".{culture}.{extension}";
                files     = contents.Where(x => !x.IsDirectory && x.Name.EndsWith(filter));
                subLength = filter.Length;
                foreach (IFileInfo file in files)
                {
                    targetName             = file.Name;
                    filePath               = $"{directory}/{targetName}"; //Path.Combine(parentPath, fileName)
                    fileNameWithoutCulture = targetName.Substring(0, targetName.Length - subLength);
                    if (!models.Contains(fileNameWithoutCulture))
                    {
                        result.Add(new FileCultureInfo(filePath, targetName, fileNameWithoutCulture, extension, cultureExp));
                        models.Add(fileNameWithoutCulture);
                    }
                }

                // try find directory named with the same language
                // en/**.ext
                relativeParent = $"{directory}/{culture}"; //Path.Combine(parentPath, culture)
                IFileInfo dir = contents.FirstOrDefault(x => x.IsDirectory && x.Name.Equals(culture));
                if (dir != null)
                {
                    IDirectoryContents directoryContents = provider.GetDirectoryContents(relativeParent);
                    files = directoryContents.Where(x => !x.IsDirectory && x.Name.EndsWith(endsWithFilter));
                    foreach (IFileInfo file in files)
                    {
                        targetName             = file.Name;
                        filePath               = $"{relativeParent}/{targetName}"; //Path.Combine(relatedParent, fileName)
                        fileNameWithoutCulture = Path.GetFileNameWithoutExtension(targetName);
                        if (!models.Contains(fileNameWithoutCulture))
                        {
                            result.Add(new FileCultureInfo(filePath, targetName, fileNameWithoutCulture, extension, cultureExp));
                            models.Add(fileNameWithoutCulture);
                        }
                    }
                }
            }
            return(result);
        }
コード例 #24
0
 internal CultureFileCollectionPage(ICultureExpression culture, int capacity)
 {
     cache        = new Cache <string, IList <IFileCultureInfo> >(capacity);
     this.culture = culture;
 }
コード例 #25
0
        public Task Invoke(HttpContext context, ICultureContext cultureContext)
        {
            if (filter == null)
            {
                InvokeMiddleware(context, cultureContext);
            }
            else
            {
                UrlFilterResult filterResult = filter(context.Request.Path);
                if (filterResult is InvokeMiddlewareFilterResult)
                {
                    InvokeMiddleware(context, cultureContext);
                }
                else if (filterResult is SetCultureFilterResult setCultureResult)
                {
                    cultureContext.UrlCultureSpecifier = setCultureResult.CultureSpecifier;
                    cultureContext.CurrentCulture      = setCultureResult.Culture;
                    cultureContext.Action    = setCultureResult.Action;
                    context.Request.Path     = new PathString(cultureContext.Action);
                    context.Request.PathBase = new PathString(setCultureResult.PathBase);
                }
                else if (filterResult is CheckHeaderFilterResult)
                {
                    cultureContext.UrlCultureSpecifier = "";
                    ICultureExpression cultureExpression = ExtractLanguageFromHeader(context, cultureContext);
                    if (cultureExpression == null)
                    {
                        cultureExpression = cultureContext.CultureOption.DefaultCulture;
                    }
                    cultureContext.Action         = context.Request.Path;
                    cultureContext.CurrentCulture = cultureExpression;
                }
                else
                {
                    ICultureExpression cultureExpression = cultureContext.CultureOption.DefaultCulture;
                    cultureContext.Action         = context.Request.Path;
                    cultureContext.CurrentCulture = cultureExpression;
                    return(next(context));
                }
            }

            string urlSpecifier = cultureContext.UrlCultureSpecifier;

            if (urlSpecifier.Length <= 0)
            {
                return(next(context));
            }
            else
            {
                return(next(context).ContinueWith(tsk =>
                {
                    if ((context.Response.StatusCode == 301 || context.Response.StatusCode == 302) &&
                        context.Response.Headers.TryGetValue("Location", out StringValues locationValue) &&
                        locationValue.Count > 0)
                    {
                        string location = locationValue[0];
                        if (UrlComponents.TryParse(location, out UrlComponents urlComponents))
                        {
                            if (urlComponents.IsRelative)
                            {
                                if (!string.IsNullOrEmpty(urlComponents.CultureSpecifier))
                                {
                                    // dose not change the location
                                    // context.Response.Headers["Location"] = urlSpecifier + context.Response.Headers["Location"];
                                    return;
                                }
                                else
                                {
                                    urlComponents.TrySetCulture(urlSpecifier);
                                    context.Response.Headers["Location"] = urlComponents.FullActionWithQuery;
                                    return;
                                }
                            }
                            else
                            {
                                string host = context.Request.Host.Value;
                                string requestedHost = urlComponents.FullHost;
                                if (requestedHost != null && requestedHost.Equals(host, StringComparison.CurrentCultureIgnoreCase))
                                {
                                    if (!string.IsNullOrEmpty(urlComponents.CultureSpecifier))
                                    {
                                        // dose not change the location
                                        // context.Response.Headers["Location"] = urlSpecifier + context.Response.Headers["Location"];
                                        return;
                                    }
                                    else
                                    {
                                        urlComponents.TrySetCulture(urlSpecifier);
                                        context.Response.Headers["Location"] = urlComponents.FullActionWithQuery;
                                        return;
                                    }
                                }
                                else
                                {
                                    // dose not change the location
                                    // context.Response.Headers["Location"] = urlSpecifier + context.Response.Headers["Location"];
                                    return;
                                }
                            }
                        }
                        else
                        {
                            // dose not change the location
                            // context.Response.Headers["Location"] = urlSpecifier + context.Response.Headers["Location"];
                        }
                    }
                }));
            }
        }
コード例 #26
0
 public CultureMatchingViewResult(ICultureExpression requestedCulture)
 {
     RequestedCulture = requestedCulture;
 }
コード例 #27
0
        private static bool TryFindFile(
            string directory,
            string fileName,
            string extension,
            IHostingEnvironment env,
            ICultureExpression requestedCulture,
            out IFileCultureInfo result)
        {
            string             filePath;
            string             targetName;
            string             culture;
            IFileInfo          file;
            IDirectoryContents contents;
            IFileProvider      provider = env.ContentRootFileProvider;

            if (requestedCulture.IsAllRegion)
            {
                // find by name
                // View.en.cshtml
                culture    = requestedCulture.Language;
                targetName = $"{fileName}.{culture}.{extension}";
                filePath   = $"{directory}/{targetName}";
                file       = provider.GetFileInfo(filePath);
                if (file.Exists && !file.IsDirectory)
                {
                    result = new FileCultureInfo(filePath, targetName, fileName, extension, requestedCulture);
                    return(true);
                }

                // try find directory named with language
                // en/View.cshtml
                contents = provider.GetDirectoryContents(directory);
                IFileInfo dir = contents.FirstOrDefault(x => x.IsDirectory && x.Name.Equals(culture));
                if (dir != null)
                {
                    targetName = $"{fileName}.{extension}";
                    filePath   = $"{directory}/{dir.Name}/{targetName}";
                    file       = provider.GetFileInfo(filePath);
                    if (file.Exists && !file.IsDirectory)
                    {
                        result = new FileCultureInfo(filePath, targetName, fileName, extension, requestedCulture);
                        return(true);
                    }
                }

                // find the first region having the same language
                // View.en-XX.cshtml
                string startsWithFilter = $"{fileName}.{culture}-";
                string endsWithFilter   = $".{extension}";
                file = contents.FirstOrDefault(x => !x.IsDirectory && x.Name.StartsWith(startsWithFilter) && x.Name.EndsWith(endsWithFilter));
                if (file != null)
                {
                    culture  = file.Name.Substring(fileName.Length + 1);
                    culture  = Path.GetFileNameWithoutExtension(culture);
                    filePath = $"{directory}/{file.Name}";
                    result   = new FileCultureInfo(filePath, file.Name, fileName, extension, culture.ParseCultureExpression());
                    return(true);
                }

                // try find directory named with the first region having the same language
                // en-XX/View.cshtml
                startsWithFilter = $"{culture}-";
                dir = contents.FirstOrDefault(x => x.IsDirectory && x.Name.StartsWith(startsWithFilter));
                if (dir != null)
                {
                    targetName = $"{fileName}.{extension}";
                    filePath   = $"{directory}/{dir.Name}/{targetName}";
                    file       = provider.GetFileInfo(filePath);
                    if (file.Exists && !file.IsDirectory)
                    {
                        culture = dir.Name;
                        result  = new FileCultureInfo(filePath, targetName, fileName, extension, culture.ParseCultureExpression());
                        return(true);
                    }
                }
            }
            else
            {
                // find by name
                // View.en-US.cshtml
                culture    = requestedCulture.DisplayName;
                targetName = $"{fileName}.{culture}.{extension}";
                filePath   = $"{directory}/{targetName}";
                file       = provider.GetFileInfo(filePath);
                if (file.Exists && !file.IsDirectory)
                {
                    result = new FileCultureInfo(filePath, targetName, fileName, extension, requestedCulture);
                    return(true);
                }

                // try find directory named with name
                // en-US/View.cshtml
                contents = provider.GetDirectoryContents(directory);
                IFileInfo dir = contents.FirstOrDefault(x => x.IsDirectory && x.Name.Equals(culture));
                if (dir != null)
                {
                    targetName = $"{fileName}.{extension}";
                    filePath   = $"{directory}/{culture}/{targetName}";
                    file       = provider.GetFileInfo(filePath);
                    if (file.Exists && !file.IsDirectory)
                    {
                        result = new FileCultureInfo(filePath, targetName, fileName, extension, requestedCulture);
                        return(true);
                    }
                }

                // find by language
                // View.en.cshtml
                culture    = requestedCulture.Language;
                targetName = $"{fileName}.{culture}.{extension}";
                filePath   = $"{directory}/{targetName}";
                file       = provider.GetFileInfo(filePath);
                if (file.Exists && !file.IsDirectory)
                {
                    result = new FileCultureInfo(filePath, targetName, fileName, extension, culture.ParseCultureExpression());
                    return(true);
                }

                // try find directory named with the specific language
                // en/View.cshtml
                dir = contents.FirstOrDefault(x => x.IsDirectory && x.Name.Equals(culture));
                if (dir != null)
                {
                    targetName = $"{fileName}.{extension}";
                    filePath   = $"{directory}/{culture}/{targetName}";
                    file       = provider.GetFileInfo(filePath);
                    if (file.Exists && !file.IsDirectory)
                    {
                        result = new FileCultureInfo(filePath, targetName, fileName, extension, culture.ParseCultureExpression());
                        return(true);
                    }
                }
            }

            result = null;
            return(false);
        }