Startseite > Techblog > Confluence > Umschalten der i18n Schlüssel-Wert Paare zur Laufzeit
are

Motivation

Beim Abändern von bestehenden Texten für Confluence muss der zugehörige Schlüssel bekannt sein. Um an diesen Schlüssel zu gelangen muss der Entwickler sich durch den Quellcode (Frontend) hangeln oder in den unzähligen properties-Dateien nach dem Text suchen. Es bedeutet somit einen relativ großen Aufwand, um Textanpassungen vorzunehmen. Verschärft wird diese Problematik durch das Outsourcing der Textanpassung an entsprechende Dienstleistungsunternehmen. Zumeist haben diese Firmen keinerlei Bezug zur Informatik, sodass eigenständige Recherchen nach den passenden Schlüssel-Wert Paaren nicht realistisch sind.
Optimal wäre eine Lösung, die es ermöglicht während der Laufzeit die Schlüssel-Wert Paare umzuschalten… und genau das beschreibe ich in den Teilen Umsetzung - Backend und Umsetzung - Frontend.

Umsetzung – Backend

Ein kleiner – aber wie ich finde vertretbarer – Wermutstropfen ist, dass es nicht ohne Anpassung des Confluence-Cores geht. Die abgeänderten Dateien, die nachfolgend erläutert werden, packt man am besten in eine jar und legt diese in das WEB-INF/lib Verzeichnis.

Erstellen einer ThreadLocale ShowI18NKeysThreadLocal

Die Aktivierung/Deaktivierung der Funktion wird über einen Schalter in der GUI realisiert. Damit der Zustand ins Backend übertragen werden kann, wird eine ThreadLocale verwendet. Diese ist wie folgt aufgebaut:

public class ShowI18NKeysThreadLocal {

  public static final ThreadLocal showI18nKeysLocal = new ThreadLocal () {
    protected synchronized Boolean initialValue() {
      return false;
    }
  };

}

Überschreiben der DefaultI18NBean Klasse

Die DefaultI18nBean besitzt u.a. eine Methode namens isShowKeyMode. Mit dieser Methode wird abgefragt, ob die Schlüssel-Wert Paare zurückgeliefert werden sollen. Nun vermutet man, dass die Methode aus einer Property, etc… den Zustand (aktiv, inaktiv) ausliest. Dies ist leider nicht der Fall, da sie immer den Wert false (hard-codiert) zurückliefert, sodass ohne dem Überschreiben der Methode ein Switch gar nicht möglich ist. Deshalb muss die Klasse wie folgt erweitert werden.

  public ExtendedDefaultI18NBean(Locale locale, PluginAccessor pluginManager) {
    super(locale, pluginManager);
  }

  @Override
  public boolean isShowKeyMode() {
    return ShowI18NKeysThreadLocal.showI18nKeysLocal.get();
  }

Überschreiben der DefaultI18NBeanFactory Klasse

Die Klasse DefaultI18NBean wird nicht wie die meisten Klassen per Spring Injection erzeugt, sondern über eine Factory-Klasse. Aus diesem Grund muss auch die DefaultI18NBeanFactory wie folgt überschrieben werden.

 public class ExtendedDefaultI18NBeanFactory implements I18NBeanFactory {

  private PluginAccessor pluginAccessor;

  public I18NBean getI18NBean(Locale locale) {
    return new ExtendedDefaultI18NBean(locale, pluginAccessor);
  }

  public I18NBean getI18NBean() {
    return getI18NBean(LocaleManager.DEFAULT_LOCALE);
  }

  public void setPluginAccessor(PluginAccessor pluginAccessor) {
    this.pluginAccessor = pluginAccessor;
  }

}

Anpassen der i18nContext.xml

Damit nun die von uns angepasste Factory-Klasse verwendet werden kann, muss in der i18nContext.xml der zugehörige Eintrag wie folgt angepasst werden:

<bean id="defaultI18NBeanFactory" class="de.communardo.customizations.i18n.ExtendedDefaultI18NBeanFactory" autowire="byName"/>

Anpassen der web.xml

Letztlich ist es noch notwendig, dass die web.xml auf die abgeänderte i18nContext.xml verweist. Dazu muss die entsprechende Zeile wie folgt angepasst werden.

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            ...,
            classpath:/customizedI18nContext.xml,
            ...,

Umsetzung – Frontend

Wie zuvor bereits erwähnt, zielt dieses Vorgehen auf eine Laufzeitlösung ab, sodass im Frontend ein entsprechender “Schalter” implementiert werden muss. In diesem Beispiel werden die Frontend-Anpassungen über ein Plugin durchgeführt.

Erstellen der ShowI18NKeyFilter Klasse

Der neue Filter hat einzig und allein die Aufgabe zu überprüfen, ob und auf welchen Wert der Request-Parameter showI18nKeys gesetzt ist. Sollte der Wert true sein, dann werden beim Reload der aktuellen Seiten nicht mehr nur die Texte, sondern auch die zugehörigen Schlüssel angezeigt. Außerdem wird der aktuelle Zustand in der Session vermerkt, sodass beim Seitenwechsel der gewünschte Zustand immernoch existiert. Natürlich wirkt sich die Zustandsänderung nur auf den aktuellen Nutzer aus und beeinflusst nicht die Sicht der anderer Nutzer!

public class ShowI18NKeyFilter implements Filter {

  private static final String I18N_KEYS = "showI18nKeys";

  private static final String CONFLUENCE_I18N_SHOWKEY = "confluence.i18n.showkey";

  public void destroy() {

  }

  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
      ServletException {

    if (request instanceof PluginHttpRequestWrapper) {
      PluginHttpRequestWrapper httpRequest = (PluginHttpRequestWrapper) request;
      Boolean showI18nKeysSession = (Boolean) httpRequest.getSession().getAttribute(CONFLUENCE_I18N_SHOWKEY);
      if (httpRequest.getParameter(I18N_KEYS) != null) {
        Boolean showI18nKeysRequest = Boolean.valueOf(httpRequest.getParameter(I18N_KEYS));
        if (showI18nKeysRequest != showI18nKeysSession) {
          if (showI18nKeysRequest) {
            httpRequest.getSession().setAttribute(CONFLUENCE_I18N_SHOWKEY, true);
            ShowI18NKeysThreadLocal.showI18nKeysLocal.set(true);
          } else {
            httpRequest.getSession().removeAttribute(CONFLUENCE_I18N_SHOWKEY);
            ShowI18NKeysThreadLocal.showI18nKeysLocal.set(false);
          }
        }
      } else {
        ShowI18NKeysThreadLocal.showI18nKeysLocal.set(showI18nKeysSession != null ? showI18nKeysSession : false);
      }
    }
    chain.doFilter(request, response);
  }

  public void init(FilterConfig arg0) throws ServletException {

  }

}

Anpassung einer vm Datei

Letztlich fehlt nur noch ein Link (am besten im Header, da diese Stelle auf fast allen Seiten sichtbar ist), welcher den GET-Parameter showI18nKeys konträr zum aktuellen Zustand den Wert auf true bzw. auf false übermitteln soll.

Kommentar Feed Trackback URL

Hinterlassen Sie einen Kommentar

Tag Cloud

Unsere Themen

Kommentare

  • Christian Heindel: Hallo Volti, die Option “Verbindung mit ‘Dokumentbibliothek̵ 7; herstellen”...
  • volti: Hi, ich hab das beschriebene Probleme mit Outlook 2010, dort finde ich die Option Aktionen >...
  • Michael Wittwer: Hallo Guter Beitrag, bin seit kurzem auch mit Balsamiq am arbeiten und die Effizienz ist einfach...
  • Frank: Danke, tut und ist im Vergleich zur Atlassian Lösung abwärtskompatibel bis Confluence 2.10.
  • Ghost@: Danke für die schnelle Antwort Martin! Das ist natürlich ärgerlich, dass der Datentyp nicht unterstützt ist....

Twitter