I've setup a web site to be localized using Global resources only. I'm having a hard time figuring out why a page is always giving inconsistent behavior every time I trigger a culture change through a drop down list. Here are my resource files:
Resources:
Setup Here is the Base Page that is inherited by all pages:
public partial class BaseWebForm : Page
{
protected override void InitializeCulture()
{
if (Session["UserLanguage"] != null)
{
String selectedLanguage = Session["UserLanguage"].ToString();
UICulture = selectedLanguage;
Culture = selectedLanguage;
CultureInfo culture = CultureInfo.CreateSpecificCulture(selectedLanguage);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
}
base.InitializeCulture();
}
}
I'm using a Session variable, UserLanguage
, to manage selected language. My site assumes en-US as default language and the drop down is displayed on the login page. That means the user cannot change language on any page as, upon login page, a service retrieves available languages.
I'm using Master page and I've handled the menus, breadcrumb SiteMapPath, and LTR-RTL there.
On the actual page, here is a brief:
public partial class PublicLogOn : BaseWebForm
{
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (Request.IsAuthenticated)
{
SiteLogger.NLogger.Info("Request Authenticated");
SiteLogin.RedirectToDefaultPage();
}
#region Handle Return URL
if (HttpContext.Current.Request.QueryString["ReturnUrl"] != null && !String.IsNullOrEmpty(HttpContext.Current.Request.QueryString["ReturnUrl"]))
{
var tempUrl = HttpContext.Current.Request.QueryString["ReturnUrl"];
SiteLogger.NLogger.Info("Return URL : " + tempUrl);
if (tempUrl.Contains(@"/SecuredArea/AdminArea/"))
{
buttonLogOn.Visible = false;
// buttonAdminLogOn.Visible = true;
}
else if (tempUrl.Contains(@"/SecuredArea/EmployeeArea/"))
{
buttonLogOn.Visible = true;
// buttonAdminLogOn.Visible = false;
}
else
{
// buttonLogOn.Visible = buttonAdminLogOn.Visible = true;
buttonLogOn.Visible = true;
}
}
#endregion
if (!Page.IsPostBack)
{
SiteLogger.NLogger.Info("Loading Languages and Directories");
// Actual language loading
if (!LoadLanguages() || !LoadDirectories())
{
SiteLogger.NLogger.Info("Loading Languages or Directories failed!");
return;
}
SiteLogger.NLogger.Info("Completed : PublicLogOn.PageLoad");
}
// Don't know why this fails and the drop-down still shows en-US even culture is ur-PK
//if (Session["UserLanguage"] != null)
//{
// DDLLanguages.SelectedValue = Session["UserLanguage"].ToString();
//}
}
catch (Exception ex)
{
SiteLogger.NLogger.Error("Error in PublicLogOn.Page_Load", ex.Message);
}
}
private Boolean LoadLanguages()
{
Boolean methodResult;
try
{
SiteLogger.NLogger.Info("In Load Languages");
// This line also mess up
// Session["UserLanguage"] = null;
DDLLanguages.Items.Clear();
var fetchedLanguages = UserManagePage.GetOrganizationLanguages();
foreach (var oneFetchedLanguage in fetchedLanguages)
{
DDLLanguages.Items.Add(new ListItem(oneFetchedLanguage.LanguageSymbol, oneFetchedLanguage.LanguageSymbol));
}
if (fetchedLanguages.Count() == 1)
{
DDLLanguages.Enabled = false;
}
methodResult = true;
}
catch (Exception exp)
{
SiteLogger.NLogger.Error("Error in load languages : ", exp.ToString());
labelMessage.Text = MessageFormatter.GetFormattedErrorMessage("Error retrieving organization languages.");
methodResult = false;
}
return methodResult;
}
private Boolean LoadDirectories()
{
// Nothing to-do with code-in-question
}
protected void ButtonLogOn_Click(object sender, EventArgs e)
{
// Nothing to-do with code-in-question
}
protected void DDLLanguages_SelectedIndexChanged(object sender, EventArgs e)
{
Session["UserLanguage"] = DDLLanguages.SelectedValue;
// Reload-hack. Was recommended on SO.
Response.Redirect(Request.Url.AbsolutePath);
}
}
After all of this, there one more point where the session variable is used as read-only: I'm using a header to tell my server that the client's using xyz language and that server should return translated data, where applicable:
public class CustomInspectorBehavior : IClientMessageInspector, IEndpointBehavior
{
#region IClientMessageInspector
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
string languageIdentifier;
if (HttpContext.Current.Session["UserLanguage"] != null)
{
languageIdentifier = HttpContext.Current.Session["UserLanguage"].ToString();
}
else
{
languageIdentifier = CultureInfo.CurrentCulture.ToString();
}
var typedHeader = new MessageHeader<string>(languageIdentifier);
var untypedHeader = typedHeader.GetUntypedHeader("LanguageIdentifier", "");
request.Headers.Add(untypedHeader);
return null;
}
#endregion
#region IEndpointBehavior
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
var inspector = new CustomInspectorBehavior();
clientRuntime.MessageInspectors.Add(inspector);
}
#endregion
}
Results Expected: I change the selected value on the drop-down and the page reload with new language + secure the selection in session. Now upon going to other pages, the new language is presented.
Actual: "LOL". I change the selected value from the default en-US to ur-PK and the web site updates to Urdu. All pages are in Urdu. I try to select en-US again and I realize I'm stuck with Urdu. The base page's InitializeCulture()
trigger way too early and it finds Session["UserLanguage"] = ur-PK'. After that the
Page_Loadof the
PublicLogOnpage triggers effectively putting Drop down's selected value to still ur-PK. After that
DDLLanguages_SelectedIndexChangedof the
PublicLogOn` page triggers updating the session variable to the selected value which is set to ur-PK from the recent PageLoad. Issue. The Hack triggers in the end repeating the cycle one more time.
I'm trying a number of things but end in this mini-loop. Any help will be appriciated.
I re-did the whole thing from scratch. Turns out there was one or two variables being static at IIS level which were the cause of all the pain.