When selecting the language from a particular page, the client would like the exact page in the other language to display. Currently, the selected languages home page is displaying.
How can I relate EVERY page in the English site to the same page in the French and Spanish sites?
that's one of the main issues of having the sites separated in Umbraco (instead of using the 'tabbed' approach).
I don't think there is any other way than via a (manual) reference matrix of some kind, e.g. all English pages have 2 content pickers on them that link to the Spanish and French counterparts. In case of switching from Spanish to French there will be some heavy lifting necessary, however until you have 1000s of nodes that should be fine I guess. Other option would be to have the matrix external, e.g. build a custom page with a custom data table that has the columns 'English Page ID', 'Spanish Page ID', 'French Page ID', so you can relate the pages to one another.
Obviously when switching to another language you'd have some kind of a matrix lookup depending on the page you came from.
Just my five cents, would be interesting to see if there is a better solution to this. :)
I was considering using a path converter.. I could take the current page to look up the path based on sort order instead of node ids.. with this sort order, I could then determine the page in the other language site. This would only work if the sites were structured the same (and they are).. What do you think?
If you copy nodes in Umbraco you are given the option of relating the copied pages to the original. The related nodes can be retrieved using XSLT as found here:
Clearly this doesn't work nicely with more than two sites. However you'll note in the XSLT example it is getting multiple relations, so can be extended to support multiple relations.
Umbraco (as usual) already has the infrastructure in place if not the user interface!
Here are the Umbraco TV videos talking about the relations API
So all that is needed is some kind of relationship manager interface or an event handler which can auto-relate the pages. I suspect this would make a killer package as Umbraco really needs a nice way of managing content relationships.
I checked the relation box when I copied the sites, but the problem is when adding new content. I would have to trap the event and add new content to all 3 sites and create the relationship at the same time. It would be killer package.. I'm going to consider writing it unless someone else beats me to it.
I came up with a quick solution.. I created an xslt extension. I pass in the current node id and the related language root id.
Since the sites are identical in structure (sort order as well) and will remain that way, I simply get the indices of the nodes based on the current node Path value.
I exclude the 'Content' and root nodes, then find the Node under the other language site at the same location as the current node.
Here's the code class:
using System;
using System.Collections.Generic;
using System.Linq;
using umbraco.cms.businesslogic;
namespace Dascoba.Umb.Extensions
{
public class NodePathing
{
public NodePathing() {}
public static int GetAlternateNodeId(int currentNodeId, int altRootId)
{
// Get node path as string array of node ids
var currentNode = new CMSNode(currentNodeId);
var nodeIds = currentNode.Path.Split(',');
// Collect node indices, ignoring 'Content' and root
var nodeIndices = new List<int>();
foreach (var cmsNode in from id in nodeIds where id != "-1" select new CMSNode(Convert.ToInt32(id)))
{
CMSNode parentNode;
try
{
// causes exception if root node
parentNode = cmsNode.Parent;
}
catch
{
// ignore root node
continue;
}
var node = cmsNode;
var nodeIndex = parentNode.Children.Cast<CMSNode>().TakeWhile(childNode => childNode.Id != node.Id).Count();
nodeIndices.Add(nodeIndex);
}
if (nodeIndices.Count == 0) return altRootId;
// Get alternate root node (i.e. language root)
var altNode = new CMSNode(altRootId);
try
{
// Retreive new node id based on indices starting from alternate root
var node = altNode;
foreach (var childNode in nodeIndices.Select(index => new CMSNode(node.Children[index].Id)))
{
altNode = childNode;
}
}
catch (Exception)
{
return altNode.Id;
}
return altNode.Id;
}
}
}
I then call this in my languageselector.xslt file:
I think Tim is right, in that you would probably want to use the relationship API.
What I would do is choose one site to say "this is the master site", then have relations from each page in the master site, to each page in the other language sites (I'd even setup an event handler so when you create a page in the master site, it auto creates it in the other languages). Then to choose a language, you can always refer back to the master site, and then down to the other language sites.
You could even hook up the "auto create lanugage pages" event handler to a translation service to auto translate. Granted it's not going to be perfect, but I find it's always easier to edit, than it is to create from scratch. Checkout Niels example, http://umbraco.org/blog/2009/3/25/microsoft-translator-and-umbraco
I liked Niels auto translator.. I was going to implement it.. might do that now... It also looks like he has it auto create nodes as well.
I think a combo of Niels code and my path locating code might do the trick. I'll work on the concept.
I can see it doing the following:
1. Setting a master site 2. Allowing to duplicate/copy master site and auto translate 3. Auto create pages if created in master site (like Niels code with path locating) 4. Save and Translate button on documents 5. Auto relate on page create if site is related to master site. 6. Option to delete related pages upon delete from master site.
This could work! I see a new package coming! I think I'll call it the Multilingual Site Sync package (it's a work in progress.. :) )
Sounds good, but you shouldn't need to do path locating (the way you have it in your example anyway) as long as all pages are related. Say you create a new page, just check the parent pages relation to find the other language pages, and you can just create a copy of the new page underneath each one. The relationship API will be your friend, and is much more robust than the path checking. As an example, say you have a page on one of the language sites that you don't on the master (which can happen), this could mess up your paths, but would never mess up your relations.
As Matt wrote, you should go with the relationship api. It may require some extended initial effort, but you don't have to re-invent its functionality and you even get community support as others are using the api too.
We have taken the same approach on a recent project. Codewise it is not too difficult, but just a few points that we had to take into account when doing this:
When to do the distribution of content? This is actually something that is a matter of taste, so we decided to let it be up to the editor of the site. Because if you distribute the page on create, then none of the original pages content gets copied to the new nodes, thus you have to enter everything x times (for example choosing an image). So we added some checkboxes to the doctypes to allow the editor to say "Distribute this to the other sites when I save the document". We also added options for him to (un)publish all the related nodes globally, since you might want to remove a page from the site instantly.
Handling updates. In our case, there is an editor attached to each site/language, so we needed a workflow that would somehow support that changes could be made to the master/english site, and that it would get translated to the other languages. At the same time, we did not want to destroy the work that the translators had already done in the other languages. So we went with the option of creating translation tasks for the editors, when the original page was updated (and told to distribute by the editor), and we created a couple of links in the comments that would show a diff view of the original pages properties, so that the translator could easily identify what had changed in the original document, and make the appropriate changes to his content.
I think these things are wort considering for a generic package of this type. Let me know if you want some more input, or some collaboration when you set up the project :-)
He Morton, I like your approach for notifying the translators (making it optional, sending a diff). Would you mind sharing some code snippets?
On a side note related to this topic. I found this umbraco.tv episode and attached code samples very helpfull in understanding multi-lingual structure syncing.
The code belongs to the customer, but I will see if they mind sharing some of the key bits. It's not actually too complicated, once you know which parts of the API to look at.
I think the question was how to relate pages on the front end. Like when you're on the /about-us page that when you click the dutch flag / dropdown you go to the /over-ons page. Don't think there is a package for that yet.
In Plone there is a solution for that. You can map pages to their counterparts in an other language. It would be nice to see this implemented in Umbraco.
same problem here ... time! But I'm implementing my own website in Umbraco 4.7 and I'm planning this to be a multilanguage website. For this purpose I will try Yannick's package. I keep you informed on the results.
I am able to get content structure for different language but how do we create templates for other language and apply same to created other language content.
How to relate pages in a multi-language site
I'm using separate sites for each language.
I have a language selector on the site.
When selecting the language from a particular page, the client would like the exact page in the other language to display. Currently, the selected languages home page is displaying.
How can I relate EVERY page in the English site to the same page in the French and Spanish sites?
Hi Daniel,
that's one of the main issues of having the sites separated in Umbraco (instead of using the 'tabbed' approach).
I don't think there is any other way than via a (manual) reference matrix of some kind, e.g. all English pages have 2 content pickers on them that link to the Spanish and French counterparts. In case of switching from Spanish to French there will be some heavy lifting necessary, however until you have 1000s of nodes that should be fine I guess. Other option would be to have the matrix external, e.g. build a custom page with a custom data table that has the columns 'English Page ID', 'Spanish Page ID', 'French Page ID', so you can relate the pages to one another.
Obviously when switching to another language you'd have some kind of a matrix lookup depending on the page you came from.
Just my five cents, would be interesting to see if there is a better solution to this. :)
Sascha
I was considering using a path converter.. I could take the current page to look up the path based on sort order instead of node ids.. with this sort order, I could then determine the page in the other language site. This would only work if the sites were structured the same (and they are).. What do you think?
Note:.. instead of sort order, I meant position...
Hi,
If you copy nodes in Umbraco you are given the option of relating the copied pages to the original. The related nodes can be retrieved using XSLT as found here:
http://our.umbraco.org/wiki/reference/xslt/get-related-nodes
Clearly this doesn't work nicely with more than two sites. However you'll note in the XSLT example it is getting multiple relations, so can be extended to support multiple relations.
Umbraco (as usual) already has the infrastructure in place if not the user interface!
Here are the Umbraco TV videos talking about the relations API
http://umbraco.org/documentation/videos/for-developers/relations/introduction-to-relations
So all that is needed is some kind of relationship manager interface or an event handler which can auto-relate the pages. I suspect this would make a killer package as Umbraco really needs a nice way of managing content relationships.
Tim
I checked the relation box when I copied the sites, but the problem is when adding new content. I would have to trap the event and add new content to all 3 sites and create the relationship at the same time. It would be killer package.. I'm going to consider writing it unless someone else beats me to it.
Thanks for the input.
I came up with a quick solution.. I created an xslt extension. I pass in the current node id and the related language root id.
Since the sites are identical in structure (sort order as well) and will remain that way, I simply get the indices of the nodes based on the current node Path value.
I exclude the 'Content' and root nodes, then find the Node under the other language site at the same location as the current node.
Here's the code class:
<ul>
<xsl:for-each select="$currentPage/ancestor::root/*">
<li id="{@nodeName}">
<a href="{umbraco.library:NiceUrl(dsb.nodePathing:GetAlternateNodeId($currentPage/@id, @id))}">
<xsl:if test="languageName = $currentLanguage">
<xsl:attribute name="selected">selected</xsl:attribute>
</xsl:if>
<xsl:value-of select="languageName"/>
</a>
</li>
</xsl:for-each>
</ul>
Don't forget to add the reference in the xsltextensions.config
Cool,
I think Tim is right, in that you would probably want to use the relationship API.
What I would do is choose one site to say "this is the master site", then have relations from each page in the master site, to each page in the other language sites (I'd even setup an event handler so when you create a page in the master site, it auto creates it in the other languages). Then to choose a language, you can always refer back to the master site, and then down to the other language sites.
You could even hook up the "auto create lanugage pages" event handler to a translation service to auto translate. Granted it's not going to be perfect, but I find it's always easier to edit, than it is to create from scratch. Checkout Niels example, http://umbraco.org/blog/2009/3/25/microsoft-translator-and-umbraco
Matt
I liked Niels auto translator.. I was going to implement it.. might do that now... It also looks like he has it auto create nodes as well.
I think a combo of Niels code and my path locating code might do the trick. I'll work on the concept.
I can see it doing the following:
1. Setting a master site
2. Allowing to duplicate/copy master site and auto translate
3. Auto create pages if created in master site (like Niels code with path locating)
4. Save and Translate button on documents
5. Auto relate on page create if site is related to master site.
6. Option to delete related pages upon delete from master site.
This could work! I see a new package coming! I think I'll call it the Multilingual Site Sync package (it's a work in progress.. :) )
Hi Daniel,
Sounds good, but you shouldn't need to do path locating (the way you have it in your example anyway) as long as all pages are related. Say you create a new page, just check the parent pages relation to find the other language pages, and you can just create a copy of the new page underneath each one. The relationship API will be your friend, and is much more robust than the path checking. As an example, say you have a page on one of the language sites that you don't on the master (which can happen), this could mess up your paths, but would never mess up your relations.
Matt
As Matt wrote, you should go with the relationship api. It may require some extended initial effort, but you don't have to re-invent its functionality and you even get community support as others are using the api too.
Yes I think the relationship API plan is the way forward.
If you start on this package let me know as I'd like to help. Coding, testing, documentaion etc.
Drop me a DM via twitter or contact me through the Cogworks website if you would like to collaborate.
T
I'll create a codeplex project once I get some initial code going.
We have taken the same approach on a recent project. Codewise it is not too difficult, but just a few points that we had to take into account when doing this:
When to do the distribution of content? This is actually something that is a matter of taste, so we decided to let it be up to the editor of the site. Because if you distribute the page on create, then none of the original pages content gets copied to the new nodes, thus you have to enter everything x times (for example choosing an image). So we added some checkboxes to the doctypes to allow the editor to say "Distribute this to the other sites when I save the document". We also added options for him to (un)publish all the related nodes globally, since you might want to remove a page from the site instantly.
Handling updates. In our case, there is an editor attached to each site/language, so we needed a workflow that would somehow support that changes could be made to the master/english site, and that it would get translated to the other languages. At the same time, we did not want to destroy the work that the translators had already done in the other languages. So we went with the option of creating translation tasks for the editors, when the original page was updated (and told to distribute by the editor), and we created a couple of links in the comments that would show a diff view of the original pages properties, so that the translator could easily identify what had changed in the original document, and make the appropriate changes to his content.
I think these things are wort considering for a generic package of this type. Let me know if you want some more input, or some collaboration when you set up the project :-)
Awesome information... I will definitely being consider it. Thanks....
He Morton, I like your approach for notifying the translators (making it optional, sending a diff). Would you mind sharing some code snippets?
On a side note related to this topic. I found this umbraco.tv episode and attached code samples very helpfull in understanding multi-lingual structure syncing.
Hi Yannick
The code belongs to the customer, but I will see if they mind sharing some of the key bits. It's not actually too complicated, once you know which parts of the API to look at.
Hi Morton, did the customer get back to you on possibilities to share the snipit?
I'm really interested in this project. Has any progress been made recently? Or maybe an existing project would fit the bill?
A package was created by another user.
Here's it is : http://our.umbraco.org/projects/developer-tools/relation-types
I think the question was how to relate pages on the front end. Like when you're on the /about-us page that when you click the dutch flag / dropdown you go to the /over-ons page. Don't think there is a package for that yet.
In Plone there is a solution for that. You can map pages to their counterparts in an other language. It would be nice to see this implemented in Umbraco.
greetings,
Anthony
Ok, just finished a package that implements the related page language switcher in razor. Somebody wants to test it before I put it up on our?
Hi Yannic,
I am gladly willing to test your package.
greetings,
Anthony
I've just uploaded the package, actualy it's just a 100 line razor script for now. See:
http://our.umbraco.org/projects/website-utilities/multi-language-tools
and let me know if it works for you.
Has anyone tested the package yet.. I'm interested in the results.. would test myself, but I can't find time.. even now, I'm working.
same problem here ... time! But I'm implementing my own website in Umbraco 4.7 and I'm planning this to be a multilanguage website. For this purpose I will try Yannick's package. I keep you informed on the results.
Anthony
hello,
I am able to get content structure for different language but how do we create templates for other language and apply same to created other language content.
is working on a reply...