Using a DocumentReference with a locale

Hi all,

I suspect I’m doing something wrong but I can’t get my head around this scenario:

  • Set a wiki as multinlingual with languages English (as default), and French.
  • Create page “Sandbox.P1” with language=“en” and set its title to “P1 title”.
  • Translate page to “fr” and set the the title to “P1 titre”.
  • Execute the script below with parameter language=en in the URL:
{{velocity}}
#set ($reference = $services.model.resolveDocument('Sandbox.P1'))
#set ($referenceWithLocale = $services.model.createDocumentReference($reference, $xcontext.locale))
#set ($page = $xwiki.getDocument($referenceWithLocale))
$page.displayTitle
{{/velocity}}

I would expect the script displays “P1 title”, but I keep getting “P1” instead. Does anyone have an explanation for this behaviour? (when language=fr is set in the URL, I get “P1 titre” as expected)

Cheers

I guess that you don’t have 2 version of the pages but 3:

  • 1 for en
  • 1 for fr
  • 1 default one (locale not set)

If you put language= in the URL what do you get? and with language=en?

Thank you surli, I was suspecting this as well but whatever language I set in the URL so far except language=fr, I keep getting “P1” as title output, never “P1 title”…

When looking at the XML of the “en” page, I see this:

<language/>
<defaultLanguage>en</defaultLanguage>
 <translation>0</translation>

and in XWiki.java:

    public XWikiDocument getDocument(DocumentReference reference, XWikiContext context) throws XWikiException
    {
        XWikiDocument doc = new XWikiDocument(
            reference.getLocale() != null ? new DocumentReference(reference, (Locale) null) : reference,
            reference.getLocale());

        doc.setContentDirty(true);

        return getDocument(doc, context);
    }

I’m wondering why the locale is set to null when it’s not null. Shouldn’t it be the other way round?

I think what you are missing is that the locale of the default version of a document is always “” (Locale.ROOT). Then the defaultLocale field contains the actual locale you want to associated to the document content (in your case en).

It’s not. The locale is passed as second parameter because the document reference and the locale are separated in XWikiDocument for historical reason.

1 Like

Thank you for this explanation, tmortagne. There’s still something that remains unclear to me: what is the canonical way to get a document in a given locale in all cases? Should the developer expect that the target document should exist with a default language plus in all available wiki languages? Should the default be empty in that case (for avoiding duplicated content)? Or should the developer test if a given locale matches the wiki default locale and fall back to the document with root locale in that specific case?

So I think in your case you should actually use:

#set ($reference = $services.model.resolveDocument('Sandbox.P1'))
#set ($page = $xwiki.getDocument($reference).getTranslatedDocument($context.locale))

It’s better since you let XWiki deal with the translation internally, without trying to build manually a reference that might be wrong in the end. Now I agree that it could be useful to have a proper API to get directly the right translated document given a reference and a locale.

1 Like

The code you suggest work indeed but at the cost of two documents loading instead of one, unless I’m mistaken? So we agree that an API would be useful, good, but what about the existing API method ModelScriptService#createDocumentReference(DocumentReference,Locale)? How is that API more manual than the one you suggest and why should a developer expect two different results?

Just trying to possibly contribute to the improvement of the developer experience, I understand it’s complex and that I may misunderstand the underpinnings…

Not if the default version is already the right one. Also with the document cache you don’t actually load documents very often in practice.

By the way you don’t need to pass the locale if it’s the context one:

#set ($page = $xwiki.getDocument(`Sandbox.P1`).getTranslatedDocument())

We already have that, you just have to pass a reference with the locale in it. But again don’t mix the document actual locale and the locale of the content of the default document. The reason to go trough the default version is when you don’t know the actual locale, if you know it then you can get it directly.

1 Like

Indeed, but what’s interesting in @slauriere example is that it really shows that the internal mechanism of managing locale is far from being obvious. Personally I’d say that the fact XWiki cannot find the document in the first snippet should be considered as a bug: the wiki is set as using english as default document language, the page is edited as such, so anyone would expect to get it when specifying “en” for locale.

1 Like

It’s not that simple, this is actually a pretty low level API right now and it’s perfectly possible technically to have both a default document with locale="" and defaultLocale=en and another instance with locale=en right now. It’s also important to remember that the XWikiDocument you get for the translations is not complete (it does not contain any attachment/object for example), that’s mainly why the default version of the document is at the center of the current API. So IMO it’s not as simple as adding a new getDocument with a boolean to fallback. A getDocumentContent which does that would be a lot easier to fit (we have that already in the DocumentAccessBridge).

I have the feeling what you are talking about require a new API completly which hide internal better that XWikiDocument or even Document does (which is something we need since a long time).

1 Like