Dynamic definition of the list of available languages for an ASP.NET web page
Introduction
In this article, we will learn how to dynamically define a list of available languages for an ASP.NET web page.
Requirement
Microsoft® Visual Web Developer® 2010 Express and higher. Web-site with localization that is based on the use of resource files (.resx) for localization.
Why and when this can be helpful
The main advantage of this functionality is to get rid of a static list of supported languages on the web page. With this functionality, you can have a different number of supported languages for each page. Each page will determine the list of supported languages based on the resource files existing for the page.
How to implement
To use this functionality, you need to do three things:
- Inherit each web page class which is intended to use this functionality from a base class -
BasePage
. - Add to your web site two files: BasePage.cs and Cultures.cs.
- Bind a control on the page intended for display and language selection to a page with the list of available languages for the page. The list of available languages would provide a method
GetAvailableCultures
from aCultures
class.
How it works
As an example, I will suggest a site that is created by Visual Studio as a template for a new web-site with a Master page, Default page, and an About page as well. For decreasing the project size, I will not take into account other files for authentication functionality etc. I will try to show all the functionality on the example with two pages: Default.aspx and About.aspx. For this example, I have added some resource files (with absolutely different cultures for both pages) and will show how to dynamically define a list of available cultures on each page.
After defining the project structure, we will continue with the implementation details.
First of all, let’s see the root file for this feature, Cultures.cs. Here is the code:
public class Cultures
{
public static readonly string DEFAULT_CULTURE_NAME = "en";
public IList<string> GetAvailableCultures(string directoryPath, string fileName)
{
// Used in WriteLine to trim output lines.
int trimLength = directoryPath.Length;
// Take a snapshot of the file system.
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(directoryPath);
// This method assumes that the application has discovery permissions
// for all folders under the specified path.
// Provide a search for the appropriate files
IEnumerable<System.IO.FileInfo> fileList =
dir.GetFiles(string.Format("{0}.*.resx",fileName),
System.IO.SearchOption.AllDirectories);
// Select out the name of culture from the list of resource files
IList<string> Cultures = fileList
.Select(x => x.Name.Split('.')[x.Name.Split('.').Length - 2].ToString())
.Distinct()
.Where(y => y.Length < 8 && y != "aspx").ToList<string>();
Cultures.Add(DEFAULT_CULTURE_NAME);
return Cultures;
}
}
The main function in this class is GetAvailableCultures
and it gets us the list of available cultures based on the resource files available for the current page.
When we get a list of all the available cultures, we can think about how to show it. For this issue, I will use a dropdown control which will be filled with the cultures on the Master page Page_Load
handler.
There is also another interesting question - how to change the culture of the page if the user changes it using the dropdown on the master page? There exists a good explanation for this issue here on CodeProject: http://www.codeproject.com/KB/aspnet/localizationByVivekTakur.aspx.
Following this example, we can implement such a code for the Site.Master.cs code-behind:
public partial class SiteMaster : System.Web.UI.MasterPage
{
protected string CalledPageName { get {
return HttpContext.Current.Request.
AppRelativeCurrentExecutionFilePath.Substring(2); } }
protected void Page_Load(object sender, EventArgs e)
{
// Select choosen language after the page was reloaded
if (this.IsPostBack == false)
{
//if (Cache[CalledPageName] != null) Cache.Remove(CalledPageName);
IList<string> CultureList = null;
if (Cache[CalledPageName] != null)
CultureList = (IList<string>)Cache[CalledPageName];
else
{
// Get a list of availabele cultures
// based on an appropriate resource files
Cultures c = new Cultures();
CultureList = c.GetAvailableCultures(
System.IO.Path.GetDirectoryName(
Request.PhysicalPath)
, CalledPageName
);
Cache[CalledPageName] = CultureList;
}
// Add all available languages to Dropdown list "Choose Language"
foreach (string culture in CultureList)
ddlChooseCulture.Items.Add(new ListItem(
CultureInfo.GetCultureInfo(
culture).NativeName.ToLowerInvariant(), culture));
if (CultureList.Count == 0)
ddlChooseCulture.Items.Add(new ListItem(
CultureInfo.GetCultureInfo(
Cultures.DEFAULT_CULTURE_NAME).NativeName.ToLowerInvariant(),
Cultures.DEFAULT_CULTURE_NAME));
if (Session["CurrentCulture"] != null)
ddlChooseCulture.SelectedValue = (string)Session["CurrentCulture"];
else
{
if (ddlChooseCulture.Items.FindByValue(
System.Threading.Thread.CurrentThread.
CurrentUICulture.TwoLetterISOLanguageName) != null)
ddlChooseCulture.SelectedValue =
System.Threading.Thread.CurrentThread.
CurrentUICulture.TwoLetterISOLanguageName;
else
ddlChooseCulture.SelectedValue = Cultures.DEFAULT_CULTURE_NAME;
}
}
}
protected void ddlChooseCulture_SelectedIndexChanged(object sender, EventArgs e)
{
Session["CurrentCulture"] = ddlChooseCulture.SelectedValue.ToString();
Response.Redirect(Request.Url.AbsoluteUri);
}
}
This requires us to override the InitializeCulture()
method on the page code-behind class. But it is not a good practice to implement the same piece of code on each page. So, the solution is to create a BasePage
class which will provide the core functionality for all the pages. Now, each page that requires localization should inherit the BasePage
class.
The base class implementation includes this code:
public class BasePage : System.Web.UI.Page
{
/// <summary>
/// Initialize choosen culture
/// </summary>
protected override void InitializeCulture()
{
string language = string.Empty;
if (Session["CurrentCulture"] != null)
language = (string)Session["CurrentCulture"];
if (!string.IsNullOrEmpty(language))
{
Thread.CurrentThread.CurrentCulture =
CultureInfo.CreateSpecificCulture(language);
Thread.CurrentThread.CurrentUICulture = new CultureInfo(language);
}
base.InitializeCulture();
}
}
Summary
This article covers the basic fundamentals of using a dynamic definition of culture that is based on existing resource files for a specified page. Hope you have learned something new from this article. Please share your valuable feedback and suggestions to improve this.