The best way would be if it was possible just to check for the current culture without checking for id's or strings like the examples above but I don't know how to do this yet...
Might be a stupid question and haven't got the time to test it atm. Would that return the culture like "en_US"? If it does, how could you use that in your XSLTs? :)
I was looking for a way of doing this natively with XSLT, by checking the culture code associated with the hostname variable. I know it can be done in .Net, I wondered if there was a native XSLT method.
It was a question that arose on the Level 1 training, that we couldn't answer, so it's really of academic interest.
XML actualy has a special attribute for this kind of thing: xml:lang can be set on any element and is in scope for that element and its descendants until another xml:lang attribute is encountered:
1) include this in your xslt file - just below the xsl:stylesheet tag (our xslt is in a subfolder of the website root - hence we use the path ../bin/ )
if (domains != null && domains.Length >= 0)
{
int languageId = domains[0].Language.id;
Language language = new Language(languageId);
return language.CultureAlias;
}
}
catch (Exception errDictionary)
{
}
return string.Empty;
}
</msxml:script>
you can further customize with code to display the error
2) make sure your xsl:stylesheet tag includes a reference to urn:schemas-microsoft-com:xslt and to your namespace like this ( we use prefix customfunction)
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:umbraco.library="urn:umbraco.library"
exclude-result-prefixes="msxml umbraco.library"
xmlns:customfunction="http://www.yourdomain.com">
3) now you can retrieve the culture name of a given node with this call to the function:
Be aware that using script as you're using may cause performance issues!! Don't find the post where Casey explains why (he's done some research on this), will try to find and link it here.
I think the performance issues would probably be related to something that I heard Benjamin Howarth explaining, when he was describing how to get Umbraco to work in Medium trust at the Umbraco 5th Birthday event in London.
I *think* these <msxml:script> 's result in temporary files being created (its compiled on the fly for every request - using Reflection.Emit) and ends up hammering your O/S drive temp folder. It was relevant to him because Reflection.Emit is not allowed in medium trust, but the bit that will be relevant to you, in terms of performance, is the on-the-fly compilation to temp directory.
If I've got my explanation correct, using <msxml:script> could also potentially open your site up to a denial-of-service attack by anyone who floods a page, that uses those scripts, with lots of requests. It could potentially fill your O/S drive and then may eventually crash applications on the server.
After brief diversion on performance in my previous comment:
I have found I also need the ability to detect which culture I am rendering for a given request. In my case, I'm not so concerned about the culture of the node, I would rather know the culture that the page is currently being rendered with.
I've looked at the Umbraco source code that loads the domain & culture, which then sets the ASP.NET Thread and Thread.UI culture. So my thinking is that I'd probably need to write an extension method to detect the Culture of the System.Threading.Current Thread... Might be worth raising a codeplex feature request to add that as a method to the umbraco.library class (e.g. umbraco.library:CurrentPageCulture - returns string in form of "en-US" etc.) if enough people think it would be a useful core feature?
How do you retrieve the Culture Code for a given Node
in xslt is it possible to retrieve the culture code associated with a particular node (or it's ancestor)?
Or do you need a bit of .net?
Well, there's two ways to do it, as I know of, but I'm still looking for a better solution.
1. You could check for the ancestors id...
<xsl:variable name="languageID">
<xsl:choose>
<xsl:when test="$currentPage/ancestor-or-self::node/@id = '1801'">
Danish
</xsl:when>
<xsl:when test="$currentPage/ancestor-or-self::node/@id = '1802'">
German
</xsl:when>
<xsl:otherwise>
English
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
2. Create a dictionary Item 'LanguageList' with the values like "da", "en" and "de". And check for the culture with the following xslt:
<xsl:variable name="langSelectDic" select="umbraco.library:GetDictionaryItem('LanguageList')"/>
<xsl:variable name="selectLanguage">
<xsl:choose>
<xsl:when test="$langSelectDic = 'en'">English</xsl:when>
<xsl:when test="$langSelectDic = 'da'">Danish</xsl:when>
<xsl:when test="$langSelectDic = 'de'">German</xsl:when>
<xsl:otherwise>English</xsl:otherwise>
</xsl:choose>
</xsl:variable>
The best way would be if it was possible just to check for the current culture without checking for id's or strings like the examples above but I don't know how to do this yet...
You couls use an extension and use the method below:
/// <summary>
/// Returns the ID of the current language.
/// </summary>
/// <returns>The ID of the current language, or 0 if it could not be determined.</returns>
public static string GetLanguageAlias(int pageId)
{
int languageId = 0;
string la = string.Empty;
try
{
Domain[] domains = umbraco.library.GetCurrentDomains(pageId);
if (domains != null && domains.Length >= 0)
{
languageId = domains[0].Language.id;
Language l = new Language(languageId);
la = l.CultureAlias;
}
return la;
}
catch (Exception errDictionary)
{
HttpContext.Current.Trace.Warn("library", "Error returning language alias for'" + pageId + "'", errDictionary);
return string.Empty;
}
}
Might be a stupid question and haven't got the time to test it atm. Would that return the culture like "en_US"? If it does, how could you use that in your XSLTs? :)
Thanks in advance!
Ahhh... Where is that edit button?? Instead of "en_US" I mean "en-US". Just to clarify that.. ;)
You need to compile the above method into a dll and then add it to your umbraco installation.
For more info on how to add and use XSLt extensions, please have a look here
http://blockquote.be/2006/08/09/extending-umbraco-with-a-library/
http://en.wikibooks.org/wiki/Umbraco/Create_xslt_exstension_like_umbraco.Library_in_C
or in the XSLT code;
http://umbraco.org/documentation/books/extending-xslt-with-c-sharp-or-javascript
Ahhh... Alright. But Paul is asking for a way to do it in XSLT or if it's necessary to go with the .net solution... But thanks for the reply. :)
I was looking for a way of doing this natively with XSLT, by checking the culture code associated with the hostname variable. I know it can be done in .Net, I wondered if there was a native XSLT method.
It was a question that arose on the Level 1 training, that we couldn't answer, so it's really of academic interest.
XML actualy has a special attribute for this kind of thing: xml:lang can be set on any element and is in scope for that element and its descendants until another xml:lang attribute is encountered:
In XSLT/XPath you can select by language using the lang() function:
<label for="colorpicker"> <xsl:value of select="$labels/label[lang('en-US')]" /> </label>
But of course we'd have to be able to add that attribute to Umbraco nodes to use this built-in feature - anyone know how to do that in a nice way?
if you don't want the compiled dll solution
1) include this in your xslt file - just below the xsl:stylesheet tag (our xslt is in a subfolder of the website root - hence we use the path ../bin/ )
<msxml:script language="CSharp" implements-prefix="customfunction">
<msxml:assembly href="../bin/cms.dll" />
<msxml:assembly href="../bin/umbraco.dll" />
<msxml:using namespace="System.Globalization" />
<msxml:using namespace="umbraco" />
<msxml:using namespace="umbraco.cms.businesslogic.web" />
<msxml:using namespace="umbraco.cms.businesslogic.language" />
public static string GetLanguage(int pageId)
{
try
{
Domain[] domains = library.GetCurrentDomains(pageId);
if (domains != null && domains.Length >= 0)
{
int languageId = domains[0].Language.id;
Language language = new Language(languageId);
return language.CultureAlias;
}
}
catch (Exception errDictionary)
{
}
return string.Empty;
}
</msxml:script>
you can further customize with code to display the error
2) make sure your xsl:stylesheet tag includes a reference to urn:schemas-microsoft-com:xslt and to your namespace like this ( we use prefix customfunction)
3) now you can retrieve the culture name of a given node with this call to the function:
<xsl:value-of select="customfunction:GetLanguage(./@id)" disable-output-escaping="no"/>
Be aware that using script as you're using may cause performance issues!! Don't find the post where Casey explains why (he's done some research on this), will try to find and link it here.
Cheers,
/Dirk
I think the performance issues would probably be related to something that I heard Benjamin Howarth explaining, when he was describing how to get Umbraco to work in Medium trust at the Umbraco 5th Birthday event in London.
I *think* these <msxml:script> 's result in temporary files being created (its compiled on the fly for every request - using Reflection.Emit) and ends up hammering your O/S drive temp folder. It was relevant to him because Reflection.Emit is not allowed in medium trust, but the bit that will be relevant to you, in terms of performance, is the on-the-fly compilation to temp directory.
If I've got my explanation correct, using <msxml:script> could also potentially open your site up to a denial-of-service attack by anyone who floods a page, that uses those scripts, with lots of requests. It could potentially fill your O/S drive and then may eventually crash applications on the server.
After brief diversion on performance in my previous comment:
I have found I also need the ability to detect which culture I am rendering for a given request. In my case, I'm not so concerned about the culture of the node, I would rather know the culture that the page is currently being rendered with.
I've looked at the Umbraco source code that loads the domain & culture, which then sets the ASP.NET Thread and Thread.UI culture. So my thinking is that I'd probably need to write an extension method to detect the Culture of the System.Threading.Current Thread... Might be worth raising a codeplex feature request to add that as a method to the umbraco.library class (e.g. umbraco.library:CurrentPageCulture - returns string in form of "en-US" etc.) if enough people think it would be a useful core feature?
+1 on that!
I am using one domain for each language tree.
@inherits umbraco.MacroEngines.DynamicNodeContext
@using umbraco;
@using umbraco.MacroEngines;
@using umbraco.cms.businesslogic.web;
@{
var en = Parameter.English; //id of Home page of English tree
var ar = Parameter.Arabic; //id of Home page of Arabic tree
umbraco.MacroEngines.DynamicNode page = @Model;
Domain[] domains = umbraco.library.GetCurrentDomains(page.Id);
<span class="languageswitch">
@if(domains[0].Language.CultureAlias.Contains("ar"))
{
<a href="@library.NiceUrlWithDomain(int.Parse(en))" title="">English</a>
}
@if(domains[0].Language.CultureAlias.Contains("en"))
{
<a href="@library.NiceUrlWithDomain(int.Parse(ar))" title="Arabic"></a>
}
</span>
}
Can anyone suggest improvements to this?
Could you not just use a current Dictionary value to determine what culture you are working with?
is working on a reply...