Bulk-update document default language

Last modified by Anca Luca on 2026/06/02 17:54

cog
Type
CategoryOther
Developed by

Clément Aubin

Rating
0 Votes
LicenseGNU Lesser General Public License 2.1

Table of contents

Description

This script will go through every document having a provided default language, and update each document to set their default language to a new value. The script will also skip updating documents coming from extensions, or documents having a translation in the targeted new default language, for which a manual resolution is required.

To use the script, create a new XWiki page and copy / paste the following content :

{{velocity}}
This script allows to perform bulk update of the default language used in documents in XWiki. Programming rights are required to execute this script.

{{html clean="false"}}
<form class="xform" action="#" method="post">
  <dl>
    <dt>
      <label for="currentDefault">Current default language</label>
      <span class="xHint">The script will look for every document in XWiki having the provided default language.</span>
    </dt>
    <dd>
      <input type="text" name="currentDefault" id="currentDefault" value="#if($request.currentDefault)$escapetool.xml($request.currentDefault)#end" />
    </dd>
    <dt>
      <label for="newDefault">New default language</label>
      <span class="xHint">For each identified document, XWiki will update the default language to the following.</span>
    </dt>
    <dd>
      <input type="text" name="newDefault" id="newDefault" value="#if($request.newDefault)$escapetool.xml($request.newDefault)#end" />
    </dd>
    <dt>
      <input id="savePages" name="savePages" type="checkbox" value="save"/> <label for="savePages">Save pages</label>
      <span class="xHint">By default, this script will execute in dry-mode, and will not save pages.</span>
    </dt>
  </dl>
  <p>
    <span class="buttonwrapper">
      <input type="hidden" name="form_token" value="$!{services.csrf.token}"/>
      <input type="hidden" name="confirm" value="true"/>
      <input class="button" type="submit" value="Update default language"/>
    </span>
  </p>
</form>
{{/html}}
{{/velocity}}

{{groovy}}
import com.xpn.xwiki.api.Document
import org.apache.commons.lang3.StringUtils
import org.xwiki.logging.LogLevel;

componentManager = services.component.getComponentManager();

if (hasProgramming && services.csrf.isTokenValid(request.form_token)) {
  // Check if we have enough to work on
  if (StringUtils.isNotBlank(request.currentDefault) && StringUtils.isNotBlank(request.newDefault)) {

    def currentDefaultLocale = new Locale(request.currentDefault);
    def newDefaultLocale = new Locale(request.newDefault);

    // Get every page matching the space
    def documents = services.query.hql('select doc.fullName from XWikiDocument doc where doc.defaultLanguage = :currentDefault').bindValue('currentDefault', request.currentDefault).execute();

    println(String.format('Found [%s] documents to update', documents.size()))
    documents.each { documentFullName ->
      try {
        Document document = xwiki.getDocument(documentFullName);
        println(String.format('* Verifying document [[%s]]', document.getDocumentReference()));

        // Check if the document comes from an extension
        def documentExtensions = services.extension.xar.getInstalledExtensions(document.getDocumentReferenceWithLocale());
        if (documentExtensions.size() == 0) {
          // Check if the document has also a translation in the new default locale
          def translatedDocuments = services.query.hql('select doc.fullName from XWikiDocument doc where doc.language = :newDefault').bindValue('newDefault', request.newDefault).execute();
          if (translatedDocuments.size() == 0) {
            document.getDocument().setDefaultLocale(newDefaultLocale);
            if ('save'.equals(request.savePages)) {
              document.save('Update document default language');
              println('** Saved document with new language');
            } else {
              println('** Running in dry mode, the document will not be updated');
            }
          } else {
            println('** A translation of the document already exists in the new default language, the document will thus not be updated by the script');
          }
        } else {
          println('** The document has been provided by extensions, it will thus not be updated by the script');
        }
      } catch (Exception e) {
        println(String.format('Uncaught exception [%s]', e));
      }
    }
  } else {
    println('Insufficient parameters. Please provide a target space and a search URL. Aborting.');
  }
} else {
  println('Insufficient permissions or invalid CSRF token. Aborting.');
}
{{/groovy}}

Get Connected