Thursday, January 31, 2013

c# - Edit,Update Resource files in a Multilingual Site programmatically

There are a lot of third party content management tools available.(See here http://www.webdesignerdepot.com/2011/10/top-10-content-management-systems/ ).
Recently I have been tasked with a rewrite of some of my company's websites, that is used by millions of people.The old sites use xml,xslt for content management and multiple language support

One of the requirements was to provide the team that managed the content for the sites, the flexibility to edit the content on the fly for any of the language supported by the site. This would also reduce the need for developers to spend time editing content on the sites.

My first goal is to build a simple site with few content pages.I am using ASP.Net Localization feature for this sample.

Below is structure of the sample project that I have.The site has two content pages i.e. Home.aspx and About.aspx.The site will have the feature to display to the content in 3 different languages i.e German (de),Spanish (es) and English as default.I have added resource files for each page and each langauge
Home.aspx.resx (English),Home.aspx.de.resx(German),Home.aspx.es.resx(Spanish)
About.aspx.resx (English),About.aspx.de.resx(German),About.aspx.es.resx(Spanish)




The About.aspx.resx resource file is below.






In the next step I add a page that will allow to make the changes for the content in the resource files.I have added a page called Edit.aspx which will be available only for the team responsible for the content of the site.

The Edit.aspx page will list all the pages,languages supported in the site.Once the page,language is selected a dropdownlist will list all the resource keys. The user would then choose a resource key and on key selection the corresponding value(content) stored in the resource file will be shown in the RadEditor(Use a richtextbox to display the content).The save button will allow to rewrite the resource file.

Once the changes are made the content changes can be viewed Home,About pages.  


The source code for the Edit.aspx page is below

<%@ Page Language="C#" AutoEventWireup="true" ValidateRequest="false" CodeBehind="Edit.aspx.cs" MasterPageFile="~/Site.Master" Inherits="Sample.SupportForm" %>

<%@ Register Assembly="Telerik.Web.UI" Namespace="Telerik.Web.UI" TagPrefix="telerik" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <table width="100%" style="table-layout:fixed">
        <tr>
            <td><telerik:RadScriptManager ID="RadScriptManager1" runat="server">
</telerik:RadScriptManager>
                <asp:DropDownList ID="PagesDropDownList" runat="server" Width="133px" AutoPostBack="true">
                    <asp:ListItem Text="Home" Value="Home"></asp:ListItem>
                    <asp:ListItem Text="About" Value="About"></asp:ListItem>
                </asp:DropDownList>
            </td>
        </tr>
        <tr>
            <td>
                <asp:DropDownList ID="LangaugesDropDownList" runat="server" Width="133px" 
                    AutoPostBack="true" 
                    onselectedindexchanged="LangaugesDropDownList_SelectedIndexChanged">
                    <asp:ListItem Text="English" Value=""></asp:ListItem>
                    <asp:ListItem Text="EspaƱol" Value="es"></asp:ListItem>
                    <asp:ListItem Text="Deutsch" Value="de"></asp:ListItem>
                </asp:DropDownList>
            </td>
        </tr>
        <tr>
                <td>
                    <asp:DropDownList ID="ResourceKeyDropDownList" runat="server" Visible="false" 
                        AutoPostBack="true" AppendDataBoundItems="true" Height="23px" 
                        onselectedindexchanged="ResourceKeyDropDownList_SelectedIndexChanged" 
                        Width="300px">
                    </asp:DropDownList>
                </td>
        </tr>
        <tr>
            <td>
                <telerik:RadEditor ID="ResourceValueEditor" runat="server" Width="100%" 
                    Visible="False"></telerik:RadEditor>
            </td>
        </tr>
        <tr>
            <td>
                <asp:Button ID="SaveButton" runat="server" Text="Save" Visible="false" 
                    onclick="SaveButton_Click" />
            </td>
        </tr>
    </table>
</asp:Content>


The code behind for Edit.aspx

using System;
using System.Collections.Generic;
using System.Web.UI.WebControls;
using System.Resources;
using System.Collections;

namespace Sample
{
    public partial class SupportForm : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                ResourceKeyDropDownList.Visible = true;
                ResourceKeyDropDownList.Items.Clear();
                ResourceKeyDropDownList.Items.Add(new ListItem("Select", "Select"));

                string sPage = PagesDropDownList.SelectedValue;
                string sLanguage = LangaugesDropDownList.SelectedValue;
                SortedList<string, string> oKeyValue = new SortedList<string, string>();

                string sPath = Request.PhysicalApplicationPath + @"App_LocalResources\" + sPage + (string.IsNullOrEmpty(sLanguage) ? ".aspx.resx" : (".aspx." + sLanguage + ".resx"));

                using (ResXResourceReader oReader = new ResXResourceReader(sPath))
                {
                    IDictionaryEnumerator oResource = oReader.GetEnumerator();
                    while (oResource.MoveNext())
                        ResourceKeyDropDownList.Items.Add(new ListItem(oResource.Key.ToString(), oResource.Key.ToString()));
                }
            }
        }

        protected void LangaugesDropDownList_SelectedIndexChanged(object sender, EventArgs e)
        {
            ResourceKeyDropDownList.Visible = true;
            ResourceKeyDropDownList.Items.Clear();
            ResourceKeyDropDownList.Items.Add(new ListItem("Select", "Select"));

            string sPage = PagesDropDownList.SelectedValue;
            string sLanguage = LangaugesDropDownList.SelectedValue;
            SortedList<string,string> oKeyValue = new SortedList<string,string>();

            string sPath = Request.PhysicalApplicationPath + @"App_LocalResources\" + sPage + (string.IsNullOrEmpty(sLanguage) ? ".aspx.resx" : (".aspx." + sLanguage + ".resx"));
            
            using (ResXResourceReader oReader = new ResXResourceReader(sPath))
            {
                IDictionaryEnumerator oResource = oReader.GetEnumerator();
                while (oResource.MoveNext())
                    ResourceKeyDropDownList.Items.Add(new ListItem(oResource.Key.ToString(), oResource.Key.ToString()));
            }
        }

        protected void ResourceKeyDropDownList_SelectedIndexChanged(object sender, EventArgs e)
        {
            string sResourceKey = ResourceKeyDropDownList.SelectedValue;
            if (!(string.IsNullOrEmpty(sResourceKey) || sResourceKey == "Select"))
            {
                ResourceValueEditor.Visible = true;
                SaveButton.Visible = true;

                string sPage = PagesDropDownList.SelectedValue;
                string sLanguage = LangaugesDropDownList.SelectedValue;

                string sPath = Request.PhysicalApplicationPath + @"App_LocalResources\" + sPage + (string.IsNullOrEmpty(sLanguage) ? ".aspx.resx" : (".aspx." + sLanguage + ".resx"));

                using (ResXResourceReader oReader = new ResXResourceReader(sPath))
                {
                    IDictionaryEnumerator oResource = oReader.GetEnumerator();
                    while (oResource.MoveNext())
                    {
                        if (oResource.Key.ToString() == sResourceKey)
                        {
                            ResourceValueEditor.Content = oResource.Value.ToString();
                            break;
                        }
                    }
                }
            }
            else
            {
                ResourceValueEditor.Visible = false;
                SaveButton.Visible = false;
            }
        }

        protected void SaveButton_Click(object sender, EventArgs e)
        {
            string sResourceKey = ResourceKeyDropDownList.SelectedValue;
            string sPage = PagesDropDownList.SelectedValue;
            string sLanguage = LangaugesDropDownList.SelectedValue;
            
            Hashtable oHt = new Hashtable();

            string sPath = Request.PhysicalApplicationPath + @"App_LocalResources\" + sPage + (string.IsNullOrEmpty(sLanguage) ? ".aspx.resx" : (".aspx." + sLanguage + ".resx"));
             using (ResXResourceReader oReader = new ResXResourceReader(sPath))
                {
                    IDictionaryEnumerator oResource = oReader.GetEnumerator();
                    while (oResource.MoveNext())
                        oHt.Add(oResource.Key,oResource.Value);
                }

            oHt[sResourceKey] = ResourceValueEditor.Content;

            using (ResXResourceWriter oWriter = new ResXResourceWriter(sPath))
            {
               
                foreach (string key in oHt.Keys)
                    oWriter.AddResource(key.ToString(), oHt[key].ToString());
                oWriter.Generate();
            }
        }
    }
}





No comments: