Gegenüber meines alten Blogeintrages zur Lokalisierung von NetBeans RCP Projekten ist es mit Maven sogar einfacher geworden ein Build einzurichten.
Wie auch damals, stehen zur Zeit keine deutschsprachigen Übersetzungen für NetBeans 6.9 RCP Projekte zur Verfügung. Kein Wunder, wir sind auch noch mitten im Development. Gerade mal eine Beta steht zur Zeit zur Verfügung. Übersetzungs-Projekte laufen erst gerade an.
Vorbereitungen
Wer ein Lokalisierungsmodul jetzt nachbauen will, sollte zwei Dinge sofort tun. Erstens die aktuelle Mercurial Version installieren und zweitens die Sprachdateien von hg.netbeans.org herunterladen. Der Mercurial-Download findet sich hier. NetBeans 6.9 dev nach der Installation von hg neu starten, damit der Installations-Pfad von hg gefunden wird. In NetBeans nun ein "Clone other" im Team-Menü/Mercurial ausführen. Das Repository ist hg.netbeans.org/release68/l10n/. User/Password bleibt leer, pull und push Path auf der nächsten Seite bleibt wie vorgeschlagen. Auf der letzten Seite einen passenden Pfad festlegen und den Haken Scan for NetBeans Projects entfernen. [Finish] anklicken und hier weiter lesen, das wird nämlich dauern (ein bis zwei Stunden).
Modul erstellen
Es wird zunächst ein ganz normales Maven based NetBeans RCP Module mit dem New Project Assistenten erzeugt. Da ich in diesem Fall ein Multimodule Projekt einrichte, wo das Sprachmodul direkt in der Platform zur Verfügung stehen soll, ist der beste Ort direkt unter dem Ordner des Maven Platform Projektes.
├───42
│ └───sxbase
│ ├───application
│ ├───branding
In meinem Fall ist sxbase das POM-Projekt (Maven Hauptprojekt für die Platform Applikation). Application ist die Platform-Suite und Branding übernimmt grundlegende Einrichtungen für Splash-Screen, Name der Anwendung, kleinere Lokalisierungen. Aber Branding eignet sich nicht generell für Sprach-Plugins. Besonders wenn man mehrere Sprachen in getrennten Plugins haben will.
Also wird das neue Modul unter sxbase angelegt.
Ich hatte mein deutschsprachiges Übersetzungsplugin i18n-de genannt, sinnvoller wäre vielleicht l10n-de. Aber letztendlich ist das egal, so lange es verstanden wird - und das wird sowieso über die Bundle.properties als Sprachtexte gesteuert.
nbm-branding Plugin
Das neue Modul kann aber so noch keine Bundle-Dateien verarbeiten, wie man es schon vom branding-Modul gewohnt ist. Zunächst muss man ein NetBeans Plugin für den Branding-Build-Prozess in der pom.xml hinterlegen:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>nbm-maven-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>branding</id>
<phase>process-resources</phase>
<goals>
<goal>branding</goal>
</goals>
<configuration>
<brandingToken>s3</brandingToken>
</configuration>
</execution>
</executions>
</plugin>
Der Branding Token kann ggf. weggelassen werden. Wichtig ist die Angabe der phase und das goal.
Resource Ordner einrichten
Nun braucht man zwingend unter dem src/main Ordner das Verzeichnis nbm-branding. Das macht man in der Files Ansicht (nicht im Project Explorer), öffnet dort den Ordner src/main und legt dort den Folder nbm-branding an.
Darunter benötigt man nun zwei Unterordner core und modules. Im core-Ordner wird das Branding für den Boot-Prozess (Splash usw) angelegt, in modules die Brandings für die Platform-Module.
Die Ordnerstruktur ist dann folgende:
src
├───main
│ └───nbm-branding
│ ├───core
│ ├───modules
Branding-Archive für Bundle-Dateien
Jetzt kommt ein recht ungewöhnlicher Aufbau der Unterordner für das Build der Spracharchive.
Alle Unterordner müssen exakt so heißen, wie die Original-Module, deren Ressourcen wir überschreiben wollen. Der Classloader von NetBeans überdeckt letztendlich die Bundle.properties der Original-Module mit den neuen Sparcharchiven gleichen Namens.
Zwei Beispiele: Im core-Ordner wird ein Unterordner angelegt, der core.jar heißt (mit der Endung .jar!). Im modules-Ordner benötigen wir z.B. org-netbeans-core-windows.jar als Unterordner. In diesen Ordnern müssen aber wieder alle package-Ebenen der Original-Module nachvollzogen werden.
Für core.jar:
core.jar
├───org
│ └───netbeans
│ └───core
│ └───startup
Und beispielsweise für org-netbeans-core-windows.jar:
org-netbeans-core-windows.jar
├───org
│ └───netbeans
│ └───core
│ └───windows
│ ├───actions
│ ├───options
│ ├───persistence
...
Bundles aus dem hg-Clone kopieren
Aber woher bekommt man a) die Namen der Module und b) die Strukturen der Unterordner?
Punkt a durch Raten und Vergleich, Punkt b durch kopieren. Es gibt zwar Java-Ant-Tasks, die aus den XML-Dateien der Platform-Module die Original Ordnerstrukturen ermitteln und damit die Original hg-Sprachdateien zu den Ziel-Archivnamen konvertieren, aber für dieses eine Sprachplugin habe ich die Methode "zu Fuß" durchgeführt. Zum einem, weil bei Maven-Platform Builds die Struktur der Mavenartifakte (und der Nutzung eines Firmenrepository für Platforms) eine direkte Umsetzung der Ant-Tasks nicht erlaubt und zum anderen, weil ich noch kein passendes Mojo fertig habe, dass die hg-Sprachbundles automatisiert kopiert.
Die Namen der platform Module (bitte beachten, NetBeans 6.9 hat keine Nummerierung der Cluster mehr. In NetBeans 6.8 war es noch platform11) finden sich im Installationsverzeichnis von NetBeans /platform/core und /platform/modules. Alle JAR-Dateien darin sind die englischen Versionen (d.h. nicht lokalisierten) Module einer RCP Basis Anwendung. Nun wirft man einen Blick in den hg-Ordner, in dem die Multilanguage Sprachprojekte geclont wurden:
local
├───l10n
│ ├───.hg
│ ├───antsrc
│ ├───l10n_uc_kits
│ └───src
│ └───de
│ └───platform11
Da ich ja ein clone von NetBeans 6.8 vorgenommen habe, heißt es hier platform11.
Einige Unterordner habe schon eine passende tld-package-package-module Bezeichnung ohne die Endung .jar. Andere Ordner heißen nur print oder javahelp. Hier hilft nur "Educated Guess". Die Namen der Ordner aus den hg-Verzeichnissen müssen in die Modulordnernamen mit der Endung .jar umgesetzt werden. Das nächste Problem ist, dass teilweise in den Ordnern der Name des Spracharchiv wiederholt wird oder direkt mit der Packagestruktur begonnen wird. Das ist alles historisches Chaos von falscher Strukturierung.
Was muss also gemacht werden? Nehmen wir ein einfaches Beispiel mit org-netbeans-core-windows.
Struktur in hg:
org-netbeans-core-windows
├───org-netbeans-core-windows
│ └───org
│ └───netbeans
│ └───core
│ └───windows
...
Wir legen in unserem Maven-Projekt den Ordner org-netbeans-core-windows.jar an und kopieren alles ab dem org-Ordner dort hinein. damit haben wir folgende neue Ordnerstruktur:
org-netbeans-core-windows.jar
├───org
│ └───netbeans
│ └───core
│ └───windows
...
Das machen wir mit allen Ordnern, die wir so einfach erkennen können.
Jetzt zu den komplizierteren Fällen. Ein Beispiel im hg:
javahelp
├───javahelp
│ └───org
│ └───netbeans
│ └───modules
│ └───javahelp
...
Wir schauen in das NetBeans69/platform/modules Verzeichnis und finden das JAR org-netbeans-modules-javahelp.jar. Also haben wir den neuen Namen im Projekt:
org-netbeans-modules-javahelp.jar
├───org
│ └───netbeans
│ └───modules
│ └───javahelp
...
Na ja, ich habe für die ganzen Umstellungen 30 Minuten gebraucht. Langweilige Fleißarbeit und fast schlimmer als HTML coden, aber für das erste Beispiel machbar. So weiß man auch, wie man mal ein zukünftiges Mojo schreiben muss.
Folgende Mappings müssen berücksichtigt werden:
Ordner Modules | |
| |
org-jdesktop-layout | org-jdesktop-layout.jar |
org-netbeans-api-annotations-common | org-netbeans-api-annotations-common.jar |
org-netbeans-api-progress | org-netbeans-api-progress.jar |
org-netbeans-api-visual | org-netbeans-api-visual.jar |
org-netbeans-core-execution | org-netbeans-core-execution.jar |
org-netbeans-core-io-ui | org-netbeans-core-io-ui.jar |
org-netbeans-core-multiview | org-netbeans-core-multiview.jar |
org-netbeans-core-nativeaccess | org-netbeans-core-nativeaccess.jar |
org-netbeans-core-output2 | org-netbeans-core-output2.jar |
org-netbeans-core-ui | org-netbeans-core-ui.jar |
org-netbeans-core-windows | org-netbeans-core-windows.jar |
org-netbeans-core | org-netbeans-core.jar |
org-netbeans-libs-jna | org-netbeans-libs-jna.jar |
org-netbeans-libs-jsr223 | org-netbeans-libs-jsr223.jar |
org-netbeans-libs-junit4 | org-netbeans-libs-junit4.jar |
applemenu | org-netbeans-modules-applemenu.jar |
autoupdate-services | org-netbeans-modules-autoupdate-services.jar |
autoupdate-ui | org-netbeans-modules-autoupdate-ui.jar |
core-kit | org-netbeans-modules-core-kit.jar |
editor-mimelookup-impl | org-netbeans-modules-editor-mimelookup-impl.jar |
editor-mimelookup | org-netbeans-modules-editor-mimelookup.jar |
favorites | org-netbeans-modules-favorites.jar |
javahelp | org-netbeans-modules-javahelp.jar |
masterfs | org-netbeans-modules-masterfs.jar |
options-api | org-netbeans-modules-options-api.jar |
options-keymap | org-netbeans-modules-options-keymap.jar |
print | org-netbeans-modules-print.jar |
progress-ui | org-netbeans-modules-progress-ui.jar |
queries | org-netbeans-modules-queries.jar |
sendopts | org-netbeans-modules-sendopts.jar |
settings | org-netbeans-modules-settings.jar |
spi-actions | org-netbeans-modules-spi-actions.jar |
templates | org-netbeans-modules-templates.jar |
org-netbeans-spi-quicksearch | org-netbeans-spi-quicksearch.jar |
org-netbeans-swing-outline | org-netbeans-swing-outline.jar |
org-netbeans-swing-plaf | org-netbeans-swing-plaf.jar |
org-netbeans-swing-tabcontrol | org-netbeans-swing-tabcontrol.jar |
org-openide-actions | org-openide-actions.jar |
org-openide-awt | org-openide-awt.jar |
org-openide-compat | org-openide-compat.jar |
org-openide-dialogs | org-openide-dialogs.jar |
org-openide-execution | org-openide-execution.jar |
org-openide-explorer | org-openide-explorer.jar |
org-openide-io | org-openide-io.jar |
org-openide-loaders | org-openide-loaders.jar |
org-openide-nodes | org-openide-nodes.jar |
org-openide-options | org-openide-options.jar |
org-openide-text | org-openide-text.jar |
org-openide-util-enumerations | org-openide-util-enumerations.jar |
org-openide-windows | org-openide-windows.jar |
org-openide-util | org-openide-util.jar |
org-openide-modules | org-openide-modules.jar |
| |
| |
Ordner Core | |
| |
org-openide-filesystems | org-openide-filesystems.jar |
org-netbeans-core-startup | core.jar |
| |
| |
Kein Java Archive Build | |
| |
org-netbeans-bootstrap | Ist für die native Startdatei nbexec.exe |
Hat man diese gesamten Kopieraktionen erfolgreich durchgeführt, ist das Projekt vollständig, d.h. alle Plattform Übersetzungen wurden so in das Deutschsprachige übersetzt. Die Bundle-Dateien, die aus dem hg-Ordnern kopiert wurden, tragen alle schon das Kennzeichen _de im Namen. Das ist wichtig, damit die Bundles zu den passenden Sprachen geladen werden.
Nun kann man im eigenen Projekt noch Applikationsnamen anpassen, ein paar Rechtschreibfehler korrigieren oder komplett Wörter ändern, um diese einer unternehmensweiten Sprachregelung anzupassen.
Für alle, die sich nicht dir Mühe machen wollen, die Ordner für die Spracharchive aufzubauen, habe ich hier eine kleine ZIP-Datei. Kleinere Teile müssten angepasst werden. Die splash-Grafik fehlt und ###APPLICATION NAME### steht überall dort, wo der Applikationsname eingesetzt werden muss. Außerdem sollte man nach www.example.com suchen und ersetzen (wird im About-Dialog verwendet). Das ZIP-Archiv wird direkt in das src/main Verzeichnis extrahiert. Wer es nutzt kann ja mal ein Kommentar hier hinterlassen, an sonsten ist die Lizenz CDDL und GPL v2 mit Classpath Exception. So wie die Originaldateien.
Beste Grüße,
Josch.