MVC5 How to set language based on top level domain - asp.net-mvc-4

I have a single MVC5 site which is accessed via several different regional URLs. In my case .co.uk (for the UK), .de (for Germany) and .fr (for France).
The site content is localised using RESX files and users can switch language via a cookie for persistence and a HttpModule which sets the asp.net thread locale based on the cookie (I used this approach).
I want the default language to be relevant to the top-level domain the user is accessing the site as. For example if a user is on .de, the default language should be de-DE. The user may choose to change the language in which case the default is overwritten, but it is very important that the default language is appropriate to the top-level domain (for users and search engines).
How can I achieve this in MVC5? The best I have got to so far is using JavaScript to check the url, set the cookie and refresh the page, but i know this is nasty and there must be a better way.
PS: Please note it is the top level domain that I want to drive this. I'm not using regional routing, for example http://whatever.com/DE or http://whatever.com/EN
PPS: I do not want to use the browser language detection feature either because that causes problems for search engines. i.e. it may cause the .de site to show in en-GB because that is what the search engine uses (or the search engine has no language so that is the default). If that happens the .de site will be treated as a duplicate of the .co.uk site which is never good for SEO

I figured out how to do this. Add this to global.asax
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if (Request.Cookies[Constants.LanguageCookieName] == null)
{
var culture = GetCultureFromHost();
Thread.CurrentThread.CurrentUICulture = culture;
Thread.CurrentThread.CurrentCulture = culture;
}
}
private CultureInfo GetCultureFromHost()
{
//set default culture of en-GB
CultureInfo ci = new CultureInfo("en-GB");
//get top level domain
string host = Request.Url.Host.ToLower();
//check for other known domains and set culture accordingly
if (host.Contains("whatever.de"))
{
ci = new CultureInfo("de-DE");
}
return ci;
}

In my case I set Persian cluture in global.asax and works well
protected void Application_BeginRequest(object sender, EventArgs e)
{
var persianCulture = new PersianCulture();
persianCulture.DateTimeFormat.ShortDatePattern = "yyyy/MM/dd";
persianCulture.DateTimeFormat.LongDatePattern = "dddd d MMMM yyyy";
persianCulture.DateTimeFormat.AMDesignator = "صبح";
persianCulture.DateTimeFormat.PMDesignator = "عصر";
Thread.CurrentThread.CurrentCulture = persianCulture;
Thread.CurrentThread.CurrentUICulture = persianCulture;
}

Related

Resource files from Resource folder

I have 3 resource files:
/Resources/Values.en-US.resx
/Resources/Values.es-ES.resx
/Resources/Values.fr-FR.resx
(English, Spanish, French)
From here I want to 'scan' what languages (from these resource files) are available so I can put them in a list and display them to the user for selecting. After releasing my program, people should be able to add more languages. The program will scan for new languages and make them available from a list.
Is there a way to get the files from Resources folder?
You can iterate through files located under application content directory, then select the resource files, extract the culture fragment from the file name and eventually create a list of cultures.
First, inject the IHostingEnvironment to use the ContentRootPath property it provides.
private readonly IHostingEnvironment _hostingEnvironment;
public HomeController(IHostingEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
}
As long as you keep all your resource files under ./Resources/ directory you should be fine.
Next, create DirectoryInfo:
var contentRootPath = Path.Combine(_hostingEnvironment.ContentRootPath, "Resources");
DirectoryInfo contentDirectoryInfo;
try
{
contentDirectoryInfo = new DirectoryInfo(contentRootPath);
}
catch (DirectoryNotFoundException)
{
// Here you should handle "Resources" directory not found exception.
throw;
}
Get the resource file names:
var resoruceFilesInfo = contentDirectoryInfo.GetFiles("*.resx", SearchOption.AllDirectories);
var resoruceFileNames = resoruceFilesInfo.Select(info => info.Name);
All three examples of resource files you provided follow a culture naming pattern. That is, a combination of an ISO 639 two-letter lowercase culture code associated with a language and an ISO 3166 two-letter uppercase subculture code associated with a country or region. For proper culture fragment extraction I suggest using a Regular Expression like this one below:
var regex = new Regex(#"(?<=\.)[a-z]{2}-[A-Z]{2}(?=\.resx$)");
var culturePrefixes = resoruceFileNames.Select(fileName => regex.Match(fileName).Value);
Finally, create a culture collection:
var cultureList = culturePrefixes.Select(prefix => new CultureInfo(prefix));

mvc 4 localization in multi layer web app

I am new to MVC and am trying to get a web application up and running that will be displayed in a couple of languages.
I have the localization functioning as I want in my web project but I have split my domain model into a separate class library and am wanting to perform localization on my property attributes as in the web project.
I have created a folder in my domain model project called Resources and have a Client.resx to store my fallback/default strings for property error messages and display names etc... I have also created a Client.es.resx for Spanish errors and display names however even if my culture is set to es, as below in my Global.aspx, I receive spanish on main web views but still receive english error messages on properties etc.. Can you tell me what I am doing wrong?
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
//Create culture info object
CultureInfo ci = new CultureInfo("es");
Thread.CurrentThread.CurrentUICulture = ci;
Thread.CurrentThread.CurrentCulture =
CultureInfo.CreateSpecificCulture(ci.Name);
}
Dope...... I had forgot to add the named parameters to the attribute as below...... what a clown!
[Required (ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ModelRes.Client))]

