My Cart (0)  |  My Orders  |  My Downloads  |  My Auction  |  My Account  |  Help


Login |Register        Search

Creating multilanguage enabled DNN modules

                Print      Add To Favorite     Add To Watch List     Contact Author

Creator: host   7/7/2015 11:34:53 PM    Author: Torsten Weggen   Source: http://www.bitboxx.net   Views: 2350    0    0  
Tags:
Module develop Dnn development Content Localization Dnn Tutorial

If you want to create your modules for an international audience you must be aware of maintaining different languages. This is no problem for static content because DNN has his concept of resource files, which is very easy to handle. But when it comes to dynamic data like product information in an ecommerce module, you have to handle this in the database. This is no problem at all but which is the best way of entering these different language information in your edit-control ?

Building the UI in the edit control

We build our language entering control with the help of a formview control which is set to edit mode. The HeaderTemplate has a placeholder inside where the flags for the different portal languages are rendered. The EditItemTemplate holds all the Controls we need to save for every language:

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<asp:formview id="formViewLang" runat="server" allowpaging="false" defaultmode="Edit" onitemcreated="formViewLang_ItemCreated" cssclass="grdCartRow">
<headertemplate>
<edititemtemplate>
</edititemtemplate><footertemplate>
</footertemplate><table border="0" cellpadding="2" cellspacing="0">
<tbody><tr>
<td class="SubHead"><dnn:label id="lblLanguage" runat="server" suffix=":"></dnn:label> </td>
<td><span style="border-bottom: 1px solid; border-width: 1px; vertical-align: bottom;">
</span>
<asp:placeholder id="phLanguage" runat="server"></asp:placeholder>
<span style="border-bottom: 1px solid; border-width: 1px; text-align: left; vertical-align: bottom;">
</span>
</td>
</tr>
<tr>
<td style="width: 200px;" class="SubHead" valign="top"><dnn:label id="lblName" runat="server" controlname="txtName" suffix=":"></dnn:label> </td>
<td><asp:textbox id="txtName" runat="server" columns="40" text="<%# Bind("Name") %>"></asp:textbox> </td>
</tr>
<tr>
<td style="width: 200px;" class="SubHead" valign="top"><dnn:label id="lblName" runat="server" controlname="txtName" suffix=":"></dnn:label> </td>
<td><asp:textbox id="txtShort" runat="server" text="<%# Bind("ShortDescription") %>" columns="40" textmode="MultiLine" rows="2" maxlength="80"></asp:textbox> </td>
</tr>
<tr>
<td style="width: 200px;" class="SubHead" valign="top"><dnn:label id="lblContent" runat="server" controlname="txtContent" suffix=":"></dnn:label> </td>
<td> <dnn:texteditor id="txtContent" runat="server" height="600" width="500" htmlencode="false" text="<%# Bind("ProductDescription") %>"></dnn:texteditor> </td>
</tr>
</tbody></table>
</headertemplate>
</asp:formview>

DataBase Implementation

For every table xyz which has language related information, you need to create an additional “xyzLang” table which holds the translated strings for every language. Common information, which is equal for every language like itemno or price is stored in the main table.

The Language field in the xyzLang table contains the 5 letter ISO code for the language (eg. en-US, de-DE)

 image

Furthermore, we need the DAL implementation :

1.) Info class for the Lang-Tabelle:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[Serializable()]
public class ProductLangInfo
{
public ProductLangInfo()
{
ProductId = -1;
Language = "";
ProductDescription = "";
ShortDescription = "";
Name = "";
}
public int ProductId { get; set; }
public string Language { get; set; }
public string ProductDescription { get; set; }
public string ShortDescription { get; set; }
public string Name { get; set; }
}

2.) The CRUD-Methods:

1
2
3
public abstract IDataReader GetProductLangs(int ProductId);
public abstract void NewProductLang(ProductLangInfo ProductLang, string Language);
public abstract void DeleteProductLangs(int ProductId);

(This is shown here only as abstract definition. The implementation should be no problem for you Zwinkerndes Smiley )

CodeBehind

Properties:

We need a property ProductLangs. Within this property, we save all the language related values in viewstate to persist information between postbacks.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public List<productlanginfo> ProductLangs
{
get
{
if (ViewState["ProductsLang"] != null)
return (List<productlanginfo>)ViewState["ProductsLang"];
else
return new List<productlanginfo>();
}
set
{
ViewState["ProductsLang"] = value;
}
}</productlanginfo></productlanginfo></productlanginfo>

Page_Load:

Starting the page life cycle we first create a List and add one element for every portal language:

1
2
3
4
5
6
7
8
Dictionary<string,> loc = Localization.GetLocales(PortalId);
List<productlanginfo> memLangs = new List<productlanginfo>();
foreach (KeyValuePair<string,locale>item in loc)
{
ProductLangInfo li = new ProductLangInfo();
li.Language = item.Key;
memLangs.Add(li);
}</string,locale></productlanginfo></productlanginfo></string,>

