Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Daniel Bardi 927 posts 2562 karma points
    Jul 12, 2010 @ 22:14
    Daniel Bardi
    3

    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?

  • Sascha Wolter 615 posts 1101 karma points
    Jul 13, 2010 @ 00:25
    Sascha Wolter
    0

    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 

  • Daniel Bardi 927 posts 2562 karma points
    Jul 13, 2010 @ 00:31
    Daniel Bardi
    0

    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?

  • Daniel Bardi 927 posts 2562 karma points
    Jul 13, 2010 @ 00:32
    Daniel Bardi
    0

    Note:.. instead of sort order, I meant position...

  • Tim 225 posts 690 karma points
    Jul 13, 2010 @ 00:45
    Tim
    1

    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

     

  • Daniel Bardi 927 posts 2562 karma points
    Jul 13, 2010 @ 01:25
    Daniel Bardi
    0

    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.

  • Daniel Bardi 927 posts 2562 karma points
    Jul 13, 2010 @ 08:58
    Daniel Bardi
    0

    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:
     <ul>
       <xsl:for-each select="$currentPage/ancestor::root/*">
         <li id="{@nodeName}">
           <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>
    I know there might be a better way, but this works for me for now..

     

  • Daniel Bardi 927 posts 2562 karma points
    Jul 13, 2010 @ 09:12
    Daniel Bardi
    0

    Don't forget to add the reference in the xsltextensions.config

    <?xml version="1.0" encoding="utf-8" ?> 
    <XsltExtensions>
      <ext assembly="Dascoba.Umb.Extensions" type="Dascoba.Umb.Extensions.NodePathing" alias="dsb.nodePathing"/>
    </XsltExtensions> 
  • Matt Brailsford 4124 posts 22215 karma points MVP 9x c-trib
    Jul 13, 2010 @ 09:21
    Matt Brailsford
    1

    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

  • Daniel Bardi 927 posts 2562 karma points
    Jul 13, 2010 @ 09:36
    Daniel Bardi
    1

    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.. :) )

     

  • Matt Brailsford 4124 posts 22215 karma points MVP 9x c-trib
    Jul 13, 2010 @ 09:58
    Matt Brailsford
    1

    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

  • atze187 160 posts 215 karma points
    Jul 13, 2010 @ 10:18
    atze187
    0

    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.

  • Tim 225 posts 690 karma points
    Jul 13, 2010 @ 10:52
    Tim
    1

    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

  • Daniel Bardi 927 posts 2562 karma points
    Jul 13, 2010 @ 19:19
    Daniel Bardi
    1

    I'll create a codeplex project once I get some initial code going.

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Jul 13, 2010 @ 19:41
    Morten Bock
    4

    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 :-)

  • Daniel Bardi 927 posts 2562 karma points
    Jul 14, 2010 @ 05:30
    Daniel Bardi
    0

    Awesome information... I will definitely being consider it.  Thanks.... 

     

  • Yannick Smits 321 posts 718 karma points
    Oct 25, 2010 @ 19:01
    Yannick Smits
    0

    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.

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Oct 25, 2010 @ 20:29
    Morten Bock
    0

    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.

  • Yannick Smits 321 posts 718 karma points
    Jan 14, 2011 @ 11:37
    Yannick Smits
    0

    Hi Morton, did the customer get back to you on possibilities to share the snipit?

  • Alexander Bobin 6 posts 26 karma points
    Mar 24, 2011 @ 16:54
    Alexander Bobin
    0

    I'm really interested in this project. Has any progress been made recently? Or maybe an existing project would fit the bill?

  • Daniel Bardi 927 posts 2562 karma points
    Mar 24, 2011 @ 17:46
    Daniel Bardi
    0

    A package was created by another user.

    Here's it is : http://our.umbraco.org/projects/developer-tools/relation-types

  • Yannick Smits 321 posts 718 karma points
    Mar 25, 2011 @ 10:39
    Yannick Smits
    0

    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.

  • Anthony Candaele 1197 posts 2049 karma points
    Mar 25, 2011 @ 10:50
    Anthony Candaele
    0

    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

  • Yannick Smits 321 posts 718 karma points
    Mar 25, 2011 @ 17:08
    Yannick Smits
    1

    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?

  • Anthony Candaele 1197 posts 2049 karma points
    Mar 26, 2011 @ 10:39
    Anthony Candaele
    0

    Hi Yannic,

    I am gladly willing to test your package.

     

    greetings,

    Anthony

  • Yannick Smits 321 posts 718 karma points
    Mar 27, 2011 @ 01:39
    Yannick Smits
    0

    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.

  • Daniel Bardi 927 posts 2562 karma points
    Mar 29, 2011 @ 09:14
    Daniel Bardi
    0

    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.

  • Anthony Candaele 1197 posts 2049 karma points
    Mar 29, 2011 @ 09:32
    Anthony Candaele
    0

    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

  • KK 35 posts 55 karma points
    Jun 23, 2011 @ 15:31
    KK
    0

    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.

     

Please Sign in or register to post replies

Write your reply to:

Draft