Sharepoint - Hiding some fields from some groups

I would like to ask , How can I hide some columns (ex. price,client's Mobile etc...)from group (such as Home visitors )?
Note: I'm using sharepoint 2010 foundation.
SharePoint 2010 doesn't have field level security, so you can't totally prevent different groups from seeing that data.
What you could do is create different forms/views for the different groups, and then only give them links to those form/view pages depending on the groups. However, if they know the right URL, they'd be able to type that in and see the other views.
I do not know of anything in the Enterprise version that adds field level audiences, security, or trimming. We recently completed a project that had "For Admin use only" fields. As Andy described, we used multiple forms to accomplish this. The only difference is that we protected against URL spoofing by having the Admin forms inherit from a custom class that checked the identity of the user:
public class AdminEditFormPage : WebPartPage
{
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
CheckRights();
}
private void CheckRights()
{
SPWeb web = SPContext.Current.Web;
SPGroup group = web.SiteGroups[Groups.FarmAdministrators];
bool flag = (group != null) && group.ContainsCurrentUser;
if (!flag)
{
SPUtility.HandleAccessDenied(new UnauthorizedAccessException());
}
}
}

Simple login for multi-domain intranet?

I have an intranet server on a Windows domain (server is Windows 2003, IIS6, NTFS permissions). It is on the domain Domain01. I have users from two domains in the same forest that access this intranet: Domain01 and Domain02 (DCs also running Windows 2003). Currently, the users are required to login by entering either:
Domain01\username or username#Domain01
My users are completely and thoroughly confused by having to enter the domain each time they log in.
Is there any way to simply allow them to log in by entering just their username and password WITHOUT the domain? For example, have the server try Domain01 by default, and if the login fails to try Domain02?
NOTE: I would like to do this via IIS or server settings if possible, rather than programmatically (for reference, I am using ASP.NET 2.0).
Yes. Usually what I do is do a global catalog search using the supplied user name as the sAMAccountName. Doing this with a PrincipalSearcher requires getting the underlying DirectorySearcher and replacing it's SearchRoot. Once I find the corresponding user object I extract the domain from the user object's path and use that as the domain for the authentication step. How you do the authentication varies depending on what you need it to do. If you don't need impersonation you can use PrincipalContext.ValidateCredentials to make sure that the username/password match using a PrincipalContext that matches the domain of the user account that you previously found. If you need impersonation check out this reference.
// NOTE: implement IDisposable and dispose of this if not null when done.
private DirectoryEntry userSearchRoot = null;
private UserPrincipal FindUserInGlobalContext( string userName )
{
using (PrincipalSearcher userSearcher = new PrincipalSearcher())
{
using (PrincipalContext context
= new PrincipalContext( ContextType.Domain ))
{
userSearcher.QueryFilter = new UserPrincipal( context );
DirectorySearcher searcher
= (DirectorySearcher)userSearcher.GetUnderlyingSearcher();
// I usually set the GC path from the existing search root
// by doing some string manipulation based on our domain
// Your code would be different.
string GCPath = ...set GC path..
// lazy loading of the search root entry.
if (userSearchRoot == null)
{
userSearchRoot = new DirectoryEntry( GCPath );
}
searcher.SearchRoot = userSearchRoot;
using (PrincipalContext gcContext =
new PrincipalContext( ContextType.Domain,
null,
GCPath.Replace("GC://",""))
{
UserPrincipal userFilter = new UserPrincipal( gcContext );
userFilter.SamAccountName = userName;
userSearcher.QueryFilter = userFilter;
return userSearcher.FindOne() as UserPrincipal;
}
}
}
}

ASP.NET Site Maps

Does anyone have experience creating SQL-based ASP.NET site-map providers?
I have the default XML file web.sitemap working properly with my Menu and SiteMapPath controls, but I'll need a way for the users of my site to create and modify pages dynamically.
I need to tie page viewing permissions into the standard ASP.NET membership system as well.
The Jeff Prosise version from MSDN magazine works pretty well, but it has a few flaws:
AddNode freaks out with links to external sites on your menu (www.google.com, etc.)
Here's my fix in BuildSiteMap():
SiteMapNode node = GetSiteMapNodeFromReader(reader);
string url = node.Url;
if (url.Contains(":"))
{
string garbage = Guid.NewGuid().ToString(); // SiteMapNode needs unique URLs
node.Url = "~/dummy_" + garbage + ".aspx";
AddNode(node, _root);
node.Url = url;
}
else
{
AddNode(node, _root);
}
SQLDependency caching is cool, but if you don't want to make a trip to the DB everytime your menu loads (to check to see if the dependency has changed) and your menus don't change very often, then why not use HttpRuntime.Cache instead?
public override SiteMapNode RootNode
{
get
{
SiteMapNode temp = (SiteMapNode)HttpRuntime.Cache["SomeKeyName"];
if (temp == null)
{
temp = BuildSiteMap();
HttpRuntime.Cache.Insert("SomeKeyName", temp, null, DateTime.Now.AddHours(1), Cache.NoSlidingExpiration);
}
return temp;
}
}