Next we read all language records from database for a specific productId, fill all the values into our List and save the result to our Property ProductLangs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
List<productlanginfo> dbLangs = Controller.GetProductLangs(productId);
foreach (ProductLangInfo dbLang in dbLangs)
{
foreach (ProductLangInfo li in memLangs)
{
li.ProductId = dbLang.ProductId;
if (li.Language == dbLang.Language)
{
li.Name = dbLang.Name;
li.ProductDescription = dbLang.ProductDescription;
li.ShortDescription = dbLang.ShortDescription;
break;
}
}
}
SimpleProductLangs = memLangs;</productlanginfo>

Page_Prerender:

In Page_Prerender we databind the formview to our List property :

1
2
formViewLang.DataSource = SimpleProductLangs;
formViewLang.DataBind();

FormViewLang_ItemCreated:

When the FormViewLang is created, we look into DNN to get the portal languages. Then we search our PlaceHolder in the HeaderTemplate. For every portal language we create a new ImageButton-Control, add a litlle bit styling, the correspondig flag-gif and an ImageClickEventhandler. When a button is clicked, our method “Language_Selected” should be called. All created buttons are added to the Placeholder control.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
protected void formViewLang_ItemCreated(object sender, EventArgs e)
{
Dictionary<string,> loc = Localization.GetLocales(PortalId);
FormViewRow row = formViewLang.HeaderRow;
PlaceHolder phLanguage = row.FindControl("phLanguage") as PlaceHolder;
int i = 0;
foreach (KeyValuePair<string,> item in loc)
{
ImageButton imgBtn = new ImageButton();
imgBtn.ID = "imgLanguage" + i.ToString();
imgBtn.Click += new System.Web.UI.ImageClickEventHandler(Language_Selected);
imgBtn.ImageUrl = "~\\images\\Flags\\" + item.Key + ".gif";
imgBtn.Style.Add("padding", "3px 10px 5px 10px");
imgBtn.Style.Add("border-width", "1px");
imgBtn.Style.Add("border-color", "#000000");
imgBtn.Style.Add("margin", "0 px");
if (i == formViewLang.PageIndex)
{
imgBtn.Style.Add("border-style", "solid solid none solid");
imgBtn.Style.Add("background-color", "White");
}
else
{
imgBtn.Style.Add("border-style", "solid solid solid solid");
}
phLanguage.Controls.Add(imgBtn);
i++;
}
}</string,></string,>

Language_Selected:

When a flag button is clicked, we save all values from the EditItemTemplate in our List property. Then we change the PageIndex of the Formview to the selected language (We can determine the selected language ISO code from the name of the gif file)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected void Language_Selected(object sender, System.Web.UI.ImageClickEventArgs e)
{
TextBox txtName = formViewLang.FindControl("txtName") as TextBox;
ProductLangs[formViewLang.PageIndex].Name = txtName.Text;
TextBox txtShort = formViewLang.FindControl("txtShort") as TextBox;
ProductLangs[formViewLang.PageIndex].ShortDescription = txtShort.Text;
TextEditor txtContent = formViewLang.FindControl("txtContent") as TextEditor;
ProductLangs[formViewLang.PageIndex].ProductDescription = txtContent.Text;
ImageButton btn = sender as ImageButton;
string url = btn.ImageUrl;
string language = url.Substring(url.LastIndexOf('\\') + 1);
language = language.Replace(".gif", "");
int i = 0;
foreach (ProductLangInfo li in ProductLangs)
{
if (li.Language == language)
{
formViewLang.PageIndex = i;
break;
}
i++;
}
}

cmdUpdate_Click:

When we leave the edit control with the help of an update button, we have to save all language information in the database. Easiest way is to delete all language information first and then store everything new (so you don’t have to deal with inserts,updates and deletes). Don't forget to read out the latest information from your control in your property before saving (see Language_Selected):

1
2
3
4
5
6
Controller.DeleteProductLangs(productId);
foreach (ProductLangInfo si in ProductLangs)
{
si.ProductId = productId;
Controller.NewProductLang(si, si.Language);
}

Hope I could have helped you with this. Comments, corrections and advancements are appreciated!


Rating People: 0   Average Rating:     

     DnnModule.com is built to provide DNN quality modules and DNN skins, some of them are free, some not. We wish these stuffs (free or not ) can be useful to you.

     Besides that, we also provide a full range of professional services, ranging from web site build, seo, system management, administration, support, senior consultancy and security services. We act as if your development project or network was ours, with care and respect. We are not satisfied until it works the way you want it to, and we don't silently ignore found issues as somebody else's problem.