Skip to end of metadata
Go to start of metadata

Contents

Introduction

While pages in Confluence can be written in a variety of languages, there is no built-in support for managing and associating these pages (links, by themselves, are not a solution). Add-ons are certainly worth investigating. But add-ons are not always suitable to one's needs or way of working.

For those interested in an alternative approach, this page shows how to manage multi-language content in Confluence using a macro and a simple, yet effective process and organization to coordinate/associate related pages. The method used here is similar in some ways to how Wikipedia does things as described here.

Organization

The key points to how content is organized are:

  • one space per language
  • a dedicated space for "data"
  • all related spaces share a common space key root (not necessary but useful to keep things straight)

Content Spaces

Rather than putting content from different languages into the same space, a different space is used for each language. This maintains clear lines of separation by language.

A site will typically start off with a space in one, local language (e.g., English) and have a meaningful space key for that language. To support the other languages, the original space key is used as a root to which a suffix will be appended to discriminate between languages.

For example:

  • SCI - original space key
  • SCIxFR - French language version of SCI
  • SCIxDE - German language version of SCI

If one is starting completely from scratch, the original space key above may have been named SCIxEN (English) to fully follow the pattern. Regardless, the point is that SCI serves as the root for all related space keys.

As a practical matter, it is unnecessary for all spaces to have corresponding content. That is, it is possible that one space will have content that another/the others do not.

It is also unnecessary for page names or page content to be translated strictly. That is, the goal is to make associations, not force or intimate full equivalence between the pages.

Data Space

To be able to inform users that a page is related to others, the association between pages in the different spaces needs to be specified somewhere.

One option is to choose a "master" space (e.g., SCI) and keep all the associations there. But, what if there is no page (yet) in the "master" space. One must then either create a holding, but empty, page in the "master" space or do without the associations. Neither of these choices are good.

Another option is to maintain associations in each page. So, the SCI space would have to contain references to SCIxFR (French) and SCIxDE (German); the SCIxFR space would have to keep references to SCI and SCIxDE; and so on. This approach provides the association wanted, but at significant cost. For n spaces, n pages would need to be updated with n-1 entries. This is completely unmanageable and unscalable (see the graph of interlanguage links before Wikidata).

The approach of Wikidata, and the one used here, is to manage associations in a separate, dedicated "data" space. Pages in the data space contain information about the associations and no content. An association, then, is a collection of links to related pages and managed within a single page. As such. there is only one page to update when creating, adding to, or removing from an association.

Following the naming pattern, with a space key root of SCI, the data space would be named SCIx.

Finding, Collecting, and Presenting the Associations

The glue between the content spaces and the data space is the macro called incoming.

This macro is passed the data space key and presented on all pages of the content spaces. The easiest way to do this is to make it a component in the sidebar (the header and footer are not as useful for this). The sidebar is configured once for each space, is loaded automatically for each content page, and most importantly, no content page needs to be modified.

To do its work, the macro:

  • finds all pages in the data space with at least one outgoing link pointing to the currently loaded content page
  • collects all the outgoing links in those data space pages
  • generates a list of of links based on the outgoing links, themselves

The macro:

incoming
## @param DataSpace:title=Space|type=spacekey|required=true
## @param Label:title=Label|type=string|default=|required=false
#set ($containerManagerClass = $content.class.forName('com.atlassian.spring.container.ContainerManager'))
#set ($getInstanceMethod = $containerManagerClass.getDeclaredMethod('getInstance',null))
#set ($containerManager = $getInstanceMethod.invoke(null,null))
#set ($containerContext = $containerManager.containerContext)
#set ($linkManager = $containerContext.getComponent('linkManager'))
#set ($i = 0)
#set ($refpages = $linkManager.getReferringContent($content))
#foreach ($refpage in $refpages)
#if ($refpage.getSpaceKey() == "$paramDataSpace")
#if ($i == 0)
<strong>$paramLabel <a href="$req.contextPath/pages/viewpage.action?pageId=$refpage.getId()">🔗</a></strong><br><br>
#set ($i = 1)
#end
#foreach ( $link in $refpage.getOutgoingLinks())
#set ($dstpagetitle = $link.getDestinationPageTitle())
#set ($dstpagespacekey = $link.getDestinationSpaceKey())
#set ($dstpage = $pageManager.getPage($dstpagespacekey, $dstpagetitle))
 <a href="$req.contextPath/pages/viewpage.action?pageId=$dstpage.getId()">$dstpagetitle</a><br>
#end
#end
#end

Notes:

  • linkManager.getReferringContent() returns a list of referring pages (from the whole site)
  • only the referring pages that come from the data space are used
  • on the first iteration (i == 0), a label is output along with a link to the referring page; easy access to the referring page (from the data space) is helpful if one needs to make an update
  • refpage.getOutgoingLinks() returns the list of links (i.e., the association) from the data space page
  • each link is output on its own with as an HTML link

Demo

To demonstrate how this works:

StepDescriptionScreenshot
1

Create the user macro ( → General configuration → User Macros → Create a User Macro). Copy the macro code to the Template text field.



2Create content space SCI.
3Create content space SCIxFR.

4Create data space SCIx.
5

Add macro to sidebar for SCI (Space tools → Look and Feel → Sidebar, header and footer).

{incoming:DataSpace=SCIx|Label=Languages}

6

Add macro to sidebar for SCIxFR.

{incoming:DataSpace=SCIx|Label=Langues}

7Create "hello" page in SCI.
8Create "bonjour" page in SCIxFR.
9Create "hello" page in SCIx.
10

Add two links in the SCIx "hello" page:

  1. link to SCI:hello
  2. link to SCIxFR:bonjour

11Go to SCI "hello". Look for the "Languages" section in the sidebar.

12Go to SCIxFR "bonjour". Look for the "Langues" section in the sidebar.

See video for full example.

Conclusion

This way of managing and coordinating multi-language content is simple, clear, and imposes a negligible performance hit. It also does not need anything more than the standard features of Confluence and so should work across many versions of Confluence.

If anyone has any comments or tweaks to suggest, drop a line (see contact info).

  • No labels