<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8796582083368239187</id><updated>2024-09-05T09:58:54.585-04:00</updated><category term="ASP.Net"/><category term="DNN"/><category term="Localization"/><category term="RTL Layout"/><category term="DotNetNuke"/><category term="SXA"/><category term="Sitecore"/><category term="Sitecore experience accelerator"/><title type='text'>Michael Saleeb Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://michaelfayez.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://michaelfayez.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/16252645336692523661</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>7</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8796582083368239187.post-505653911112280631</id><published>2016-12-13T12:58:00.001-05:00</published><updated>2016-12-13T12:58:10.927-05:00</updated><title type='text'>Sitecore SSO Part 2</title><content type='html'>This is the second article of the SSO blog posts. You can find the first one &lt;a href=&quot;http://bit.ly/2gx9Zcf&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;h2&gt;
Sharing Authentication cookie across 2 Sitecore instances:&lt;/h2&gt;
&lt;/div&gt;
&lt;div&gt;
As I mentioned in my first post, we now want to share the authentication cookie across 2 different sitecore instances (6.5 and 8.1)&lt;/div&gt;
&lt;div&gt;
Sitecore 8.1 and 6.5 behave differently when dealing with authentication.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
Both use 2 cookies for authentication&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;.ASPXAUTH (name specified in web.config)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;sitecore_userticket&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Every version deals with authentication cookie in a different way&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;Sitecore 6.5: When user logs in, both cookies are created. It only uses the .ASPXAUTH cookie for authentication. If you delete or modify the content of sitecore_userticket cookie using a browser plugin, it will not be regenerated. Sitecore is not affected if you modify the content of sitecore_userticket&amp;nbsp; cookie&lt;/li&gt;
&lt;li&gt;Sitecore 8.1: When user logs in, both cookies are created. It only uses sitecore_userticket cookie for authentication. If it is missing or modified, then you are considered logged out even if you have the other cookie. sitecore_userticket content is different than Sitecore 6.5 cookie. So sharing it won&#39;t make logged in users in Sitecore 6.5 logged in Sitecore 8.1. &amp;nbsp;.ASPXAUTH cookie can be deleted safely and it will be recreated with every request. You will get an ASP.Net Exception though, if you modify the content of the .ASPXAUTH cookie.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
To summarize&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;sitecore_userticket: Different across versions. Important only for Sitecore 8.1&amp;nbsp;&lt;/li&gt;
&lt;li&gt;.ASPXAUTH: Same across versions. Important only for Sitecore 6.5&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
The solution I implmented to solve this was:&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;Share .ASPXAUTH cookie across instances as both have the same top domain&lt;/li&gt;
&lt;li&gt;Recreate the sitecore_userticket&amp;nbsp;in Sitecore 8.1 if .ASPXAuth cookie exists.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
Sharing .ASPXAUTH cookie:&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
You will have to share the same machine key specified in the web.config in &lt;b&gt;BOTH&amp;nbsp;&lt;/b&gt;sites:&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;lt;machineKey validationKey=&quot;xxxxxxxxxxxxxxx&quot; &amp;nbsp;decryptionKey=&quot;xxxxxxxxxx&quot; validation=&quot;SHA1&quot; decryption=&quot;AES&quot; /&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
Make the Authentication cookie domain the top domain used by &lt;b&gt;BOTH&amp;nbsp;&lt;/b&gt;instances&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;lt;authentication mode=&quot;None&quot;&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;lt;forms name=&quot;.ASPXAUTH&quot; cookieless=&quot;UseCookies&quot; domain=&quot;&lt;span style=&quot;background-color: yellow;&quot;&gt;[Your top domain here]&lt;/span&gt;&quot;/&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;lt;/authentication&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;
Recreating sitecore_userticket &amp;nbsp;Cookie:&lt;/h3&gt;
&lt;div&gt;
I modified a solution is specified &lt;a href=&quot;http://bit.ly/2gWozes&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;. The solution specified in the link is good to share the ticket between 2 instances of the same version. In this case sharing the cookie is enough between the domains. But as the content of the cookie is not the same across the old and new versions of sitecore, we have to regenerate it again by adding the code below in the Global.asax file in the &lt;b&gt;NEW &lt;/b&gt;sitecore instance. (This was a question I asked on stack exchange &lt;a href=&quot;http://bit.ly/2gwQaSI&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;)&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;protected void Application_EndRequest(object sender, EventArgs e)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; var authCookie = HttpContext.Current.Response.Cookies[&quot;sitecore_userticket&quot;];&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; if (!Request.IsAuthenticated || authCookie == null)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // when checking response cookies, cookie is created if not exists, so delete now&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; HttpContext.Current.Response.Cookies.Remove(&quot;sitecore_userticket&quot;);&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; //we don&#39;t need to make it cross domain as it will be different for every instance&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; //due to version differences.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; //create the ticket cookie. Every Sitecore instance will generate it the way it expects.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; authCookie.Value = TicketManager.CreateTicket(HttpContext.Current.User.Identity.Name, string.Empty);&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4&gt;
&lt;b&gt;Conclusion:&lt;/b&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
Now you will have the sign on shared across the 2 versions. This solution may still have some minor issues but all the major challenges are fixed.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://michaelfayez.blogspot.com/feeds/505653911112280631/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://michaelfayez.blogspot.com/2016/12/sitecore-sso-part-2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/505653911112280631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/505653911112280631'/><link rel='alternate' type='text/html' href='http://michaelfayez.blogspot.com/2016/12/sitecore-sso-part-2.html' title='Sitecore SSO Part 2'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/16252645336692523661</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8796582083368239187.post-4587599078367881074</id><published>2016-12-13T12:54:00.002-05:00</published><updated>2016-12-13T12:56:31.725-05:00</updated><title type='text'>Sitecore SSO Part 1</title><content type='html'>&lt;h3&gt;
&lt;span style=&quot;background-color: yellow;&quot;&gt;This blog post is about SSO across 2 different instances of Sitecore while sharing the same top domain i.e. cookies can be shared across the 2 instances and both instances can access the same DB&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
I was recently tasked with implementing SSO across two different sitecore sites that are sharing the same top domain. Every instance has different version (8.1 and 6.5) and every instance has its own (core/master/web) databases.&lt;/div&gt;
&lt;div&gt;
To implement SSO you will have to:&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;Share authentication/authorization/profiles info&lt;/li&gt;
&lt;li&gt;Share authentication cookie across sites&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
I am splitting them to 2 posts for the sake of clarity&lt;/div&gt;
&lt;h2&gt;
Sharing Authentication/Authorization/Profile info:&lt;/h2&gt;
&lt;/div&gt;
&lt;h4&gt;
Sharing Databases:&lt;/h4&gt;
&lt;div&gt;
Sitecore uses the normal ASP.Net tables schema and builds upon the membership/roles/profiles provider. These providers use core database by default as specified in the Web.Config. To be able to share this existing info, we will need to make changes to the configuration of the new site. So first we need to add a connection in App_Config\ConnectionStrings.config file in the new instance to point to the existing core database of the old site. Let&#39;s call this connection oldcore&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;lt;add name=&quot;oldcore&quot;
connectionString=&quot;&lt;span style=&quot;background-color: yellow;&quot;&gt;[old site core database connection string]&lt;/span&gt;&quot; /&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
Then we go to the web.config in the new site and point the profile/membership/roles tags to the new oldcore db. Changes are highlighted in yellow (I removed irrelevant configuration for clarity)&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;lt;membership defaultProvider=&quot;sitecore&quot;
hashAlgorithmType=&quot;SHA1&quot;&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;providers&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;clear /&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; .....&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;add
name=&quot;sql&quot; type=&quot;System.Web.Security.SqlMembershipProvider&quot;
connectionStringName=&quot;&lt;span style=&quot;background: yellow; mso-highlight: yellow;&quot;&gt;oldcore&lt;/span&gt;&quot;.... /&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;.........&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/providers&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/membership&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;roleManager
defaultProvider=&quot;sitecore&quot; enabled=&quot;true&quot;&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;providers&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;clear /&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;........&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;add
name=&quot;sql&quot; type=&quot;System.Web.Security.SqlRoleProvider&quot;
connectionStringName=&quot;&lt;span style=&quot;background: yellow; mso-highlight: yellow;&quot;&gt;oldcore&lt;/span&gt;&quot;
applicationName=&quot;sitecore&quot; /&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .......&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/providers&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/roleManager&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;lt;profile defaultProvider=&quot;sql&quot;
enabled=&quot;true&quot; inherits=&quot;Sitecore.Security.UserProfile,
Sitecore.Kernel&quot;&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;providers&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;clear /&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;add
name=&quot;sql&quot; type=&quot;System.Web.Profile.SqlProfileProvider&quot;
connectionStringName=&quot;&lt;span style=&quot;background: yellow; mso-highlight: yellow;&quot;&gt;oldcore&lt;/span&gt;&quot;
applicationName=&quot;sitecore&quot; /&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .....&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/providers&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; .........&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/profile&amp;gt;&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
This way we only shared the needed info not the whole core database which wouldn&#39;t have worked due to version differences&lt;/div&gt;
&lt;h4&gt;
Sharing Domains and User Profiles:&lt;/h4&gt;
&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJyKHWXFZ1UuBVT3y6m2nVZAo0Ptz65g8E5Eui5_e9NqWXczoqVLveZcWOw7DL86eAg651Sh9OtNkmgNcOdqcT3SYgPKqHiQymK-F01PaRC_74LgZT2M8YSOr1q2BMuFpAJrC54MlAyFc/s1600/12.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJyKHWXFZ1UuBVT3y6m2nVZAo0Ptz65g8E5Eui5_e9NqWXczoqVLveZcWOw7DL86eAg651Sh9OtNkmgNcOdqcT3SYgPKqHiQymK-F01PaRC_74LgZT2M8YSOr1q2BMuFpAJrC54MlAyFc/s1600/12.png&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Domains and User profiles in the add user dialog (sitecore 6.5). Client specific info obscured&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Domains info are saved in the file&amp;nbsp;App_config\security\domains.config. So this will need to be copied over to the new instance.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
Custom user profiles templates are in the core db in the folder:&amp;nbsp;/sitecore/templates/System/Security&lt;/div&gt;
&lt;div&gt;
The user profile items themselves are in the core db in the folder&amp;nbsp;/sitecore/system/Settings/Security/Profiles&lt;/div&gt;
&lt;div&gt;
The easiest way to copy the templates and the items over to the new instance is to create a sitecore package and install them in the new instance.&lt;/div&gt;
&lt;h4&gt;
&lt;b&gt;Profiles Versions incompatibility:&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;div&gt;
Due different versions Profiles modified in Sitecore 8.1 cannot be loaded in Sitecore 6.5. While profiles created in Sitecore 6.5 are loaded in Sitecore 8.1&lt;/div&gt;
&lt;div&gt;
The solution for this was hacky. I had to decompile the new&amp;nbsp;Sitecore.Security.UserProfile from Sitecore 8.1 Sitecore.Kernel.dll and then create in a project in the old sitecore version and then inherit from UserPorfile class in the Sitecore 6.5 Sitecore.Kernel.dll. Then fix all compilation error and remove all the properties the already exist in the old class&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;namespace UserProfile&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;public class UserProfile : Sitecore.Security.UserProfile&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;{&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;.......&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
and then you will need to modify the web.config in the old Sitecore to be&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&amp;lt;profile defaultProvider=&quot;sql&quot; enabled=&quot;true&quot; inherits=&quot;&lt;span style=&quot;background-color: yellow;&quot;&gt;UserProfile.UserProfile, UserProfile&lt;/span&gt;&quot;&amp;gt;&lt;/div&gt;
&lt;div&gt;
I removed some redundant code but didn&#39;t go and spend much time to remove as much as possible of redundant code (You can find it &lt;a href=&quot;http://pastebin.com/MPycTxKE&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;). You can optimize this part. But currently this code allowed Sitecore 6.5 to load profiles modified in Sitecore 8.1&lt;/div&gt;
&lt;div&gt;
Also there is another problem of caching in each instance where the user profile will load from cache so you will need to reload the profile every time you deal with it.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h4&gt;
&lt;b&gt;Conclusion:&lt;/b&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;div&gt;
Now both sitecore instances share the same login and now we all we need is to share the authentication cookie.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://michaelfayez.blogspot.com/feeds/4587599078367881074/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://michaelfayez.blogspot.com/2016/12/sitecore-sso-part-1.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/4587599078367881074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/4587599078367881074'/><link rel='alternate' type='text/html' href='http://michaelfayez.blogspot.com/2016/12/sitecore-sso-part-1.html' title='Sitecore SSO Part 1'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/16252645336692523661</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJyKHWXFZ1UuBVT3y6m2nVZAo0Ptz65g8E5Eui5_e9NqWXczoqVLveZcWOw7DL86eAg651Sh9OtNkmgNcOdqcT3SYgPKqHiQymK-F01PaRC_74LgZT2M8YSOr1q2BMuFpAJrC54MlAyFc/s72-c/12.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8796582083368239187.post-6137053780722669756</id><published>2016-10-12T13:48:00.002-04:00</published><updated>2016-10-12T13:48:16.112-04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Sitecore"/><category scheme="http://www.blogger.com/atom/ns#" term="Sitecore experience accelerator"/><category scheme="http://www.blogger.com/atom/ns#" term="SXA"/><title type='text'>Sitecore SXA first impressions</title><content type='html'>&lt;h3&gt;
First Impressions&lt;/h3&gt;
When I started working with Sitecore CMS, one of the most confusing parts was the lack pre-built components for simple stuff like adding page content, Facebook comments. This was due to my background in DotNetNuke what comes with lots of first party modules to be used out of the box, I assumed this would be the case with Sitecore. It is the case now with the introduction of Sitecore experience accelerator (SXA).&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
What is Sitecore Experience Accelerator (SXA)?&lt;/h3&gt;
&lt;div&gt;
SXA is a set of re-usable templates and components that allows you to get your website quickly up and running. In order to achieve this goal SXA has these types out of the box:&lt;/div&gt;
&lt;div&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3CCWCeS5q06PCtLV45i626a49l9M1dyxMBwS8OMqmr_gOKeD6RWT_48xLnnc7s1d7KCHb0FtEyFBgSarmTUrhty3EEtDQDuhvNb00fouZD1hDsXcKoNN7P61SUYCImA-xeZ9AR3xoLTM/s1600/SXA+components.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;640&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3CCWCeS5q06PCtLV45i626a49l9M1dyxMBwS8OMqmr_gOKeD6RWT_48xLnnc7s1d7KCHb0FtEyFBgSarmTUrhty3EEtDQDuhvNb00fouZD1hDsXcKoNN7P61SUYCImA-xeZ9AR3xoLTM/s640/SXA+components.png&quot; title=&quot;SXA Components&quot; width=&quot;185&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Part of SXA components&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Components&lt;/b&gt;: varies from content to composite to media components, etc. They all can be dragged and dropped on place holders. Some components can also host other placeholders (They automatically solve the problem of dynamic placeholders that exist in current Sitecore layouts. In existing projects we have a custom solution for this)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Partial Designs&lt;/b&gt;: Designs that are to be shared across different types of pages like copyright footer or a top menu or search box&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Page Designs&lt;/b&gt;: Designs that will be used across certain page templates. These designs have either page components or partial designs. There is a mapping between which template should use which page design in the ribbon of the experience editor. Of course you can add components directly on the page but page designs allows you to maintain consistency among all pages with the same template&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Rendering Variants&lt;/b&gt;: Allows the admin to create rendering variants of components that include both html and CSS changes.These variants can be selected in the experience editor in the properties of the component.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Creative Exchange Export/Import: &lt;/b&gt;Allows the admin to export the whole design to send it to web designers to modify the look and feel of HTML+CSS and the re-imported again to the website.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
From what I saw, SXA looks very promising with simple sites can be totally be done with little to no custom development. But from my experience, you will never know till you use SXA in a real life project.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h3&gt;
Important links:&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
SXA at the time of writing is version 1.1 and requires either Sitecore 8.1 or 8.2.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Prerequisites:&lt;/b&gt;&amp;nbsp;&lt;a href=&quot;http://bit.ly/2dWxNau&quot; target=&quot;_blank&quot;&gt;Sitecore powershell extensions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Download and release information&lt;/b&gt;: &lt;a href=&quot;http://bit.ly/2e1AFBR&quot; target=&quot;_blank&quot;&gt;SXA version 1.1&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://bit.ly/2dL6akS&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;SXA documentation&lt;/b&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;http://bit.ly/2e9CDRs&quot; target=&quot;_blank&quot;&gt;SXA Webinar&lt;/a&gt;: &lt;/b&gt;&lt;span style=&quot;background-color: yellow;&quot;&gt;This webinar is the best resource I found to demo the SXA capabilities. To view the recording, just enter your info and click Register&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3&gt;
License Considerations:&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
SXA requires extra license key &quot;Sitecore.SXA&quot;. This key is not in Sitecore license files generated before August,25th 2016. To be able to use SXA, you will need to get a sitecore license file that is generated after this date. Also this means extra money to be paid by the companies purchasing Sitecore.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
Final Thoughts and Questions:&lt;/h3&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;This is a really promising technology. It can reduce site development time and comes with lots of useful components out of the box.&lt;/li&gt;
&lt;li&gt;This is a new technology that involves some risk and learning curve to master.&lt;/li&gt;
&lt;li&gt;I was not able to make the export/import work as expected. I think I missed one of the steps.&lt;/li&gt;
&lt;li&gt;Custom development will be needed to meet your requirements that are not fulfilled by the existing SXA components but it is not mentioned in the webinar other than that we should inherit controllers from certain class. And it is not that clear from the documentation.&lt;/li&gt;
&lt;li&gt;I don&#39;t think we can limit the content of the toolbar depending on the template but I am not sure. This feature will be useful as we may need to limit content authors from adding certain components in certain templates&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://michaelfayez.blogspot.com/feeds/6137053780722669756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://michaelfayez.blogspot.com/2016/10/sitecore-sxa-first-impressions.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/6137053780722669756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/6137053780722669756'/><link rel='alternate' type='text/html' href='http://michaelfayez.blogspot.com/2016/10/sitecore-sxa-first-impressions.html' title='Sitecore SXA first impressions'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/16252645336692523661</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3CCWCeS5q06PCtLV45i626a49l9M1dyxMBwS8OMqmr_gOKeD6RWT_48xLnnc7s1d7KCHb0FtEyFBgSarmTUrhty3EEtDQDuhvNb00fouZD1hDsXcKoNN7P61SUYCImA-xeZ9AR3xoLTM/s72-c/SXA+components.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8796582083368239187.post-8068648855225541482</id><published>2010-01-30T19:13:00.001-05:00</published><updated>2010-01-31T20:20:38.287-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.Net"/><category scheme="http://www.blogger.com/atom/ns#" term="DNN"/><category scheme="http://www.blogger.com/atom/ns#" term="DotNetNuke"/><category scheme="http://www.blogger.com/atom/ns#" term="Localization"/><category scheme="http://www.blogger.com/atom/ns#" term="RTL Layout"/><title type='text'>Modified DNN with RTL support release</title><content type='html'>&lt;p&gt;As promised here the release of DNN version 5.02.01 modified to support RTL languages as a proof of concept of my suggestions. Here is a summary of modifications that are explained more in &lt;a href=&quot;http://michaelfayez.blogspot.com/2010/01/proposal-for-dnn-support-of-rtl-layout.html&quot; target=&quot;_blank&quot;&gt;Part 1&lt;/a&gt; &amp;amp; &lt;a href=&quot;http://michaelfayez.blogspot.com/2010/01/proposal-for-dnn-support-of-rtl-layout_22.html&quot; target=&quot;_blank&quot;&gt;Part 2&lt;/a&gt; for proposal to support RTL in DNN (without messing up the LTR layout). You can download this release from &lt;a href=&quot;http://cid-9269c74f7e8e207c.skydrive.live.com/self.aspx/.Public/ModifiedDotNetNuke^_Community^_05.02.01^_Source.zip&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;h4&gt;Release Notes&lt;/h4&gt;  &lt;h5&gt;1. API Changes&lt;/h5&gt;  &lt;ol&gt;   &lt;li&gt;Added read only property IsRightToLeft in Localization class to determine if the current culture is right to left. &lt;/li&gt;    &lt;li&gt;Added an extension method GetLabelModeString to LabelMode enumeration. When LabelMode is left and text direction is rtl the method returns right instead of left and when right the method returns left. If the text direction is left it has no effect when direction. This method should be used instead of ToString for supporting both LTR and RTL directions. This method returns string in lower case. &lt;/li&gt;    &lt;li&gt;Changed the PropertyGrid class to use the method described in point 2 above instead of using ToString method. &lt;/li&gt;    &lt;li&gt;Changed the behavior of AddStyleSheet in CDefault class to check the existance of RTL files and inculde them along side the normal CSS file in case of RTL culture. For example if AddStyleSheet is called to add file x.css, it will check for existance of x.rtl.css and include it if exists and RTL culture. &lt;/li&gt;    &lt;li&gt;Added dnn.direction() method in dnn.js. It returns rtl in case direction is RTL. &lt;/li&gt; &lt;/ol&gt;  &lt;h5&gt;2. Changes in WebSite&lt;/h5&gt;  &lt;ol&gt;   &lt;li&gt;Added RTL CSS files according to point 4 above. &lt;/li&gt;    &lt;li&gt;Fixed calculations for Menu absolute positioning in dnn.controls.dnnmenu.js &lt;/li&gt;    &lt;li&gt;Fixed layout of Search controls in Search.js file. (background-image is always aligned left in CSS. In case of RTL direction, it needs to aligned right using background-position. &lt;/li&gt;    &lt;li&gt;Numerous fixes in the website to support both RTL and LTR layout. You can find them by searching through the solution for Modified By Michael Fayez in the code. &lt;/li&gt;    &lt;li&gt;Added the changes suggested &lt;a href=&quot;http://www.dotnetnuke.com/Community/Forums/tabid/795/forumid/77/threadid/300971/scope/posts/Default.aspx&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; for adding rtl/ltr plugin to FCK editor (with slight modifications).&lt;/li&gt;    &lt;li&gt;I didn’t use CSS flipping as it didn’t work on Opera. I used flipped images from the original ones when needed. &lt;/li&gt; &lt;/ol&gt;  &lt;h5&gt;3. Notes&lt;/h5&gt;  &lt;ol&gt;   &lt;li&gt;The attached file is only a proof of concept and is not supported by any means. &lt;/li&gt;    &lt;li&gt;I don’t claim any copyright for these modifications. (Thanking me would be nice).&amp;#160; &lt;/li&gt;    &lt;li&gt;The RTL modification of default skin could be better by flipping images of borders to have the shadows mirrored. Though the current solution passes. &lt;/li&gt;    &lt;li&gt;Only default skin and default menu are fixed. &lt;/li&gt;    &lt;li&gt;In some places like breadcrumb, the layout looks not mirrored in RTL mode this is because of flow direction of English in an RTL language the layout would be mirrored automatically. So this is not an issue at all. &lt;/li&gt;    &lt;li&gt;I didn&#39;t make any modifications to the core modules of DNN. They need to be checked one by one to fix them. I know that there are problems in forum module in RTL. The repository module layout engine uses a single template from html file per module which may not be adequate in case of supporting both direction LTR and RTL and so on. &lt;/li&gt;    &lt;li&gt;I don’t guarantee nor know if the DNN team would embrace these changes or supporting RTL layout. (Currently they fix RTL issues one by one without resolving to the root cause of the problem). &lt;/li&gt;    &lt;li&gt;This release is not thoroughly tested. My changes may cause bugs in some scenarios unknown to me. &lt;/li&gt;    &lt;li&gt;I only changed the pages and controls that made the layout wrong in the pages i visited while testing. I didn’t fix ALL DNN user controls with hardcoded alignments. &lt;/li&gt;    &lt;li&gt;This code is not upgradable. When I started working on modifying DNN for RTL, latest DNN version was 5.02.01. Version 5.02.02 was released during my work. Copying the changes to the new version was too much to do. &lt;/li&gt;    &lt;li&gt;The RTL style is having some problems in IE 7 (and I assume IE 6 too), while working fine on other browsers. I don’t think this is a major issue for a proof of concept. &lt;/li&gt;    &lt;li&gt;The default theme for FCK editor has curved dotted end in its toolbars. They look ugly in RTL mode. They should be flipped but I didn’t try to find a solution for this. As a workaround you can use the sliver theme which has a straight dotted vertical line at the end of toolbars.&lt;/li&gt; &lt;/ol&gt;  &lt;h5&gt;4. Installation&lt;/h5&gt;  &lt;ol&gt;   &lt;li&gt;Set up DNN using the normal method. &lt;/li&gt;    &lt;li&gt;Copy the file portal.rtl.css from _default portal file to the folder of your created portals. (I didn’t find a way for the automatic copy of this file every time a new portal is created and didn’t want to spend more time in this point). &lt;strong&gt;&lt;u&gt;This is VERY important as without it the page won’t have direction:rtl style and all JavaScript calculations that depends on dnn.direction() will not work.&lt;/u&gt;&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;Add an RTL culture in languages page and compare the layouts of both RTL and LTR layouts by switching cultures using the flags in the top. &lt;/li&gt; &lt;/ol&gt;  &lt;h5&gt;&lt;/h5&gt;  &lt;h5&gt;5. Things to consider&lt;/h5&gt;  &lt;p&gt;I suggested that RTL CSS is loaded along the normal css. But this duplicates the number of CSS files loaded and download by browser in RTL layout as almost no CSS file is suitable for both LTR and RTL directions so it duplicates the overhead of downloading. The other solution would be that RTL CSS file is loaded instead of the normal CSS file and duplicate the normal CSS file styles while modifying it for RTL layout. Maybe this is a better solution and easily doable by modifying the attached code.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://michaelfayez.blogspot.com/feeds/8068648855225541482/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://michaelfayez.blogspot.com/2010/01/modified-dnn-with-rtl-support-release.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/8068648855225541482'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/8068648855225541482'/><link rel='alternate' type='text/html' href='http://michaelfayez.blogspot.com/2010/01/modified-dnn-with-rtl-support-release.html' title='Modified DNN with RTL support release'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/16252645336692523661</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8796582083368239187.post-1873788659245303352</id><published>2010-01-21T21:40:00.001-05:00</published><updated>2010-01-21T21:42:05.699-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.Net"/><category scheme="http://www.blogger.com/atom/ns#" term="DNN"/><category scheme="http://www.blogger.com/atom/ns#" term="Localization"/><category scheme="http://www.blogger.com/atom/ns#" term="RTL Layout"/><title type='text'>Proposal for DNN support of RTL layout Part 2</title><content type='html'>Please read the &lt;a href=&quot;http://michaelfayez.blogspot.com/2010/01/proposal-for-dnn-support-of-rtl-layout.html&quot; target=&quot;_blank&quot;&gt;first part&lt;/a&gt; of this post first to better understand this post.&lt;br /&gt;
In my first post, I didn’t speak about the number of RTL script language users. They are about 600 millions (300 million in Arabic states (including economically important Persian gulf states), 170 millions in Pakistan, 75 millions in Iran, 30 millions in Afghanistan, etc.). This makes about 10% of the human population use RTL scripts mostly using the Arabic script which is used for many languages not just Arabic. Hebrew script users are 5 millions. Thaana script users in Maldives are 350,000 users.I have no info about Syriac user community but I think they won&#39;t be more than 3 millions but not sure.&lt;br /&gt;
&lt;br /&gt;
I want also to clarify part of my previous post that maybe was not clear enough. The RTL CSS should override any property that affects horizontal direction not only float, text-align but also padding, margin, border any other property that affects the horizontal layout as in RTL layout it should be mirrored. &lt;br /&gt;
Now, I will continue explaining how to handle images and JavaScript in RTL layout.   &lt;br /&gt;
&lt;h4&gt;



Handling images in RTL mode&lt;/h4&gt;
&lt;h5&gt;



Usually images shouldn’t be horizontally flipped in RTL mode except:&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;Images that specifies horizontal direction. For example in the image below the required image should be flipped to point to the text box not to point to the empty space beside the empty textbox. &lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhj8I6umwDD4IDHPDXyYboqCLTdvzqhCL2xzgRJ1Qta1pwIBrN8nrJcBT7ECWtdBoejtf2vC1e3UYfmOiu70y3OQ-R57pelFU77q_aX9en0RhhA26UuACfN9nMuHAe-REQFBZJfboqBFB8/s1600-h/direction.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhj8I6umwDD4IDHPDXyYboqCLTdvzqhCL2xzgRJ1Qta1pwIBrN8nrJcBT7ECWtdBoejtf2vC1e3UYfmOiu70y3OQ-R57pelFU77q_aX9en0RhhA26UuACfN9nMuHAe-REQFBZJfboqBFB8/s320/direction.jpg&quot; /&gt;&lt;/a&gt;     &lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li value=&quot;2&quot;&gt;Images that are displayed in sequence horizontally as in RTL these images should be flipped to give the same effect. A real life example here is &lt;a href=&quot;http://www.dnnskins.com/free-skins.aspx?List=0&amp;amp;SortField=ProductName%2cProductName&amp;amp;ProductID=156&quot; target=&quot;_blank&quot;&gt;XDNewBlue&lt;/a&gt; skin. The skin is having messy layout in RTL mode because of its asymmetric layout. Here I will only show the container in RTL and LTR modes. The container header has 3 consecutive images which when rendered in reverse order were not correct. You will need to reverse second image to have the same layout of LTR flipped horizontally. In this case the image file is specified in a CSS file so the flipped image should be referenced in the RTL CSS file.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiysR3233vjt-Mp-d2FyQKRh47VnNtkww_OL_-p3pPMuRjhUfaQYdeQV93Pi8Rg-ATF_Qitw4HLIKfxCcdsNb8E4ra6cYfqSLIr6k1zOd7aUkVJTBBegxsxv00ah_iunzxBcZsUH0AUpN4/s1600-h/container.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiysR3233vjt-Mp-d2FyQKRh47VnNtkww_OL_-p3pPMuRjhUfaQYdeQV93Pi8Rg-ATF_Qitw4HLIKfxCcdsNb8E4ra6cYfqSLIr6k1zOd7aUkVJTBBegxsxv00ah_iunzxBcZsUH0AUpN4/s320/container.jpg&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;
&lt;h5&gt;



Images should be flipped either using:&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;Client side horizontal flipping: this way is done using flipping images using CSS and remove the need to having a separate mirrored image file. After doing some search, I found a solution &lt;a href=&quot;http://stackoverflow.com/questions/1309055/cross-browser-way-to-flip-image-via-javascript-css&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;. This solution is very good and would work by adding the CSS class below to the element to be flipped. This class should be empty in normal CSS and only having the text below in the RTL CSS file. Unfortunately this solution while it worked on Internet Explorer, Firefox, Safari and Chrome, it didn’t work on Opera browser. If you find any solution for Opera, please send it to me in comments. Please also note that if you apply this style to an element with text, the text will be mirrored which would not make it readable.&lt;/li&gt;
&lt;/ol&gt;
&lt;div style=&quot;background-color: #f4f4f4; border-bottom: silver 1px solid; border-left: silver 1px solid; border-right: silver 1px solid; border-top: silver 1px solid; cursor: text; direction: ltr; font-family: &#39;Courier New&#39;,courier,monospace; font-size: 8pt; height: 95px; line-height: 12pt; margin: 20px 0px 10px; max-height: 200px; overflow: auto; padding-bottom: 4px; padding-left: 4px; padding-right: 4px; padding-top: 4px; text-align: left; width: 80.66%;&quot;&gt;
.flip-horizontal {    &lt;br /&gt;
-moz-transform: scaleX(-1);     &lt;br /&gt;
-webkit-transform: scaleX(-1);     &lt;br /&gt;
transform: scaleX(-1);     &lt;br /&gt;
filter: fliph; /*IE*/ }     &lt;br /&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li value=&quot;2&quot;&gt;Server side flipping: A more trivial and cross browser way but will require a separate copy of every flipped image file. I suggest if the original image called x.jpg, the flipped one should be called x.rtl.jpg. This is just a naming convention and will not imply automatic loading. You will have to handle programmatically substituting images with flipped ones in case you detect the culture is RTL culture. &lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;



JavaScript files in RTL mode&lt;/h4&gt;
Usually JavaScript code don’t have problems with RTL layout. The catch here is that you should not specify any inline style properties in JavaScript files that affect horizontal layout as possible as you can. Use instead classes specified in CSS files, so they would be correct for both LTR and RTL layout or you will have to programmatically check for RTL and then reverse the style.   &lt;br /&gt;
&lt;h5&gt;



To determine the direction client side:&lt;/h5&gt;
According to &lt;a href=&quot;http://michaelfayez.blogspot.com/2010/01/proposal-for-dnn-support-of-rtl-layout.html&quot; target=&quot;_blank&quot;&gt;Part 1&lt;/a&gt; of this post direction propery is put in the portal.rtl.css file. So the only way to get this value in either use GetComputedStyle in Firefox or currentStyle for Internet Explorer. The function below is inspired from &lt;a href=&quot;http://www.howtocreate.co.uk/tutorials/javascript/domcss&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;. The code&amp;nbsp;should be put in js/dnn.js file.   &lt;br /&gt;
&lt;div style=&quot;background-color: #f4f4f4; border-bottom: silver 1px solid; border-left: silver 1px solid; border-right: silver 1px solid; border-top: silver 1px solid; cursor: text; direction: ltr; font-family: &#39;Courier New&#39;,courier,monospace; font-size: 8pt; height: 130px; line-height: 12pt; margin: 20px 0px 10px; max-height: 200px; overflow: auto; padding-bottom: 4px; padding-left: 4px; padding-right: 4px; padding-top: 4px; text-align: left; width: 80.66%;&quot;&gt;
dnn.direction = function() {    &lt;br /&gt;
if (typeof (dnn.__direction) == &quot;undefined&quot;) {     &lt;br /&gt;
var hElement = document.getElementsByTagName(&#39;html&#39;)[0];     &lt;br /&gt;
if (window.getComputedStyle)     &lt;br /&gt;
dnn.__direction = window.getComputedStyle(hElement, null).direction;     &lt;br /&gt;
else if (oElement.currentStyle)     &lt;br /&gt;
dnn.__direction = hElement.currentStyle.direction;     &lt;br /&gt;
}     &lt;br /&gt;
return dnn.__direction;     &lt;br /&gt;
}     &lt;br /&gt;
&lt;/div&gt;
&lt;h5&gt;



Explicit handling of RTL layout in JavaScript&lt;/h5&gt;
The only case I can think of now is handling absolute positioning set programmatically. Usually this is done in menus. Below the image of DNN menu in RTL layout   &lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0KDWq2-3fTKksS0mMWKUTA2YExCmKVzfrbySgOgFCja6n9UMArO5hTgibzeV2nCaDGcfbFDx-KmANoISclM4MNsbx0gB_TyfZXdNMHnksZQWUkAr6B1eKEEoyWbpucjxdjFRJ8FCJzl4/s1600-h/WrongMenuRTL.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0KDWq2-3fTKksS0mMWKUTA2YExCmKVzfrbySgOgFCja6n9UMArO5hTgibzeV2nCaDGcfbFDx-KmANoISclM4MNsbx0gB_TyfZXdNMHnksZQWUkAr6B1eKEEoyWbpucjxdjFRJ8FCJzl4/s320/WrongMenuRTL.jpg&quot; /&gt;&lt;/a&gt;     &lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
As the co-ordinates are not mirrored for RTL layout, the code adjusts the absolute position of menu to the left offset of the button. The solution here for RTL layout is if in RTL layout then it should position the menu = offsetLeft of button - menu width + offsetWidth of button and then the menu will look like the image below  &lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfsvp2o8GMhFrvcf4j7JOMTItWSPUEl0j40iW8x2oHyrGApgM_o3p1Qu4Zx5vuWbE54HOQlV7WHvgkHKFDs-yjawD67yxiEJihuBiueDV_Lk60fj9ktLJWFVZ_Q6Y1_5mRQmnXDSCt1cI/s1600-h/Correct+MenuRTL.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfsvp2o8GMhFrvcf4j7JOMTItWSPUEl0j40iW8x2oHyrGApgM_o3p1Qu4Zx5vuWbE54HOQlV7WHvgkHKFDs-yjawD67yxiEJihuBiueDV_Lk60fj9ktLJWFVZ_Q6Y1_5mRQmnXDSCt1cI/s320/Correct+MenuRTL.jpg&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;
&lt;h4&gt;



Catches:&lt;/h4&gt;
Real testing RTL layout should ALWAYS be done using an RTL script. In the screenshots above though text is aligned right but text itself is written from left to right which is not the case with RTL scripts (I took screenshots in English for simplicity). The RTL script is written from right to left. This text direction could affect in some cases the layout. For Example the image below is for Save/Cancel buttons are messed up because Latin script is written left to right regardless of alignment.  &lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhk7gNJRxwYtUNTgWxCQDLbLHXgegYLeQisWH1aDLVeUGCv5hGseV8trL4bkgnZSYbV6947hYVT7tKTbO8EgM6Er-xN-RFzqt9PspXWnN80ptwazCtP9ZIXrJieJ4lQ6peb8d8uNVTpDnI/s1600-h/WrongOrderRegisterCancel.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhk7gNJRxwYtUNTgWxCQDLbLHXgegYLeQisWH1aDLVeUGCv5hGseV8trL4bkgnZSYbV6947hYVT7tKTbO8EgM6Er-xN-RFzqt9PspXWnN80ptwazCtP9ZIXrJieJ4lQ6peb8d8uNVTpDnI/s320/WrongOrderRegisterCancel.jpg&quot; /&gt;&lt;/a&gt;    &lt;br /&gt;&lt;/div&gt;
As you see the save icon is beside cancel and the cancel icon is beside register. But when the text is really in RTL Arabic script, we see in the image below that everything is OK without doing any change.  &lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8T1tso9wj0IZqbcR9PtKR1IV2bao8zrIvApwS_sIRLix3eFuVo0NuzjhDW_Pg78FqqORhx835qhUAy7fXYKj1a1BMZ_YEz0uVb4oJKw5tBcRQsnJhy7Sx4nSwGN72UHTR-hTh3kiubno/s1600-h/CorrectRegisterCancel.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8T1tso9wj0IZqbcR9PtKR1IV2bao8zrIvApwS_sIRLix3eFuVo0NuzjhDW_Pg78FqqORhx835qhUAy7fXYKj1a1BMZ_YEz0uVb4oJKw5tBcRQsnJhy7Sx4nSwGN72UHTR-hTh3kiubno/s320/CorrectRegisterCancel.jpg&quot; /&gt;&lt;/a&gt;    &lt;br /&gt;&lt;/div&gt;
&lt;h4&gt;



Recommendations:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Changes to core DNN library and core modules should be done to handle both LTR and RTL layouts automatically.&lt;/li&gt;
&lt;li&gt;In &lt;a href=&quot;http://www.snowcovered.com/&quot; target=&quot;_blank&quot;&gt;snowcovered&lt;/a&gt; sold modules, there should be some info about if the displayed module is tested in RTL layout with the default to No.&lt;/li&gt;
&lt;li&gt;Every release of DNN or DNN core modules should be developed with RTL layout in mind and should be tested by a developer that knows a language that is written in RTL script ( There would be a lot of them especially Egyptians, Pakistanis and Israelis)&lt;/li&gt;
&lt;/ol&gt;
I didnt discuss the RTL localization of FCK editor. There is a post about it &lt;a href=&quot;http://www.dotnetnuke.com/Community/Forums/tabid/795/forumid/77/threadid/300971/scope/posts/Default.aspx&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;
Next week, I will publish the DNN code described here as a proof of concept.&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelfayez.blogspot.com/feeds/1873788659245303352/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://michaelfayez.blogspot.com/2010/01/proposal-for-dnn-support-of-rtl-layout_22.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/1873788659245303352'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/1873788659245303352'/><link rel='alternate' type='text/html' href='http://michaelfayez.blogspot.com/2010/01/proposal-for-dnn-support-of-rtl-layout_22.html' title='Proposal for DNN support of RTL layout Part 2'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/16252645336692523661</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhj8I6umwDD4IDHPDXyYboqCLTdvzqhCL2xzgRJ1Qta1pwIBrN8nrJcBT7ECWtdBoejtf2vC1e3UYfmOiu70y3OQ-R57pelFU77q_aX9en0RhhA26UuACfN9nMuHAe-REQFBZJfboqBFB8/s72-c/direction.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8796582083368239187.post-1089165759855812069</id><published>2010-01-14T20:25:00.000-05:00</published><updated>2010-01-21T20:28:06.659-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.Net"/><category scheme="http://www.blogger.com/atom/ns#" term="DNN"/><category scheme="http://www.blogger.com/atom/ns#" term="DotNetNuke"/><category scheme="http://www.blogger.com/atom/ns#" term="Localization"/><category scheme="http://www.blogger.com/atom/ns#" term="RTL Layout"/><title type='text'>Proposal for DNN support of RTL layout Part 1</title><content type='html'>&lt;a href=&quot;http://www.dotnetnuke.com/&quot; target=&quot;_blank&quot;&gt;DotNetNuke&lt;/a&gt; or (DNN in short) is an open source CMS that is built over ASP.Net. It is also extensible using modules providing a powerful programming platform. Unfortunately it has some issues with right to left (RTL) layout. In this blog post I am proposing the steps to be done in DNN to fully support RTL and LTR in the same portal out of the box.   &lt;h4&gt;For any CMS to fully support localization it needs:&lt;/h4&gt;  &lt;ol&gt;   &lt;li&gt;Static content localization: currently supported by DNN using Resx files and allows admins to modify them using the languages page in admin menu. admins can translate the resx files manually or just use a language pack if they can find a good and complete one. &lt;/li&gt;    &lt;li&gt;Dynamic content localization: DNN Corp is currently working on it. They put an infrastructure for dynamic content localization in version 5.2 but still not usable for the end-user. If you cannot wait for it to be complete you can use for example &lt;a href=&quot;http://magiccontent.codeplex.com/&quot; target=&quot;_blank&quot;&gt;Magic content&lt;/a&gt; instead of HTML module, &lt;a href=&quot;http://ealo.codeplex.com/&quot; target=&quot;_blank&quot;&gt;Ealo package&lt;/a&gt; for menu, breadcrumb localization and &lt;a href=&quot;http://nbstore.codeplex.com/&quot; target=&quot;_blank&quot;&gt;NBStore&lt;/a&gt; instead of DNN Store module. All these modules support dynamic content localization &lt;/li&gt;    &lt;li&gt;Right to left layout: for scripts that is written in right to left direction. Currently there is no official support for RTL in DNN. You will have to manually add in portal.css html {direction:rtl;} to make layout flipped. Most of the forms of DNN works good but some forms like login and manage profile don’t have a correct layout along with the default DNN menu in the default skin. Though the layout issue is not a blocking bug, it makes the layout looks wrong and amateurish for the end user. &lt;/li&gt; &lt;/ol&gt;  &lt;h4&gt;The scripts that uses right to left layout are:&lt;/h4&gt;  &lt;ol&gt;   &lt;li&gt;Arabic script: which is used for writing Arabic, Persian, Urdu, Punjabi, Sindhi, etc. &lt;/li&gt;    &lt;li&gt;Hebrew script: which is used for writing Hebrew and Jewish languages like Yiddish, Ladino, etc. &lt;/li&gt;    &lt;li&gt;Scripts that are used by minority languages that nobody knows or cares about: like &lt;a href=&quot;http://en.wikipedia.org/wiki/Thaana&quot; target=&quot;_blank&quot;&gt;Thaana&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Syriac&quot; target=&quot;_blank&quot;&gt;Syriac&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/N%27Ko&quot; target=&quot;_blank&quot;&gt;N&#39;Ko&lt;/a&gt;, etc. &lt;/li&gt; &lt;/ol&gt; Only Arabic and Hebrew scripts have economic value especially in the Persian Gulf area and in Israel.   &lt;br /&gt;  &lt;h4&gt;Root causes of messing up the RTL layout in web applications:&lt;/h4&gt;  &lt;ol&gt;   &lt;li&gt;In table cell alignment when a cell content is aligned left it remains aligned left event in RTL direction and when aligned right it remains aligned right in RTL direction. It should be mirrored. So when in a perfect world when i say when in RTL mode an html element is having      &lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 56.16%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; direction: ltr; height: 76px; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot;&gt;       &lt;p&gt;&amp;lt;table align=&amp;quot;left&amp;quot;&amp;gt;&lt;/p&gt;        &lt;br /&gt;&lt;/div&gt; it should align right and vice versa. unfortunately this is not the case.       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;When using float left and float right css styles, they behave like point 1      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;When assuming that images are displayed in specific order horizontally, this order is reversed in RTL mode. So some images will need to be flipped to look as good as in LTR mode (will give an example for this when discussing image RTL localization).      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;The absolute positioning always starts from top left of the page regardless of the direction of the page (RTL or LTR). Usually this affects absolute positioning when an html element is placed using calculated co-ordinates to align left with another element. In RTL mode you should update the calculation to align right(will give an example for this when discussing JavaScript RTL localization). &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;These four reasons made some great Javascript frameworks like &lt;a href=&quot;http://www.extjs.com&quot; target=&quot;_blank&quot;&gt;ExtJs&lt;/a&gt; unusable in RTL layout without much customization.     &lt;br /&gt;&lt;/p&gt; Though this is out of topic, Microsoft did a really good job on supporting RTL layout out of the box in&amp;#160; Windows forms. When a control is positioned using a left anchor in RTL layout it is positioned right though the anchor is still left. All of the standard windows forms controls behaves well in RTL mode. (though not all third party windows forms controls support RTL mode like &lt;a href=&quot;http://www.devexpress.com/&quot; target=&quot;_blank&quot;&gt;Devexpress&lt;/a&gt; for example but this is not the time to discuss this here)   &lt;br /&gt;  &lt;br /&gt;  &lt;h4&gt;Straightforward steps to make DNN portal have an RTL layout:&lt;/h4&gt;  &lt;ol&gt;   &lt;li&gt;modify portal.css and add &lt;/li&gt; &lt;/ol&gt;  &lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 58.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; direction: ltr; height: 68px; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot;&gt;   &lt;p&gt;html {direction:rtl;}&lt;/p&gt;    &lt;br /&gt;&lt;/div&gt;  &lt;ol&gt;   &lt;li&gt;Open ~/DesktopModules/AuthenticationServices/DNN/login.ascx and modify all table align=&amp;quot;left&amp;quot; to align=&amp;quot;right&amp;quot; and vice versa.      &lt;br /&gt;&lt;/li&gt; &lt;/ol&gt; Unfortunately the straight forward approach fails due to:   &lt;br /&gt;  &lt;ol&gt;   &lt;li&gt;Usually my customers want a multi lingual portal (English/Arabic) using dynamic content localization as described above. Adding the direction:rtl in portal.css will lead to displaying English language in RTL mode which is not correct.      &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;The default menu is still in LTR mode.&amp;#160; &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;The manage profile tab is messed up because of hardcoded style of text-align: left in Profile.ascx. (though the RTL issue is supposed to be &lt;a href=&quot;http://support.dotnetnuke.com/issue/ViewIssue.aspx?ID=7001&amp;amp;PROJID=2&quot; target=&quot;_blank&quot;&gt;resolved&lt;/a&gt; but apparently the developer that fixed it doesn’t know how RTL languages would look like because he left behind text-align: left which messed up the RTL layout) &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;So now we have a dead end for a trivial quick solution.&lt;/p&gt;  &lt;h4&gt;The good solution for the RTL problem:&lt;/h4&gt;  &lt;h5&gt;Requirements:&lt;/h5&gt;  &lt;ul&gt;   &lt;li&gt;The solution should fix the problem of RTL without messing the layout of the LTR languages on the same multi-lingual portal. &lt;/li&gt; &lt;/ul&gt;  &lt;h5&gt;&lt;/h5&gt;  &lt;h5&gt;Detecting RTL culture server side:&lt;/h5&gt;  &lt;p&gt;We need to detect the RTL language culture server side to do some actions for handling RTL layout as I will discuss later. The best way to do this is using Thread.CurrentThread.CurrentUICulture.TextInfo.IsRightToLeft property which is deeply buried in the properties of the properties of the properties of the current thread object.&lt;/p&gt;  &lt;p&gt;I suggest adding a shared/static readonly property to DotNetNuke.Services.Localization.Localization class to return the IsRightToLeft property&lt;/p&gt;  &lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 87%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; direction: ltr; height: 137px; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot;&gt;   &lt;p&gt;Public Shared ReadOnly Property IsRightToLeft() As Boolean      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Get       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Return Thread.CurrentThread.CurrentUICulture.TextInfo.IsRightToLeft       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; End Get       &lt;br /&gt;End Property&lt;/p&gt;    &lt;br /&gt;&lt;/div&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Handling the embedded styles in tags:&lt;/p&gt;  &lt;p&gt;After digging into the DNN code, I found an enumeration called DotNetNuke.UI.WebControls.LabelMode. this enumeration is used by the FieldEditorControl to display the register and the user profile control. Labels have the LabelMode left and controls have the LabelMode right. And then the FieldEditorControl calls the ToSring().ToLower() for the enumeration to get the text to embed in style left or right (these are the two properties we care about now for RTL layout). So the good news is that if we override the ToString() of the enumeration to render left property if not RTL then &amp;quot;left&amp;quot; else &amp;quot;right&amp;quot; and vice versa, all the forms that uses this control will be adjusted automatically without handling them case by case. The bad news is that there is no support for overriding ToString() method for enumerations :). So we will need an extension method to get label mode text and get the correct string according to text layout and this extension method should be used instead of ToString()&lt;/p&gt;  &lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 94.92%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; direction: ltr; height: 146px; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot;&gt;   &lt;p&gt;Public Module LabelModeHelper      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;Runtime.CompilerServices.Extension()&amp;gt; _       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Public Function GetLabelModeString(ByVal mode As LabelMode) As String       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; If mode &amp;lt;&amp;gt; LabelMode.Left AndAlso mode &amp;lt;&amp;gt; LabelMode.Right Then Return mode.ToString().ToLower()       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; If mode = LabelMode.Left Then       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Return If(Localization.IsRightToLeft, &amp;quot;right&amp;quot;, &amp;quot;left&amp;quot;)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; End If       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; If mode = LabelMode.Right Then       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Return If(Localization.IsRightToLeft, &amp;quot;left&amp;quot;, &amp;quot;right&amp;quot;)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; End If       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Return String.Empty       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; End Function       &lt;br /&gt;&amp;#160;&amp;#160; End Module&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;There remains another issue; handling LabelMode in RTL is &lt;a href=&quot;http://support.dotnetnuke.com/issue/ViewIssue.aspx?ID=7001&amp;amp;PROJID=2&quot; target=&quot;_blank&quot;&gt;fixed&lt;/a&gt; in three places Membership, Profile and User user controls. the same code is copy pasted 3 times in the user control. I write it here for convenience&lt;/p&gt;  &lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 96.03%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; direction: ltr; height: 147px; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot;&gt;   &lt;p&gt;Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &#39;Get the base Page       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Dim basePage As PageBase = TryCast(Me.Page, PageBase)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; If basePage IsNot Nothing Then       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &#39;Check if culture is RTL       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; If basePage.PageCulture.TextInfo.IsRightToLeft Then       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; UserEditor.LabelMode = LabelMode.Right       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Else       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; UserEditor.LabelMode = LabelMode.Left       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; End If       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; End If       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; End Sub&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;The code above is not based on a good design as it was written 3 times over and over again!!!! I commented it to make my code work as it would conflict with it. In my code I am trying to imitate the perfect case of Windows forms as I mentioned above. Thus developers would LabelMode.Left without bothering to think how it should be rendered in RTL mode.&lt;/p&gt;  &lt;p&gt;For styles embedded in ascx align=&amp;quot;left&amp;quot; or text-align:left, and also for right all these makes RTL layout looks odd. So all these should be deleted except if really needed and use the following code &amp;lt;%= LabelMode.Left.GetLabelModeString %&amp;gt; for hard coded part of &amp;quot;left&amp;quot; or move the embded alignments like float, text-align to CSS files which I will discuss now how to localize them.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;h5&gt;Handling CSS in RTL mode:&lt;/h5&gt;  &lt;p&gt;The CSS files would contain values of float:left , float:right, text-align:left, etc. These values should be reversed in RTL mode. The solution I propose here is to immitate ScriptManager control in ASP.Net for loading javascript files. For example when ScriptManager loads x.js file, if ASP.Net is in debug mode and there exists a file called x.debug.js, this file will be loaded instead of x.js which would be loaded in release mode.&lt;/p&gt;  &lt;p&gt;I suggest that all css would be optimized for LTR mode for example a file called x.css and if there is style in it that would make RTL looks odd, it would be overridden in another CSS file with the same name for example x.rtl.css&amp;#160; with the same classes but with only the parts that&amp;#160; make a conflict overridden and loaded only when the language is detected to have an RTL layout. So in this case of RTL language both files would be loaded unlike what the ScriptManager does.&lt;/p&gt;  &lt;p&gt;To achieve this we need to modify the code in the AddStyleSheet method in CDefault class in the core DNN library to check if:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;An RTL language is used for current culture &lt;/li&gt;    &lt;li&gt;and there exists a file with the same name of the CSS file being added to the page ending with .rtl.css &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;if both conditions are fulfilled then the .rtl.css class is loaded immediately after the file being added.&lt;/p&gt;  &lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 94.33%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; direction: ltr; height: 147px; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot;&gt;   &lt;p&gt;Public Sub AddStyleSheet(ByVal id As String, ByVal href As String, ByVal isFirst As Boolean)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &#39;Find the placeholder control       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Dim objCSS As Control = Me.FindControl(&amp;quot;CSS&amp;quot;) &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; If Not objCSS Is Nothing Then      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &#39;First see if we have already added the &amp;lt;LINK&amp;gt; control       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Dim objCtrl As Control = Page.Header.FindControl(id) &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; If objCtrl Is Nothing Then      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Dim objLink As New HtmlLink()       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objLink.ID = id       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objLink.Attributes(&amp;quot;rel&amp;quot;) = &amp;quot;stylesheet&amp;quot;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objLink.Attributes(&amp;quot;type&amp;quot;) = &amp;quot;text/css&amp;quot;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objLink.Href = href &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; If isFirst Then      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &#39;Find the first HtmlLink       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Dim iLink As Integer       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; For iLink = 0 To objCSS.Controls.Count - 1       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; If TypeOf objCSS.Controls(iLink) Is HtmlLink Then       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Exit For       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; End If       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Next       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objCSS.Controls.AddAt(iLink, objLink)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; If Localization.IsRightToLeft Then       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; AddRTLStyleSheet(id, href, objCSS, iLink + 1)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; End If       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Else       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objCSS.Controls.Add(objLink)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; If Localization.IsRightToLeft Then       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; AddRTLStyleSheet(id, href, objCSS)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; End If       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; End If       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; End If       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; End If       &lt;br /&gt;End Sub       &lt;br /&gt;      &lt;br /&gt;Private Sub AddRTLStyleSheet(ByVal id As String, ByVal href As String, ByVal objCSS As Control, Optional ByVal index As Integer = -1)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Dim rtlhref As String = GetRTLStyleSheetName(href)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; If String.IsNullOrEmpty(rtlhref) Then Return       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Dim objLink As New HtmlLink()       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; objLink.ID = id + &amp;quot;rtl_&amp;quot;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; objLink.Attributes(&amp;quot;rel&amp;quot;) = &amp;quot;stylesheet&amp;quot;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; objLink.Attributes(&amp;quot;type&amp;quot;) = &amp;quot;text/css&amp;quot;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; objLink.Href = rtlhref       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; If index &amp;lt;&amp;gt; -1 Then       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objCSS.Controls.AddAt(index, objLink)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Else       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objCSS.Controls.Add(objLink)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; End If &lt;/p&gt;    &lt;p&gt;End Sub      &lt;br /&gt;      &lt;br /&gt;Private Function GetRTLStyleSheetName(ByVal href As String) As String       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Dim physicalFilePath As String = Server.MapPath(href)       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; If Path.GetExtension(physicalFilePath).ToLower &amp;lt;&amp;gt; &amp;quot;.css&amp;quot; Then       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Return Nothing       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; End If       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; physicalFilePath = physicalFilePath.Substring(0, physicalFilePath.Length - 4) + &amp;quot;.rtl.css&amp;quot;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; If File.Exists(physicalFilePath) Then       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Return href.Substring(0, href.Length - 4) + &amp;quot;.rtl.css&amp;quot;       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; End If       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Return Nothing       &lt;br /&gt;End Function&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;I have tested the code above and it loaded portal.rtl.css, skin.rtl.css and index.rtl.css which are files that I made. It may not be fully optimized but it is a start at least.&lt;/p&gt;  &lt;p&gt;portal.rtl.css is the file that should contain html {direction:rtl;} not in portal.css.&lt;/p&gt;  &lt;p&gt;The rtl css files should be only overriding properties in&amp;#160; css classes in the normal css files that are only related to rtl only. No need to copy/paste the stylesheet and make changes. This way you will double size of css and will have to maintain 2 css files. Below is an example for this.&lt;/p&gt;  &lt;p&gt;In portal.css file there is class&lt;/p&gt;  &lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 64.54%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; direction: ltr; height: 77px; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot;&gt;.branding-bottom li { list-style: none; margin: 0 10px 0 0; padding: 0; display: block; width: 170px; float: left; }&lt;/div&gt;  &lt;p&gt;In portal.rtl.css there should be&lt;/p&gt;  &lt;div style=&quot;border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: rgb(244,244,244); margin: 20px 0px 10px; padding-left: 4px; width: 64.76%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;,courier,monospace; direction: ltr; height: 35px; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px&quot;&gt;.branding-bottom li { float: right; margin: 0 0 0 10px; }&lt;/div&gt;  &lt;p&gt;In my next post, I will discuss the 2 remaining aspects of RTL localization; localizing images and JavaScript files. I will publish my modified code as a proof of concept but won’t be suitable for production.&lt;/p&gt;  &lt;p&gt;I hope that DNN corp incorporate these changes to make DNN more powerful than it already is.&lt;/p&gt;  &lt;p&gt;Acknowledgements: I copied the style of the grey code boxes form &lt;a href=&quot;http://weblogs.asp.net/pawanmishra/&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://michaelfayez.blogspot.com/feeds/1089165759855812069/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://michaelfayez.blogspot.com/2010/01/proposal-for-dnn-support-of-rtl-layout.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/1089165759855812069'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/1089165759855812069'/><link rel='alternate' type='text/html' href='http://michaelfayez.blogspot.com/2010/01/proposal-for-dnn-support-of-rtl-layout.html' title='Proposal for DNN support of RTL layout Part 1'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/16252645336692523661</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8796582083368239187.post-6949982573731376800</id><published>2010-01-13T19:01:00.001-05:00</published><updated>2010-01-13T19:02:34.927-05:00</updated><title type='text'>My first post</title><content type='html'>&lt;p&gt;This my first time to start blogging. I found myself tempted to start a blog to share my ideas with the developer community. For what I see now, I will always blog about programming and software development. Talking about politics could be dangerous :) so I hope I won’t speak about them&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://michaelfayez.blogspot.com/feeds/6949982573731376800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://michaelfayez.blogspot.com/2010/01/my-first-post.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/6949982573731376800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8796582083368239187/posts/default/6949982573731376800'/><link rel='alternate' type='text/html' href='http://michaelfayez.blogspot.com/2010/01/my-first-post.html' title='My first post'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/16252645336692523661</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>