annotated tag v1.0.0 created (now 5412e3a)
This is an automated email from the git hooks/post-receive script. New change to annotated tag v1.0.0 in repository i18n. See https://gitlab.nuiton.org/nuiton/i18n.git at 5412e3a (tag) tagging e34d86e46baca4a13c40384c91b80035bba348d0 (commit) tagged by Tony Chemit on Sat Aug 22 23:35:30 2009 +0000 - Log ----------------------------------------------------------------- fi xurl in tags... ----------------------------------------------------------------------- This annotated tag includes the following new commits: new e34d86e fi xurl in tags... The 1 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Detailed log of new commits: commit e34d86e46baca4a13c40384c91b80035bba348d0 Author: Tony Chemit <chemit@codelutin.com> Date: Sat Aug 22 23:35:30 2009 +0000 fi xurl in tags... -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
This is an automated email from the git hooks/post-receive script. New commit to annotated tag v1.0.0 in repository i18n. See https://gitlab.nuiton.org/nuiton/i18n.git commit e34d86e46baca4a13c40384c91b80035bba348d0 Author: Tony Chemit <chemit@codelutin.com> Date: Sat Aug 22 23:35:30 2009 +0000 fi xurl in tags... --- LICENSE.txt | 166 ++++ README.txt | 3 + changelog.txt | 2 + maven-i18n-plugin/LICENSE.txt | 166 ++++ maven-i18n-plugin/README.txt | 2 + maven-i18n-plugin/changelog.txt | 44 + maven-i18n-plugin/pom.xml | 125 +++ .../org/nuiton/i18n/plugin/AbstractI18nPlugin.java | 282 +++++++ .../main/java/org/nuiton/i18n/plugin/Bundle.java | 361 ++++++++ .../main/java/org/nuiton/i18n/plugin/Generate.java | 144 ++++ .../main/java/org/nuiton/i18n/plugin/Getter.java | 115 +++ .../java/org/nuiton/i18n/plugin/I18nArtifact.java | 100 +++ .../java/org/nuiton/i18n/plugin/I18nLogger.java | 117 +++ .../i18n/plugin/parser/AbstractI18nParser.java | 369 ++++++++ .../java/org/nuiton/i18n/plugin/parser/Parser.java | 55 ++ .../org/nuiton/i18n/plugin/parser/ParserEvent.java | 59 ++ .../nuiton/i18n/plugin/parser/ParserException.java | 45 + .../i18n/plugin/parser/event/KeysModifier.java | 219 +++++ .../nuiton/i18n/plugin/parser/impl/ParserJava.java | 164 ++++ .../plugin/parser/impl/ParserJavaActionConfig.java | 87 ++ .../plugin/parser/impl/ParserJavaTabConfig.java | 35 + .../nuiton/i18n/plugin/parser/impl/ParserJaxx.java | 113 +++ .../i18n/plugin/parser/impl/ParserSwixat.java | 104 +++ .../i18n/plugin/parser/impl/ParserValidation.java | 194 +++++ .../nuiton/i18n/plugin/parser/impl/ParserXml.java | 255 ++++++ .../services/org.apache.commons.logging.LogFactory | 1 + maven-i18n-plugin/src/main/resources/jaxx.rules | 37 + .../src/main/resources/log4j.properties | 10 + maven-i18n-plugin/src/main/resources/swixat.rules | 33 + .../src/main/resources/validation.rules | 3 + .../src/main/resources/xwork-validator-1.0.2.dtd | 42 + maven-i18n-plugin/src/site/apt/index.apt | 42 + maven-i18n-plugin/src/site/apt/usages.apt | 8 + maven-i18n-plugin/src/site/site.xml | 46 + nuiton-i18n-api/LICENSE.txt | 166 ++++ nuiton-i18n-api/README.txt | 2 + nuiton-i18n-api/changelog.txt | 2 + nuiton-i18n-api/doc/FormatConverter-uml.uxf | 34 + nuiton-i18n-api/pom.xml | 102 +++ .../src/main/java/org/nuiton/i18n/CountryEnum.java | 284 +++++++ .../org/nuiton/i18n/I18nDefaultTooltipFilter.java | 43 + .../main/java/org/nuiton/i18n/I18nFileReader.java | 131 +++ .../src/main/java/org/nuiton/i18n/I18nFilter.java | 37 + .../src/main/java/org/nuiton/i18n/I18nUtil.java | 194 +++++ .../main/java/org/nuiton/i18n/LanguageEnum.java | 181 ++++ .../java/org/nuiton/i18n/bundle/I18nBundle.java | 160 ++++ .../org/nuiton/i18n/bundle/I18nBundleEntry.java | 192 +++++ .../org/nuiton/i18n/bundle/I18nBundleFactory.java | 613 ++++++++++++++ .../org/nuiton/i18n/bundle/I18nBundleScope.java | 144 ++++ .../main/java/org/nuiton/util/LocaleConverter.java | 126 +++ .../org.apache.commons.beanutils.Converter | 1 + nuiton-i18n-api/src/site/apt/index.apt | 20 + nuiton-i18n-api/src/site/site.xml | 33 + .../nuiton/i18n/bundle/I18nBunsleScopeTest.java | 63 ++ .../java/org/nuiton/util/LocaleConverterTest.java | 124 +++ .../src/test/resources/log4j.properties | 11 + nuiton-i18n-editor/LICENSE.txt | 674 +++++++++++++++ nuiton-i18n-editor/README.txt | 2 + nuiton-i18n-editor/changelog.txt | 8 + nuiton-i18n-editor/pom.xml | 384 +++++++++ nuiton-i18n-editor/src/main/assembly/bin.xml | 53 ++ nuiton-i18n-editor/src/main/assembly/go.bat | 1 + nuiton-i18n-editor/src/main/assembly/go.sh | 4 + .../src/main/filters/nuiton-i18n-editor.properties | 78 ++ .../java/org/nuiton/i18n/editor/I18nEditor.java | 201 +++++ .../org/nuiton/i18n/editor/I18nEditorConfig.java | 340 ++++++++ .../org/nuiton/i18n/editor/I18nEditorContext.java | 343 ++++++++ .../i18n/editor/project/AbstractI18nProject.java | 425 ++++++++++ .../project/AbstractI18nProjectProvider.java | 107 +++ .../nuiton/i18n/editor/project/I18nProject.java | 198 +++++ .../project/I18nProjectConfigurePanelUI.java | 40 + .../i18n/editor/project/I18nProjectFactory.java | 177 ++++ .../i18n/editor/project/I18nProjectProvider.java | 120 +++ .../editor/project/impl/DirectoryI18nProject.java | 67 ++ .../impl/DirectoryI18nProjectConfigurePanelUI.jaxx | 94 +++ .../project/impl/DirectoryI18nProjectProvider.java | 124 +++ .../i18n/editor/project/impl/JarI18nProject.java | 86 ++ .../impl/JarI18nProjectConfigurePanelUI.jaxx | 106 +++ .../project/impl/JarI18nProjectProvider.java | 186 ++++ .../i18n/editor/ui/BundleCheckBoxMenuUI.jaxx | 56 ++ .../org/nuiton/i18n/editor/ui/BundleValueUI.css | 52 ++ .../org/nuiton/i18n/editor/ui/BundleValueUI.jaxx | 87 ++ .../org/nuiton/i18n/editor/ui/BundleValuesUI.jaxx | 54 ++ .../org/nuiton/i18n/editor/ui/CreateBundleUI.css | 43 + .../org/nuiton/i18n/editor/ui/CreateBundleUI.jaxx | 80 ++ .../org/nuiton/i18n/editor/ui/CreatePackageUI.css | 40 + .../org/nuiton/i18n/editor/ui/CreatePackageUI.jaxx | 72 ++ .../org/nuiton/i18n/editor/ui/I18nEditorUI.css | 260 ++++++ .../org/nuiton/i18n/editor/ui/I18nEditorUI.jaxx | 343 ++++++++ .../nuiton/i18n/editor/ui/I18nEditorUIHandler.java | 937 +++++++++++++++++++++ .../i18n/editor/ui/PackageCheckBoxMenuUI.jaxx | 66 ++ .../org/nuiton/i18n/editor/ui/PropertieNode.java | 122 +++ .../nuiton/i18n/editor/ui/PropertiesTreeModel.java | 199 +++++ .../org/nuiton/i18n/editor/ui/TreeModelMode.java | 36 + .../nuiton/i18n/editor/ui/project/ProjectStep.java | 67 ++ .../nuiton/i18n/editor/ui/project/ProjectUI.css | 59 ++ .../nuiton/i18n/editor/ui/project/ProjectUI.jaxx | 299 +++++++ .../i18n/editor/ui/project/ProjectUIModel.java | 301 +++++++ .../editor/ui/project/SelectBundlesTableModel.java | 196 +++++ .../ui/project/tabs/AbstractProjectTabPanelUI.css | 41 + .../ui/project/tabs/AbstractProjectTabPanelUI.jaxx | 88 ++ .../ui/project/tabs/ChooseProjectTypePanelUI.jaxx | 72 ++ .../ui/project/tabs/ConfigureProjectPanelUI.jaxx | 70 ++ .../editor/ui/project/tabs/PersistPanelUI.jaxx | 174 ++++ .../i18n/editor/ui/project/tabs/ResumePanelUI.jaxx | 57 ++ .../ui/project/tabs/SelectBundlesPanelUI.jaxx | 57 ++ nuiton-i18n-editor/src/main/jnlp/jxlayer.jnlp | 12 + nuiton-i18n-editor/src/main/jnlp/sun.jnlp | 12 + ....nuiton.i18n.editor.project.I18nProjectProvider | 2 + .../i18n/nuiton-i18n-editor-en_GB.properties | 120 +++ .../i18n/nuiton-i18n-editor-fr_FR.properties | 120 +++ .../src/main/resources/icons/action-about.png | Bin 0 -> 936 bytes .../src/main/resources/icons/action-accept.png | Bin 0 -> 781 bytes .../src/main/resources/icons/action-add.png | Bin 0 -> 733 bytes .../src/main/resources/icons/action-calculator.png | Bin 0 -> 543 bytes .../src/main/resources/icons/action-cancel.png | Bin 0 -> 587 bytes .../src/main/resources/icons/action-close.png | Bin 0 -> 688 bytes .../src/main/resources/icons/action-closeTab.png | Bin 0 -> 518 bytes .../main/resources/icons/action-collapseAll.png | Bin 0 -> 372 bytes .../main/resources/icons/action-combobox-reset.png | Bin 0 -> 396 bytes .../main/resources/icons/action-combobox-sort.png | Bin 0 -> 574 bytes .../src/main/resources/icons/action-config.png | Bin 0 -> 611 bytes .../resources/icons/action-connect_creating.png | Bin 0 -> 1099 bytes .../src/main/resources/icons/action-connect_no.png | Bin 0 -> 601 bytes .../src/main/resources/icons/action-connect_ok.png | Bin 0 -> 619 bytes .../resources/icons/action-connect_untested.png | Bin 0 -> 698 bytes .../src/main/resources/icons/action-connected.png | Bin 0 -> 748 bytes .../src/main/resources/icons/action-db-change.png | Bin 0 -> 763 bytes .../src/main/resources/icons/action-db-local.png | Bin 0 -> 806 bytes .../src/main/resources/icons/action-db-none.png | Bin 0 -> 659 bytes .../src/main/resources/icons/action-db-remote.png | Bin 0 -> 755 bytes .../src/main/resources/icons/action-delete.png | Bin 0 -> 783 bytes .../src/main/resources/icons/action-edit.png | Bin 0 -> 574 bytes .../src/main/resources/icons/action-exit.png | Bin 0 -> 830 bytes .../src/main/resources/icons/action-expandAll.png | Bin 0 -> 371 bytes .../main/resources/icons/action-fileChooser.png | Bin 0 -> 441 bytes .../src/main/resources/icons/action-fullscreen.png | Bin 0 -> 687 bytes .../src/main/resources/icons/action-go-back.png | Bin 0 -> 345 bytes .../src/main/resources/icons/action-go-detail.png | Bin 0 -> 576 bytes .../src/main/resources/icons/action-go-down.png | Bin 0 -> 379 bytes .../src/main/resources/icons/action-go-jump.png | Bin 0 -> 723 bytes .../src/main/resources/icons/action-go-up.png | Bin 0 -> 372 bytes .../src/main/resources/icons/action-help.png | Bin 0 -> 746 bytes .../src/main/resources/icons/action-i18n-es.png | Bin 0 -> 469 bytes .../src/main/resources/icons/action-i18n-fr.png | Bin 0 -> 545 bytes .../src/main/resources/icons/action-i18n-gb.png | Bin 0 -> 599 bytes .../src/main/resources/icons/action-import-gps.png | Bin 0 -> 923 bytes .../main/resources/icons/action-information.png | Bin 0 -> 778 bytes .../resources/icons/action-leave-fullscreen.png | Bin 0 -> 727 bytes .../main/resources/icons/action-local-export.png | Bin 0 -> 528 bytes .../main/resources/icons/action-local-import.png | Bin 0 -> 532 bytes .../main/resources/icons/action-mode-create.png | Bin 0 -> 714 bytes .../src/main/resources/icons/action-mode-read.png | Bin 0 -> 779 bytes .../main/resources/icons/action-mode-update.png | Bin 0 -> 813 bytes .../src/main/resources/icons/action-next-step.png | Bin 0 -> 676 bytes .../src/main/resources/icons/action-open.png | Bin 0 -> 693 bytes .../main/resources/icons/action-previous-step.png | Bin 0 -> 655 bytes .../main/resources/icons/action-remote-export.png | Bin 0 -> 755 bytes .../main/resources/icons/action-remote-import.png | Bin 0 -> 770 bytes .../src/main/resources/icons/action-revert.png | Bin 0 -> 780 bytes .../src/main/resources/icons/action-save.png | Bin 0 -> 838 bytes .../resources/icons/action-select-ssl-cert.png | Bin 0 -> 693 bytes .../src/main/resources/icons/action-show-help.png | Bin 0 -> 744 bytes .../src/main/resources/icons/action-site.png | Bin 0 -> 928 bytes .../src/main/resources/icons/action-synch.png | Bin 0 -> 912 bytes .../main/resources/icons/action-synchro-pause.png | Bin 0 -> 598 bytes .../main/resources/icons/action-synchro-start.png | Bin 0 -> 592 bytes .../main/resources/icons/action-synchro-stop.png | Bin 0 -> 403 bytes .../src/main/resources/icons/action-translate.png | Bin 0 -> 790 bytes .../main/resources/icons/action-unconnected.png | Bin 0 -> 796 bytes .../src/main/resources/icons/action-validate.png | Bin 0 -> 537 bytes .../src/main/resources/icons/logo OT_rvb.png | Bin 0 -> 143337 bytes .../src/main/resources/icons/logo-OT_web.png | Bin 0 -> 34309 bytes .../src/main/resources/icons/logo_ird.png | Bin 0 -> 12384 bytes .../src/main/resources/log4j.properties | 14 + nuiton-i18n-editor/src/site/apt/index.apt | 25 + nuiton-i18n-editor/src/site/site.xml | 51 ++ pom.xml | 147 ++++ src/site/site.xml | 36 + 179 files changed, 14496 insertions(+) diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..d046c31 --- /dev/null +++ b/README.txt @@ -0,0 +1,3 @@ +To deploy new version of pom: mvn clean deploy -DperformRelease +To install localy: mvn clean install + diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 0000000..a35341f --- /dev/null +++ b/changelog.txt @@ -0,0 +1,2 @@ +1.0.0 xxx xxx + * Initial release (merge of previous lutin projects) \ No newline at end of file diff --git a/maven-i18n-plugin/LICENSE.txt b/maven-i18n-plugin/LICENSE.txt new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/maven-i18n-plugin/LICENSE.txt @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/maven-i18n-plugin/README.txt b/maven-i18n-plugin/README.txt new file mode 100644 index 0000000..d2e50d3 --- /dev/null +++ b/maven-i18n-plugin/README.txt @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install diff --git a/maven-i18n-plugin/changelog.txt b/maven-i18n-plugin/changelog.txt new file mode 100644 index 0000000..6156fa8 --- /dev/null +++ b/maven-i18n-plugin/changelog.txt @@ -0,0 +1,44 @@ +1.0.0 ? + * migrate to groupId org.nuiton + +0.12 chemit 20090511 + * bump versions (lutinproject, lutinprocessor, maven-license-switcher-plugin) + * improve download section on site + * update site + * introduce bundle goal to merge all bundle into one for final application + * no more use of bundles property, prefer locales one (with real Locale object instead of simple String one...) + +0.11 chemit 20090311 + * 20090420 [chemit] - bump versions + * 20090417 [chemit] - replace bundles parameters from tyep String[] to String type to make easier configuration + - use lutinproject 3.5.xx + - use lutinpluginutil 0.4 + +0.10 chemit 20090311 + * 20090223 [chemit] will skip get and gen goal if no getters were registred while parsing goals +0.9 chemit 20090218 + * 20090217 [chemit] use project.build.sourceEncoding instead of maven.compile.encoding as default encoding + * 20090214 [chemit] add safeMode, showTouchedFiles properties in parser mojo (none safeMode will improve performance) + * 20090205 [chemit] use lutinproject 3.4 +0.8 chemit 20090107 + * 20081205 [chemit] modify ParserValidation (message can by suffix by ## to delimite args) + +0.7 chemit 20081117 + * 20081205 [chemit] use lutinpluginproject 3.2 +ver-0-7 chemit 20081117 + * 20081118 [chemit] use lutinpluginproject 3.1 + * 20081026 [chemit] add xworks validator parse + * 20081026 [chemit] improve parser mojo logging + +ver-0-6 thimel 20080922 + * 20080925 [chemit] Using lutinpluginutil 0.2 and license-switcher in pom (no more in superpom) + * 20080922 [thimel] Using lutinpluginproject 3.0 + +ver-0-5 chemit 20080824 + * 20080824 [chemit] refactoring code + unificiation des reader et writer pour que cela fonctionne en utf8 + * 20080824 [chemit] suppresion dependance lutinutil + * 20080824 [chemit] passage du projet en utf8 + * 20080824 [chemit] passage en maven 2 layout directory + +ver-0-4 + * [chemit] pas maintenu avant ! diff --git a/maven-i18n-plugin/pom.xml b/maven-i18n-plugin/pom.xml new file mode 100644 index 0000000..b3e19f6 --- /dev/null +++ b/maven-i18n-plugin/pom.xml @@ -0,0 +1,125 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + <parent> + <groupId>org.nuiton</groupId> + <artifactId>i18n</artifactId> + <version>1.0.0</version> + </parent> + + <groupId>org.nuiton.i18n</groupId> + <artifactId>maven-i18n-plugin</artifactId> + + <dependencies> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>nuiton-i18n-api</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.nuiton.processor</groupId> + <artifactId>nuiton-processor</artifactId> + </dependency> + + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>maven-helper-plugin</artifactId> + <type>maven-plugin</type> + </dependency> + + <dependency> + <groupId>xalan</groupId> + <artifactId>xalan</artifactId> + </dependency> + + <dependency> + <groupId>commons-collections</groupId> + <artifactId>commons-collections</artifactId> + </dependency> + + <!-- tests dependencies --> + + <!--dependency> + <groupId>org.nuiton</groupId> + <artifactId>maven-helper-plugin</artifactId> + <classifier>tests</classifier> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency--> + + <!-- provided dependencies --> + + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-project</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-plugin-api</artifactId> + </dependency> + + <!-- FIXME si on ne le rajoute pas, on se retrouve avec la version 1.1 qui ne convient pas --> + <dependency> + <groupId>org.codehaus.plexus</groupId> + <artifactId>plexus-utils</artifactId> + </dependency> + + </dependencies> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + <name>nuiton-i18n - maven plugin</name> + <description> + Plugin pour maven 2 de génération des bundles pour l'internationnalisation (i18n) des applications java + basé sur nuiton-i18n-api. + </description> + <inceptionYear>2007</inceptionYear> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + + <packaging>maven-plugin</packaging> + + <build> + <defaultGoal>install</defaultGoal> + + <plugins> + + <!-- plugin plugin --> + <plugin> + <artifactId>maven-plugin-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>helpmojo</goal> + </goals> + </execution> + </executions> + </plugin> + + </plugins> + + </build> + + <reporting> + <plugins> + <plugin> + <artifactId>maven-plugin-plugin</artifactId> + </plugin> + </plugins> + </reporting> + +</project> diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/AbstractI18nPlugin.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/AbstractI18nPlugin.java new file mode 100644 index 0000000..fa7e63a --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/AbstractI18nPlugin.java @@ -0,0 +1,282 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package org.nuiton.i18n.plugin; + +import org.apache.maven.plugin.AbstractMojo; +import org.nuiton.i18n.plugin.parser.ParserEvent; +import org.nuiton.i18n.I18nUtil; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Properties; +import java.util.SortedSet; +import org.nuiton.util.PluginHelper; + +/** + * Classe permettant d'obenir les parametres pendant les différentes phases + * du plugin. + * + * @author julien + */ +public abstract class AbstractI18nPlugin extends AbstractMojo { + + /** + * Le nombre de getters détectés pendant le cycle de vie du build. + */ + private static int NB_GETTER_FILES = 0; + /** + * Répertoire de stockage des fichiers i18n pour la recuperation des fichiers + * de traduction entre librairie + */ + protected static final String DIRECTORY_INSTALL = "i18n" + File.separatorChar; + /** + * Nom du projet. + * + * @parameter expression="${i18n.artifactId}" default-value="${project.artifactId}" + * @readonly + */ + protected String artifactId; + /** + * Langues des bundles generes. + * <p/> + * + * @parameter expression="${i18n.bundles}" default-value="fr_FR,en_GB" + * @required + */ + protected String bundles; + /** + * Repertoire sources des fichiers i18n. + * + * @parameter expression="${i18n.src}" default-value="${basedir}/src/main/resources/i18n" + * @required + */ + protected File src; + /** + * Repertoire des fichiers generes i18n. + * + * @parameter expression="${i18n.out}" default-value="${basedir}/target/generated-sources/i18n" + * @required + */ + protected File out; + /** + * encoding a utiliser pour charger et sauver les bundles + * + * @parameter expression="${i18n.encoding}" default-value="${project.build.sourceEncoding}" + * @required + */ + protected String encoding; + /** + * Met les fichiers generes dans le repertoire des sources i18n. + * <p/> + * Note: Par défaut active, pour pouvoir paquager avec les bundles mis a jour. + * + * @parameter expression="${i18n.genSrc}" default-value="true" + */ + protected boolean genSrc; + /** + * Active la modification de cle. + * <p/> + * Note: par defaut, on ne l'active pas (build sur serveur non ui). + * + * @parameter expression="${i18n.keysModifier}" default-value="false" + */ + protected boolean keysModifier; + /** + * verbose flag + * <p/> + * Note: si non renseigne, on utilise la propiété <code>maven.verbose</code>. + * + * @parameter expression="${i18n.verbose}" default-value="${maven.verbose}" + */ + protected boolean verbose; + /** + * silent flag + * + * @parameter expression="${i18n.silent}" default-value="false" + * @since 1.0.0-rc-5 + */ + protected boolean silent; + /** + * conserve les anciens fichiers de traduction avec un suffix ~ + * <p/> + * Note: par defaut, on ne l'active pas. + * + * @parameter expression="${i18n.keepBackup}" default-value="false" + */ + protected boolean keepBackup; + /** + * ne conserve que les clef scannees (et donc traite tous les fichiers) + * + * <p/> + * Note : par default, on ne l'active car rescanne tous les fichiers. + *s + * @parameter expression="${i18n.strictMode}" default-value="false" + */ + protected boolean strictMode; + /** Liste des évènements */ + protected List<ParserEvent> events = new ArrayList<ParserEvent>(); + protected Locale[] locales; + /**logger verbeux */ + protected I18nLogger verboseLog; + + /** + * Ajoute un évènement + * + * @param parserEvent l'évènement d'ajout + */ + protected void addParserEvent(ParserEvent parserEvent) { + this.events.add(parserEvent); + } + + /** + * Supprime un évènement + * + * @param parserEvent l'évènement de suppression + */ + protected void removeParserEvent(ParserEvent parserEvent) { + this.events.remove(parserEvent); + } + + public void init() { + + verboseLog = new I18nLogger(this); + + if (verbose) { + getLog().info("config - verbose mode is on"); + } + locales = I18nUtil.parseLocales(bundles); + } + + public String getArtifactId() { + return artifactId; + } + + /** + * + * @return <code>true</code> si des getters ont etes enregistres pendant + * le cycle de vie, <code>false</code> sinon. + */ + protected boolean needGeneration() { + boolean needGeneration = NB_GETTER_FILES > 0; + return needGeneration; + } + + /** + * Prend en compte qu'un getter a été détecté. + * + * Cela veut dire qu'un goal de parser a détecté des clefs. Il + * faudra donc activer les goal get et gen. + */ + protected void addGetter() { + NB_GETTER_FILES++; + } + + protected I18nLogger getVerboseLog() { + return verboseLog; + } + + /** + * @param root le repertoire ou sont stockes les fichiers i18n + * @param artifactId le nom de l'artifact + * @param locale le nom du bundle + * @param create <code>true</code> pour creer le fichier si non present + * @return le fichier i18n + * @throws java.io.IOException si probleme lors de la creation du fichier + */ + public File getI18nFile(File root, String artifactId, Locale locale, boolean create) throws IOException { + File file = new File(root.getAbsolutePath() + File.separatorChar + artifactId + "-" + locale.toString() + ".properties"); + if (create && !file.exists()) { + if (!file.exists()) { + file.getParentFile().mkdirs(); + } + file.createNewFile(); + } + return file; + } + + /** + * @param root le repertoire ou sont stockes les fichiers getter + * @param getter le nom du getter + * @param create <code>true</code> pour creer le fichier si non present + * @return le fichier i18n + * @throws java.io.IOException si probleme lors de la creation du fichier + */ + public File getGetterFile(File root, String getter, boolean create) throws IOException { + File file = new File(root.getAbsolutePath() + File.separatorChar + getter); + if (create && !file.exists()) { + if (!file.exists()) { + file.getParentFile().mkdirs(); + } + file.createNewFile(); + } + return file; + } + + /** + * @param root le repertoire ou sont stockes les fichiers getter + * @param getter le nom du getter + * @return le fichier i18n + */ + public File getGetterFileBackup(File root, String getter) { + return new File(root.getAbsolutePath() + File.separatorChar + getter + '~'); + } + + /** + * @param root le reertoire ou sont stockes les fichiers i18n + * @param artifactId le nom de l'artifact + * @param bundle le nom du bundle + * @return le fichier i18n de backup + */ + public File getI18nFileBackup(File root, String artifactId, Locale bundle) { + return new File(root.getAbsolutePath() + File.separatorChar + artifactId + "-" + bundle.toString() + ".properties~"); + } + + protected void checkBundle(Locale locale, Properties propertiesOut, boolean showEmpty) { + // on verifie qu'il n'y a pas de traduction vide + SortedSet<String> emptyEntries = PluginHelper.getEmptyKeys(propertiesOut); + if (!emptyEntries.isEmpty()) { + StringBuilder buffer = new StringBuilder(); + int size = emptyEntries.size(); + buffer.append("bundle " + locale + " contains " + size + "/" + propertiesOut.size() + " empty entries!"); + if (showEmpty) { + int index = 0; + for (String key : emptyEntries) { + buffer.append("\n - " + (index++) + "/" + size + " : " + key); + } + } else { + buffer.append(" (use -Di18n.showEmpty to see these entries)"); + } + getLog().warn(buffer.toString()); + } else { + if (!silent && verbose) { + getLog().info("bundle " + locale + " is valid (no empty entries)."); + } + } + } + + protected void backupFile(File f) throws IOException { + PluginHelper.copy(f, new File(f.getAbsolutePath() + "~")); + } + + protected void copyFile(File src, File dst) throws IOException { + PluginHelper.copy(src, dst); + } +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/Bundle.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/Bundle.java new file mode 100644 index 0000000..18e32ef --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/Bundle.java @@ -0,0 +1,361 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package org.nuiton.i18n.plugin; + +import java.net.MalformedURLException; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.metadata.ArtifactMetadataSource; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.resolver.ArtifactCollector; +import org.apache.maven.artifact.resolver.filter.ArtifactFilter; +import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.MavenProjectBuilder; +import org.apache.maven.shared.dependency.tree.DependencyNode; +import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder; +import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException; +import org.nuiton.i18n.bundle.I18nBundleEntry; +import org.nuiton.util.PluginHelper.SortedProperties; +import org.nuiton.i18n.bundle.I18nBundleFactory; +import org.nuiton.util.DependencyUtil; +import org.nuiton.util.PluginHelper; + +/** + * Créer un bundle pour une application finale. + * + * Cela génère un merge de tous les fichiers i18n utilisés en un seul. + * + * On utilise la dépendance sur les artifacts pour connaitre l'ordre le chargement + * des bundles. + * + * Si dans un bundle childs, la valeur de la clef est vide, on conserve alors celui + * du parent, + * + * Ainsi on obtient un bundle dont toutes les clefs sont traduites. + * + * Le but aussi d'utiliser un unique bundle est de gagner du temps au runtime + * car la recherche des bundles devient trop couteuse en temps lorsque l'on a de + * nombreuses dépendances (au dessus de 100 deps cela peut prendre plusieurs + * secondes, ce qui 'est pas acceptable). + * + * On a ajoute un second mode d'initialisation dans la clesse I18n pour n'utiliser + * qu'un seul bundle et courcircuiter le chargement couteux... + * * + * + * @author chemit + * @goal bundle + * @phase generate-resources + * @execute goal=gen + * @requiresProject true + * @requiresDependencyResolution runtime + * + * @since 0.12 + */ +public class Bundle extends AbstractI18nPlugin { + + /** + * Repertoire ou generer les bundles. + * + * @parameter expression="${i18n.bundleOutputDir}" default-value="${basedir}/target/generated-sources/resources/META-INF" + * @required + * @since 1.0.0 + */ + protected File bundleOutputDir; + /** + * Nom du bundle a generer. + * + * @parameter expression="${i18n.bundleOutputName}" default-value="${project.artifactId}-i18n" + * @required + * @since 1.0.0 + */ + protected String bundleOutputName; + /** + * Un drapeau pour vérifier que les bundles ne contiennent pas d'entrées vides. + * + * @parameter expression="${i18n.checkBundle}" default-value="true" + * @required + * @since 1.0.0 + */ + protected boolean checkBundle; + /** + * Un drapeau pour afficher les entrées vides. (nécessite {@link #checkBundle} activé). + * + * @parameter expression="${i18n.showEmpty}" default-value="false" + * @required + * @since 1.0.0 + */ + protected boolean showEmpty; + /** + * Dependance du projet. + * + * @parameter default-value="${project}" + * @required + * @since 1.0.0 + */ + protected MavenProject project; + /** + * Local Repository. + * + * @parameter expression="${localRepository}" + * @required + * @readonly + * @since 1.0.0 + */ + protected ArtifactRepository localRepository; + /** + * Remote repositories used for the project. + * + * @parameter expression="${project.remoteArtifactRepositories}" + * @required + * @readonly + * @since 1.0.0 + */ + protected List<?> remoteRepositories; + /** + * Dependency tree builder component. + * + * @component + */ + protected DependencyTreeBuilder dependencyTreeBuilder; + /** + * Artifact Factory component. + * + * @component + */ + protected ArtifactFactory factory; + /** + * Artifact metadata source component. + * + * @component + */ + protected ArtifactMetadataSource artifactMetadataSource; + /** + * Artifact collector component. + * + * @component + */ + protected ArtifactCollector collector; + /** + * Maven Project Builder component. + * + * @component + */ + protected MavenProjectBuilder mavenProjectBuilder; + protected I18nArtifact[] i18nArtifacts; + protected ClassLoader loader; + protected URL[] urls; + + @Override + public void init() { + super.init(); + + if (locales == null || locales.length == 0) { + throw new IllegalStateException("il faut au moins une locale declaree (utiliser la propriete 'bundles')"); + } + + if (!bundleOutputDir.exists()) { + bundleOutputDir.mkdirs(); + } + + try { + // calcul des artifacts qui ont un bundle i18n et trie selon les + // dependances + + i18nArtifacts = detectI18nArtifacts(); + + if (!silent) { + getLog().info("detected " + i18nArtifacts.length + " i18n artifact(s) : "); + for (I18nArtifact a : i18nArtifacts) { + getLog().info(" - " + a); + } + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + + // ajout de repertoire de generation (le parent en fait) + // dans les resources du projet + + String newresourceDir = bundleOutputDir.getParentFile().getAbsolutePath(); + + PluginHelper.addResourceDir(newresourceDir, project); + } + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + if ("pom".equals(project.getPackaging()) || "site".equals(project.getPackaging())) { + return; + } + + + long t00 = System.nanoTime(); + + init(); + + if (!silent) { + getLog().info("config - bundle name : " + bundleOutputName); + getLog().info("config - baseidr : " + bundleOutputDir); + getLog().info("config - locales : " + Arrays.toString(locales)); + } + // la locale par defaut est la première + Locale defaultLocale = locales[0]; + + Map<Locale, String> bundleDico = new LinkedHashMap<Locale, String>(locales.length); + + try { + + for (Locale locale : locales) { + + long t0 = System.nanoTime(); + + File bundleOut = getI18nFile(bundleOutputDir, bundleOutputName, locale, false); + + if (!silent) { + getLog().info("generate bundle for locale " + locale); + } + + SortedProperties propertiesOut = new SortedProperties(encoding, false); + StringBuilder buffer = new StringBuilder(); + for (I18nArtifact artifact : i18nArtifacts) { + I18nBundleEntry[] bundleEntries = artifact.getBundleEntries(locale, defaultLocale); + for (I18nBundleEntry bundleEntry : bundleEntries) { + + bundleEntry.load(propertiesOut); + String strPath = bundleEntry.getPath().toString(); + int index = strPath.indexOf("i18n/"); + + buffer.append(',').append(strPath.substring(index)); + if (verbose) { + getLog().info("loaded " + bundleEntry.getPath() + " in " + PluginHelper.convertTime(t0, System.nanoTime())); + } + } + } + if (buffer.length() > 0) { + bundleDico.put(locale, buffer.substring(1)); + if (!silent) { + getLog().info("bundles for locale : " + bundleDico.get(locale)); + } + } + propertiesOut.store(bundleOut); + if (!silent && verbose) { + getLog().info("bundle created in " + PluginHelper.convertTime(t0, System.nanoTime()) + " (detected sentences : " + propertiesOut.size() + ")"); + } + if (checkBundle) { + checkBundle(locale, propertiesOut, showEmpty); + } + } + + // ecriture du ficher des definitions i18n (permet de faire une + // recherche extact sur un fichier puis d'en deduire les bundles a + // charger + String f = String.format(I18nBundleFactory.UNIQUE_BUNDLE_DEF, bundleOutputName); + File defOut = new File(bundleOutputDir, f); + if (!silent) { + getLog().info("prepare i18n definition " + defOut.getAbsolutePath()); + } + SortedProperties p = new SortedProperties(encoding, false); + p.setProperty(I18nBundleFactory.BUNDLE_DEF_LOCALES, bundles); + for (Entry<Locale, String> e : bundleDico.entrySet()) { + p.setProperty(I18nBundleFactory.BUNDLES_FOR_LOCALE + e.getKey().toString(), e.getValue()); + } + p.store(new FileOutputStream(defOut), null); + + if (!silent && verbose) { + getLog().info("done in " + PluginHelper.convertTime(t00, System.nanoTime())); + } + } catch (IOException e) { + getLog().error("File Error I/O ", e); + throw new MojoFailureException("File Error I/O "); + } + } + + /** + * Detecte les {@link I18nArtifact} et les retourne dans l'ordre de chargement + * dans le système i18n, i.e l'ordre des dependances entre artifacts. + * + * @return les artifacts i18nables triés par leur ordre de chargement dans le système i18n. + * + * @throws MalformedURLException + * @throws IOException + * @throws DependencyTreeBuilderException + */ + protected I18nArtifact[] detectI18nArtifacts() throws MalformedURLException, IOException, DependencyTreeBuilderException { + + Map<Artifact, I18nArtifact> dico = new java.util.HashMap<Artifact, I18nArtifact>(); + + I18nArtifact i18nArtifact; + for (Object o : project.getArtifacts()) { + i18nArtifact = new I18nArtifact((Artifact) o); + if (i18nArtifact.detectBundles()) { + if (!silent && getLog().isDebugEnabled()) { + getLog().debug("detected artifact " + i18nArtifact); + } + dico.put(i18nArtifact.getArtifact(), i18nArtifact); + } else { + if (!silent && getLog().isDebugEnabled()) { + getLog().debug("reject artifact " + i18nArtifact); + } + } + } + + ArtifactFilter artifactFilter = new ScopeArtifactFilter(Artifact.SCOPE_RUNTIME); + + DependencyNode rootNode = dependencyTreeBuilder.buildDependencyTree(project, localRepository, factory, + artifactMetadataSource, artifactFilter, collector); + + List<Artifact> artifacts = new java.util.ArrayList<Artifact>(dico.keySet()); + + DependencyUtil.sortArtifacts(rootNode, artifacts, getLog().isDebugEnabled()); + + // l'artifact du projet est traite en dernier car s'il possède des + // bundles alors ils doivent etre charge en dernier + + Artifact projectArtifact = project.getArtifact(); + i18nArtifact = new I18nArtifact(projectArtifact, src.getParentFile()); + + if (i18nArtifact.detectBundles()) { + if (!silent && verbose) { + getLog().info("detected artifact " + i18nArtifact); + } + artifacts.add(i18nArtifact.getArtifact()); + dico.put(i18nArtifact.getArtifact(), i18nArtifact); + } + + I18nArtifact[] result = new I18nArtifact[artifacts.size()]; + int i = 0; + for (Artifact artifact : artifacts) { + result[i++] = dico.get(artifact); + } + return result; + } +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/Generate.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/Generate.java new file mode 100644 index 0000000..851af7f --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/Generate.java @@ -0,0 +1,144 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package org.nuiton.i18n.plugin; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.nuiton.util.PluginHelper.SortedProperties; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.Locale; + +/** + * Merge des fichiers de propriétés avec les anciens. + * + * @author julien + * @goal gen + * @phase generate-resources + * @execute goal=get + */ +public class Generate extends AbstractI18nPlugin { + + /** + * Un drapeau pour vérifier que les bundles ne contiennent pas d'entrées vides. + * + * @parameter expression="${i18n.checkBundle}" default-value="true" + * @required + * @since 1.0.0 + */ + protected boolean checkBundle; + /** + * Un drapeau pour afficher les entrées vides. (nécessite {@link #checkBundle} activé). + * + * @parameter expression="${i18n.showEmpty}" default-value="false" + * @required + * @since 1.0.0 + */ + protected boolean showEmpty; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + init(); + + if (!needGeneration()) { + getLog().info("Nothing to generate - all files are up to date."); + return; + } + + if (!silent) { + getLog().info("config - src basedir : " + src.getAbsolutePath()); + getLog().info("config - out basedir : " + out.getAbsolutePath()); + getLog().info("config - locales : " + Arrays.toString(locales)); + } + for (Locale locale : locales) { + if (!silent) { + getLog().info("prepare bundle for locale " + locale); + } + try { + // Merge + File bundleSrc = getI18nFile(src, artifactId, locale, false); + File bundleOut = getI18nFile(out, artifactId, locale, false); + + SortedProperties propertiesSrc = new SortedProperties(encoding); + + if (bundleSrc.exists()) { + propertiesSrc.load(bundleSrc); + } + + SortedProperties propertiesOut = new SortedProperties(encoding); + + if (!strictMode) { + // si on n'est pas en mode strict, on doit push back in bundle out, all the bundle src keys + propertiesOut.putAll(propertiesSrc); + } + propertiesOut.load(bundleOut); + + // Parcours des clés + for (Object key : propertiesOut.keySet()) { + Object oldKey = propertiesOut.get(key); + Object value = propertiesSrc.get(oldKey); + + // Récupération de la clé si elle a été renommée + if (!key.equals(oldKey) && value == null) { + value = propertiesSrc.get(key); + } + + if (value != null) { + propertiesOut.put(key, value); + } else { + propertiesOut.put(key, ""); + } + } + + //fixme : on devrait laisser le fichier en utf8 ? + //propertiesOut.store(bundleOut); + propertiesOut.store(new FileOutputStream(bundleOut)); + + // Sauvegarde avant copie + if (genSrc && keepBackup) { + backupFile(bundleSrc); + } + if (!silent) { + getLog().info("merge bundle " + locale + " to out"); + } + + if (checkBundle) { + checkBundle(locale, propertiesOut, showEmpty); + } + + if (genSrc) { + // Copie des fichiers dans les sources + copyFile(bundleOut, bundleSrc); + //if (verbose) { + if (!silent) { + getLog().info("copy bundle " + locale + " to src"); + } + //} + } + + } catch (IOException e) { + getLog().error("File Error I/O ", e); + throw new MojoFailureException("File Error I/O "); + } + } + } +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/Getter.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/Getter.java new file mode 100644 index 0000000..3bbaade --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/Getter.java @@ -0,0 +1,115 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package org.nuiton.i18n.plugin; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.codehaus.plexus.util.DirectoryScanner; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Locale; +import org.nuiton.util.PluginHelper; +import org.nuiton.util.PluginHelper.SortedProperties; + +/** + * Recupere les différents fichiers des parsers en un fichier de proprietes. + * + * @author julien + * @goal get + * @phase generate-resources + */ +public class Getter extends AbstractI18nPlugin { + + /* + * (non-Javadoc) + * @see org.apache.maven.plugin.AbstractMojo#execute() + */ + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + init(); + + if (!needGeneration()) { + if (verbose) { + getLog().info("Nothing to generate - all files are up to date."); + } + return; + } + if (!silent) { + getLog().info("config - basedir : " + out.getAbsolutePath()); + getLog().info("config - locales : " + Arrays.toString(locales)); + } + + try { + File bundleGetters = new File(out.getAbsolutePath() + File.separatorChar + artifactId + ".properties"); + bundleGetters.createNewFile(); + + DirectoryScanner ds = new DirectoryScanner(); + ds.setBasedir(out); + ds.setIncludes(new String[]{"*.getter"}); + ds.scan(); + String[] files = ds.getIncludedFiles(); + + // Fusion des fichiers propriétés des différents parsers + for (String file : files) { + long t0 = System.nanoTime(); + File bundleGetter = getGetterFile(out, file, false); + concactProperties(bundleGetter, bundleGetters); + if (genSrc) { + bundleGetter.delete(); + } + if (!silent) { + getLog().info("import getter " + bundleGetter.getName() + " in " + PluginHelper.convertTime(System.nanoTime() - t0)); + } + } + + // Création des bundles + for (Locale locale : locales) { + if (!silent && getLog().isDebugEnabled()) { + getLog().debug("generate bundle for locale " + locale); + } + File bundleOut = getI18nFile(out, artifactId, locale, false); + copyFile(bundleGetters, bundleOut); + if (!silent && verbose) { + getLog().info("generate bundle " + locale); + } + } + + bundleGetters.delete(); + } catch (IOException e) { + getLog().error("File Error I/O ", e); + throw new MojoFailureException("File Error I/O"); + } + } + + /** + * Concatene deux fichiers de proprietes + * + * @param in le fichier entrant + * @param out le fichier sortant + * @throws IOException si problème pendant la sauvegarde ou fichier non trouvé. + */ + protected void concactProperties(File in, File out) throws IOException { + SortedProperties propertiesIn = new SortedProperties(encoding).load(in); + SortedProperties propertiesOut = new SortedProperties(encoding).load(out); + propertiesOut.putAll(propertiesIn); + propertiesOut.store(out); + } +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/I18nArtifact.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/I18nArtifact.java new file mode 100644 index 0000000..d002f06 --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/I18nArtifact.java @@ -0,0 +1,100 @@ +/** + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.plugin; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.Locale; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.maven.artifact.Artifact; +import org.nuiton.i18n.bundle.I18nBundle; +import org.nuiton.i18n.bundle.I18nBundleEntry; +import org.nuiton.i18n.bundle.I18nBundleFactory; + +/** + * + * @author chemit + * @since 0.12 + */ +public class I18nArtifact { + + static final Log log = LogFactory.getLog(I18nArtifact.class); + protected final Artifact artifact; + protected final URL url; + protected I18nBundle[] bundles; + + public I18nArtifact(Artifact artifact) throws MalformedURLException { + this.artifact = artifact; + this.url = artifact.getFile().toURI().toURL(); + } + + public I18nArtifact(Artifact artifact, File file) throws MalformedURLException { + this.artifact = artifact; + this.url = file.toURI().toURL(); + } + + public Artifact getArtifact() { + return artifact; + } + + public URL getUrl() { + return url; + } + + public I18nBundleEntry[] getBundleEntries(Locale l, Locale defaultLocale) { + if (bundles == null) { + throw new NullPointerException("le bundleManager n'a pas ete initialise!"); + } + return I18nBundleFactory.getBundleEntries(l, defaultLocale, bundles); + } + + public boolean detectBundles() throws IOException { + + URL[] i18nUrls = I18nBundleFactory.getURLs(url); + + if (i18nUrls == null || i18nUrls.length == 0) { + // aucune url sur un fichier de traduction trouve + // l'artifact n'est pas i18n. + if (log.isDebugEnabled()) { + log.debug("no i18n url for artifact " + artifact); + } + return false; + } + + List<I18nBundle> listBundles = I18nBundleFactory.detectBundles(i18nUrls); + + if (listBundles.isEmpty()) { + // pas de bundle instancie (cela ne devrait jamais arrive...) + return false; + } + + this.bundles = listBundles.toArray(new I18nBundle[listBundles.size()]); + + return true; + } + + @Override + public String toString() { + return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion(); + } +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/I18nLogger.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/I18nLogger.java new file mode 100644 index 0000000..b1aceb0 --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/I18nLogger.java @@ -0,0 +1,117 @@ +/** + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.plugin; + +import org.nuiton.util.SourceEntry; +import org.apache.maven.plugin.logging.SystemStreamLog; + +import java.beans.Introspector; +import java.io.File; +import org.nuiton.util.PluginHelper; +/** + * Le logger utilisé par les mojo. + * + * @author chemit + * @since 0.9 + */ +public class I18nLogger extends SystemStreamLog { + + /** l'entrée en cours de traitement (pour les parseurs) */ + private SourceEntry entry; + + /** le fichier en cours de traitement (pour les parseurs) */ + protected File file; + + /** le prefix du mojo courant a ajouter dans les logs. */ + protected String parser; + + public I18nLogger(AbstractI18nPlugin parser) { + this.parser = "i18n:" + Introspector.decapitalize(parser.getClass().getSimpleName()) + " on " + parser.getArtifactId(); + } + + @Override + public void info(CharSequence content) { + print(0, "INFO", null, content.toString()); + } + + @Override + public void debug(CharSequence content) { + print(0, "DEBUG", null, content.toString()); + } + + public void infoEntry(String action, CharSequence content) { + print(0, "INFO", action, entry.toString() + (content == null ? "" : " - " + content.toString())); + } + + public void infoFile(String action, String content) { + print(2, "INFO", action, file.toString() + (content == null ? "" : " - " + content)); + } + + public void infoAction(String action, String content) { + print(2, "INFO", action, (content == null ? "" : " - " + content)); + } + + private void print(int start, String prefix, String context, String content) { + StringBuilder sb = new StringBuilder(); + sb.append("[").append(prefix).append("] [").append(parser).append("] "); + + for (int i = 0; i < start; i++) { + sb.append(' '); + } + if (context != null) { + sb.append("<").append(context).append("> "); + } + sb.append(content); + System.out.println(sb.toString()); + } + + public void setEntry(SourceEntry entry) { + this.entry = entry; + } + + /** + * Construit une chaine de log formatée. + * + * @param msg le prefix du message + * @param nbFiles le nombre de fichiers actuellement traités + * @param time le time de traitement de ce fichier + * @param all le temps de traitement de tous les fichiers + * @return la chaine de log formatée + */ + public String getLogEntry(String msg, int nbFiles, long time, long all) { + long now = System.nanoTime(); + long delta = now - time; + String s = msg; + if (time > 0) { + s += " (" + PluginHelper.convertTime(delta) + ")"; + } + if (all > 0) { + s += "(total time:" + PluginHelper.convertTime(now - all) + ")"; + } + if (nbFiles > 0) { + s += " ( ~ " + PluginHelper.convertTime(((now - all) / (nbFiles))) + " / file)"; + } + return s; + } + + public void setFile(File file) { + this.file = file; + } + +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParser.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParser.java new file mode 100644 index 0000000..d484ad7 --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParser.java @@ -0,0 +1,369 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package org.nuiton.i18n.plugin.parser; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.nuiton.i18n.plugin.AbstractI18nPlugin; +import org.nuiton.i18n.plugin.I18nLogger; +import org.nuiton.util.PluginHelper.SortedProperties; +import org.nuiton.i18n.plugin.parser.event.KeysModifier; +import org.nuiton.util.FileUpdater; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.nuiton.util.SourceEntry; + +/** + * Abstract implementation for parsing goal. + * + * @author tony + */ +public abstract class AbstractI18nParser extends AbstractI18nPlugin implements Parser { + + /** @return the outGetter to use for the instance (java.getter,...) */ + protected abstract String getOutGetter(); + + /** @return the starting regex expression to catch keys in key modifier */ + protected abstract String getKeyModifierStart(); + + /** @return the ending regex expression to catch keys in key modifier */ + protected abstract String getKeyModifierEnd(); + + /** @return the default includes to add to directory scanner */ + protected abstract String[] getDefaultIncludes(); + + /** @return the default excludes to add to directory scanner */ + protected abstract String[] getDefaultExcludes(); + + /** @return the default src directory to use in directory scanner */ + protected abstract File getDefaultBasedir(); + + public abstract FileUpdater newFileUpdater(SourceEntry entry); + /** + * treate default entry + * + * @parameter expression="${i18n.treateDefaultEntry}" default-value="true" + */ + protected boolean treateDefaultEntry; + /** + * Source entries (src+includes+excludes) . + * + * @parameter expression="${i18n.entries}" + */ + protected MySourceEntry[] entries; + /** + * flag to display touched files while parsing. + * <p/> + * Note: the value will be always <code>true</code> if {@link #verbose} is set + * at <code>true</code>. + * + * @parameter expression="${i18n.showTouchedFiles}" default-value="${maven.verbose}" + * @since 0.9 + */ + protected boolean showTouchedFiles; + /** + * flag to save at eachfile treated the getter file + * + * @parameter expression="${i18n.safeMode}" default-value="false" + * @since 0.9 + */ + protected boolean safeMode; + protected SortedProperties result; + protected SortedProperties oldParser; + protected SortedProperties oldLanguage; + protected int fileTreated = 0; + protected long t0; + protected boolean touchFile; + protected List<File> treadedFiles; + + @Override + public void init() { + super.init(); + t0 = System.nanoTime(); + result = new SortedProperties(encoding); + oldParser = new SortedProperties(encoding); + oldLanguage = new SortedProperties(encoding); + out.mkdirs(); + // evenements + if (keysModifier) { + addParserEvent(KeysModifier.getInstance(getKeyModifierStart(), getKeyModifierEnd(), encoding)); + } + treadedFiles = new ArrayList<File>(); + if (!silent && verbose) { + showTouchedFiles = true; + } + } + + + /* + * (non-Javadoc) + * @see org.apache.maven.plugin.AbstractMojo#execute() + */ + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + init(); + if (entries == null || entries.length == 0 && !treateDefaultEntry) { + // nothing to do + return; + } + + if (!silent && safeMode) { + getLog().info("config - safeMode is on (could be slower)."); + } + if (!silent && strictMode) { + getLog().info("config - strictMode is on (all files will be parsed)."); + } + + try { + // Reprise sur un ancien parsing + File oldParserFile = getGetterFile(out, getOutGetter(), true); + File saveFile = getGetterFileBackup(out, getOutGetter()); + + oldParser.load(oldParserFile); + copyFile(oldParserFile, saveFile); +// FileUtil.copy(oldParserFile, saveFile); + + // Anciennes cles disponnibles + //fixme : pourquoi on utilise un bundle precis ? le premier ici, je ne comprends pas + File oldLanguageFile = getI18nFile(src, artifactId, locales[0], true); + + oldLanguage.load(oldLanguageFile); + + // Parsing + parse(); + + // Suppression du fichier sauvegarder + saveFile.delete(); + + int i = treadedFiles.size(); + if (fileTreated == 0) { + if (!silent) { + getLog().info("Nothing to generate - all files are up to date."); + } + } else { + if (!silent) { + getLog().info(getVerboseLog().getLogEntry("parsing is done. [treated file(s) : " + i + '/' + fileTreated + "]", fileTreated, 0, t0)); + } + addGetter(); + } + + } catch (Exception e) { + getLog().error("Error code parsing ", e); + throw new MojoFailureException("Error code parsing"); + } + + } + + /** + * launch the parse on every given entries. + * + * @throws IOException if any io pb + */ + @Override + public void parse() throws IOException { + if (treateDefaultEntry) { + addDefaultEntry(); + } + long t00 = System.nanoTime(); + for (MySourceEntry entry : this.entries) { + I18nLogger vLog = getVerboseLog(); + + vLog.setEntry(entry); + + boolean skip = entry.init(this); + + if (skip) { + if (!silent && verbose) { + getLog().info("skip - " + entry.getSkipMessage()); + } + continue; + } + + long t000 = System.nanoTime(); + int nbFiles = entry.getFiles().length; + if (!silent && verbose) { + vLog.infoEntry("start", vLog.getLogEntry("[incoming file(s) : " + entry.getFoudFiles() + "]", 0, 0, 0)); + } + + // launch parser for found files + parseEntry(entry); + + if (!silent && verbose) { + // log skipped files + for (String skipFile : entry.getSkipFiles()) { + vLog.setFile(new File(entry.getBasedir(), skipFile)); + vLog.infoFile("skip", null); + } + } + fileTreated += nbFiles; + if (!silent && verbose) { + vLog.infoEntry("end", vLog.getLogEntry("[treated file(s) : " + nbFiles + "]", nbFiles, t000, t00)); + } + t00 = System.nanoTime(); + } + } + + /** + * Add the default entry to entries given in configuration. + * <p/> + * This is a convinient method to simplify the configuration of the plugin. + */ + protected void addDefaultEntry() { + List<MySourceEntry> list; + + if (entries == null || entries.length == 0) { + list = new ArrayList<MySourceEntry>(); + } else { + list = new ArrayList<MySourceEntry>(Arrays.asList(entries)); + } + list.add(new MySourceEntry()); + entries = list.toArray(new MySourceEntry[list.size()]); + } + + /** + * launch parsing on a given entry. + * + * @param entry currentEntry to treate + * @throws IOException if any io pb. + */ + protected final void parseEntry(SourceEntry entry) throws IOException { + long t00 = System.nanoTime(); + String[] files = entry.getFiles(); + int beforeEntryResultSize = result.size(); + for (int i = 0, max = files.length; i < max; i++) { + String file1 = files[i]; + long t000 = System.nanoTime(); + String fileName = entry.getBasedir().getAbsolutePath() + File.separator + file1; + File file = new File(fileName); + for (ParserEvent event : events) { + event.eventChangeFile(file); + } + I18nLogger vLog = getVerboseLog(); + vLog.setFile(file); + + touchFile = false; + int size = result.size(); + if (!silent && verbose) { + vLog.infoFile("parse", null); + } + parseFile(file); + + //TC-20090214 pour des questions de performance, on ne sauvegarde pas + // a chaque traitement de fichier, les clefs mais une fois pour chaque + // source entry + // Detection de nouvelles cles, sauvegarde du fichier pour pouvoir le restaurer en cas de plantage + if (safeMode) { + if (size != result.size()) { + saveGetterFile(); + } + } + if (touchFile) { + if (showTouchedFiles) { + vLog.infoFile("touch", null); + } + treadedFiles.add(file); + if (getLog().isDebugEnabled()) { + vLog.debug(vLog.getLogEntry(fileName, i, t000, t00)); + } + } + for (ParserEvent event : events) { + event.eventNextFile(file); + } + } + + if (!safeMode && beforeEntryResultSize < result.size()) { + // Detection de nouvelles cles, sauvegarde du fichier + saveGetterFile(); + } + } + + /** + * Save the result in the getter file. + * + * @throws IOException if any io pb + */ + protected void saveGetterFile() throws IOException { + File getterFile = getGetterFile(out, getOutGetter(), false); + result.store(getterFile); + } + + public static class MySourceEntry extends SourceEntry { + + public boolean init(AbstractI18nParser mojo) { + if (!useForGoal(mojo.getClass().getSimpleName())) { + // skip not for this goal + skipMessage = "exclude for this goal."; + return true; + } + + String[] filesForEntry = getFilesForEntry(mojo); + + if (filesForEntry.length == 0) { + // skip no file found + skipMessage = "no file found."; + return true; + } + setUpdater(mojo.newFileUpdater(this)); + + if (mojo.strictMode || updater == null) { + // mojo strict mode or not updater, so force all files + skipFiles = new String[0]; + this.files = filesForEntry; + return false; + } + + List<String> listFiles = new ArrayList<String>(); + List<String> listSkipFiles = new ArrayList<String>(); + + // test if have any file + for (String foundFile : filesForEntry) { + File file = new File(getBasedir(), foundFile); + if (isFileUptodate(file)) { + listSkipFiles.add(foundFile); + } else { + listFiles.add(foundFile); + } + } + boolean todo = !listFiles.isEmpty(); + if (!todo) { + // skip, no file out-of -date + skipMessage = "all files are up to date."; + this.skipFiles = listSkipFiles.toArray(new String[listSkipFiles.size()]); + this.files = new String[0]; + return true; + } + this.skipFiles = listSkipFiles.toArray(new String[listSkipFiles.size()]); + this.files = listFiles.toArray(new String[listFiles.size()]); + return false; + } + + /** + * Obtain all the relative path of files to treate for a given entry. + * + * @param mojo the given mojo + * @return the list of relative path of files for the given entry + */ + protected String[] getFilesForEntry(AbstractI18nParser mojo) { + return getIncludedFiles(mojo.getDefaultBasedir(), mojo.getDefaultIncludes(), mojo.getDefaultExcludes()); + } + } +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/Parser.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/Parser.java new file mode 100644 index 0000000..5ba3c6b --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/Parser.java @@ -0,0 +1,55 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ + +package org.nuiton.i18n.plugin.parser; + +import java.io.File; +import java.io.IOException; + +/** + * Interface type pour la définition d'un nouveau parser. + * <p/> + * Une implantation abstraite est proposée : {@link AbstractI18nParser}. + * + * @author julien + */ +public interface Parser { + + /** + * Lancement du parser + * + * @throws java.io.IOException if any io pb + */ + public void parse() throws IOException; + + /** + * Parse sur un fichier + * + * @param file le fichier à parser + */ + public void parseFile(File file); + + /** + * Parse une partie du fichier + * + * @param file le fichier à parser + * @param args ? TODO + */ + public void parseLine(File file, String args); + +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/ParserEvent.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/ParserEvent.java new file mode 100644 index 0000000..041a3f9 --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/ParserEvent.java @@ -0,0 +1,59 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ + +package org.nuiton.i18n.plugin.parser; + +import java.io.File; + +/** + * Permet d'ajouter des évènements sur les parsers + * + * @author julien + */ +public interface ParserEvent { + + /** + * M�thode appelée quand on change de fichier parsé + * + * @param file + */ + public void eventChangeFile(File file); + + /** + * Méthode appelée après le parsing du fichier + * + * @param file + */ + public void eventNextFile(File file); + + /** + * M�thode appelée quand on change de clé + * + * @param keyI18n + * @param newKey + */ + public void eventChangeKey(String keyI18n, boolean newKey); + + /** + * M�thode appelée pour récupérer la nouvelle valeur de clé + * + * @return + */ + public String eventGetRealKey(); + +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/ParserException.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/ParserException.java new file mode 100644 index 0000000..6abd0cd --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/ParserException.java @@ -0,0 +1,45 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ + +package org.nuiton.i18n.plugin.parser; + +/** + * Permet la gestion des exceptions dans les parsers et dans les évènements + * + * @author julien + */ +public class ParserException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public ParserException() { + super(); + } + + public ParserException(String message, Throwable cause) { + super(message, cause); + } + + public ParserException(String message) { + super(message); + } + + public ParserException(Throwable cause) { + super(cause); + } +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/event/KeysModifier.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/event/KeysModifier.java new file mode 100644 index 0000000..775c033 --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/event/KeysModifier.java @@ -0,0 +1,219 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ + +package org.nuiton.i18n.plugin.parser.event; + +import org.nuiton.i18n.plugin.parser.ParserEvent; +import org.nuiton.i18n.plugin.parser.ParserException; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JTextField; +import java.awt.Container; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.nuiton.util.PluginHelper; + +/** + * IHM permettant de modifier les clés de traduction en direct dans les fichiers + * parsés et les fichiers de propriétés. + * + * @author julien + */ +public class KeysModifier extends JFrame implements ParserEvent { + + private static final long serialVersionUID = 1L; + + // Modification des clés dans le fichier + protected List<String> newKeys; + protected boolean needModifiedFile; + protected String patternLeft; + protected String patternRight; + protected String encoding; + + // Interface + protected JLabel name = new JLabel(); + protected JLabel path = new JLabel(); + protected JTextField key = new JTextField(); + protected JTextField pattern = new JTextField(".*"); + protected JCheckBox onlyNewKey = new JCheckBox(); + + + protected JButton next = new JButton("Next >>"); + private static KeysModifier keysModifier; + + /** + * Récupération d'une instance de l'interface + * + * @param patternLeft left pattern + * @param patternRight right pattern + * @param encoding encoding + * @return the shared instance with new config + */ + public static KeysModifier getInstance(String patternLeft, String patternRight, String encoding) { + if (keysModifier == null) { + keysModifier = new KeysModifier(); + } + + + keysModifier.encoding = encoding; + keysModifier.patternLeft = patternLeft; + keysModifier.patternRight = patternRight; + + return keysModifier; + } + + /** Contructeur de l'interface */ + private KeysModifier() { + setLayout(new GridLayout(9, 2, 10, 10)); + + Container pane = getContentPane(); + pane.add(new JLabel("--- File information ---")); + pane.add(new JLabel()); + + pane.add(new JLabel("Name :")); + pane.add(name); + + pane.add(new JLabel("Path : ")); + pane.add(path); + + pane.add(new JLabel("--- Files language ---")); + pane.add(new JLabel()); + + pane.add(new JLabel("Key :")); + pane.add(key); + + pane.add(new JLabel("--- Filters ---")); + pane.add(new JLabel()); + + pane.add(new JLabel("Pattern :")); + pane.add(pattern); + + pane.add(new JLabel("Only new key :")); + pane.add(onlyNewKey); + + pane.add(new JLabel()); + pane.add(next); + + next.addActionListener(new EventNextKey()); + addWindowListener(new EventWindows()); + + setTitle("Keys modifier"); + setSize(800, 400); +// pack(); + setVisible(true); + } + + @Override + public void eventChangeFile(File file) { + name.setText(file.getName()); + path.setText(file.getPath()); + key.setText(""); + repaint(); + + newKeys = new ArrayList<String>(); + needModifiedFile = false; + } + + @Override + public void eventNextFile(File file) { + if (needModifiedFile) { + String content; + int region = 0; + + try { + content = PluginHelper.readAsString(file, encoding); + } catch (IOException e) { + throw new ParserException(e); + } + + for (Iterator<String> iterator = newKeys.iterator(); iterator.hasNext();) { + String oldKey = iterator.next(); + String realKey = iterator.next(); + Pattern p = Pattern.compile("(" + patternLeft + ")(" + Pattern.quote(oldKey) + ")(" + patternRight + ")"); + Matcher matcher = p.matcher(content); + matcher.region(region, content.length()); + matcher.find(); + region = matcher.start(); + content = matcher.replaceFirst("$1" + realKey + "$3"); + } + + try { + PluginHelper.writeString(file, content, encoding); + } catch (IOException e) { + throw new ParserException(e); + } + } + } + + @Override + public synchronized void eventChangeKey(String keyI18n, boolean newKey) { + key.setText(keyI18n); + newKeys.add(key.getText()); + repaint(); + if (isVisible() && keyI18n.matches(pattern.getText()) && (!onlyNewKey.isSelected() || newKey)) { + try { + wait(); + } catch (InterruptedException e) { + throw new ParserException(e); + } + } + } + + @Override + public String eventGetRealKey() { + newKeys.add(key.getText()); + needModifiedFile |= !newKeys.get(newKeys.size() - 1).equals(newKeys.get(newKeys.size() - 2)); + return key.getText(); + } + + /** Action sur le boutton pour passer � la cl� suivante */ + class EventNextKey implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + eventNextKey(); + } + } + + /** Action sur la fermeture de la frame */ + class EventWindows extends WindowAdapter { + + @Override + public void windowClosing(WindowEvent e) { + setVisible(false); + eventNextKey(); + } + } + + /** Permet de passer à la clé suivante */ + public synchronized void eventNextKey() { + notifyAll(); + } +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJava.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJava.java new file mode 100755 index 0000000..f4bba34 --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJava.java @@ -0,0 +1,164 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ + +package org.nuiton.i18n.plugin.parser.impl; + +import org.apache.maven.project.MavenProject; +import org.nuiton.util.SourceEntry; +import org.nuiton.i18n.plugin.parser.AbstractI18nParser; +import org.nuiton.i18n.plugin.parser.ParserEvent; +import org.nuiton.i18n.plugin.parser.ParserException; +import org.nuiton.util.FileUpdater; +import org.nuiton.util.FileUpdaterHelper; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.LineNumberReader; +import org.nuiton.processor.filters.I18nFilter; + +/** + * Récupération des chaine a traduire depuis les fichiers java. + * + * @author julien + * @goal parserJava + * @phase generate-resources + */ +public class ParserJava extends AbstractI18nParser { + + /** + * Source entries (src+includes+excludes) . + * + * @parameter expression="${i18n.defaultIncludes}" default-value="**\\/*.java" + */ + protected String defaultIncludes; + + /** + * default src for an entry. + * + * @parameter expression="${i18n.defaultBasedir}" default-value="${basedir}/src/main/java" + */ + protected File defaultBasedir; + + /** + * Dependance du projet. + * + * @parameter default-value="${project}" + * @readonly + */ + protected MavenProject project; + + /** + * Repertoire sources des fichiers i18n. + * + * @parameter expression="${i18n.cp}" default-value="${basedir}/target/classes" + * @required + */ + protected File cp; + + @Override + public String[] getDefaultIncludes() { + return new String[]{defaultIncludes}; + } + + @Override + public String[] getDefaultExcludes() { + return new String[]{}; + } + + @Override + public File getDefaultBasedir() { + return defaultBasedir; + } + + @Override + public FileUpdater newFileUpdater(SourceEntry entry) { + return FileUpdaterHelper.newJavaFileUpdater(entry.getBasedir(), cp); + } + + @Override + protected String getKeyModifierStart() { + return "_\\(\\s*\""; + } + + @Override + protected String getKeyModifierEnd() { + return "\"\\s*(\\)|,|\\+|$)"; + } + + @Override + protected String getOutGetter() { + return "java.getter"; + } + + protected I18nFilter filter; + + @Override + public void init() { + super.init(); + filter = new I18nFilter(); + } + + @Override + public void parseFile(File srcFile) { + LineNumberReader lnr=null; + String line=null; + try { + lnr = new LineNumberReader(new InputStreamReader(new FileInputStream(srcFile))); + + while (lnr.ready()) { + line = lnr.readLine(); + parseLine(srcFile, line); + } + + } catch (Exception e) { + if (line!=null) { + getLog().error("could not parse line "+line); + } + throw new ParserException(e); + } + } + + /* + * (non-Javadoc) + * @see org.codelutin.i18n.plugin.core.Parser#parseLine(java.io.File, java.lang.String) + */ + @Override + public void parseLine(File srcFile, String line) { + String keysSet = filter.parse(line); + + if (!keysSet.equals(I18nFilter.EMPTY_STRING)) { + touchFile = true; + // Found a set of i18n Strings, split it. + String[] keys = keysSet.split("="); + for (String key : keys) { + String keyModified = key; + for (ParserEvent event : events) { + event.eventChangeKey(key, !oldLanguage.containsKey(key)); + keyModified = event.eventGetRealKey(); + } + if (oldParser.containsKey(key)) { + result.put(keyModified, oldParser.get(key)); + } else { + result.put(keyModified, key); + } + } + } + } + +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaActionConfig.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaActionConfig.java new file mode 100644 index 0000000..9a4bb23 --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaActionConfig.java @@ -0,0 +1,87 @@ +/* +* *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package org.nuiton.i18n.plugin.parser.impl; + +import org.nuiton.i18n.plugin.parser.ParserEvent; + +import java.io.File; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Un parseur java pour scanner les annotations ActionConfig + * + * @author chemit + * @goal parserJavaActionConfig + * @phase generate-resources + */ +public class ParserJavaActionConfig extends ParserJava { + + protected static final Pattern MATCH_PATTERN = Pattern.compile("(name|shortDescription|longDescription|name2|shortDescription2|longDescription2)\\s*=\\s*\"([\\w|\\.]+)\"(|\\s*|\\s*,\\s*$)"); + + @Override + protected String getKeyModifierStart() { + return "[\\w|\\.]+\\s*=\\s*\""; + } + + @Override + protected String getKeyModifierEnd() { + return "\"\\s*(\\)|,|\\+|$)"; + } + + @Override + protected String getOutGetter() { + return "java-action-config.getter"; + } + + /* + * (non-Javadoc) + * @see org.codelutin.i18n.plugin.extension.XmlParser#extract(java.lang.String) + */ + + public String extract(String i18nString) { + Matcher matcher = MATCH_PATTERN.matcher(i18nString.trim()); + if (matcher.matches()) { + return matcher.group(2); + } + return null; + } + + /* + * (non-Javadoc) + * @see org.codelutin.i18n.plugin.core.Parser#parseLine(java.io.File, java.lang.String) + */ + @Override + public void parseLine(File srcFile, String line) { + String key = extract(line); + if (key != null) { + touchFile = true; + String keyModified = key; + for (ParserEvent event : events) { + event.eventChangeKey(key, !oldLanguage.containsKey(key)); + keyModified = event.eventGetRealKey(); + } + if (oldParser.containsKey(key)) { + result.put(keyModified, oldParser.get(key)); + } else { + result.put(keyModified, key); + } + } + } + +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaTabConfig.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaTabConfig.java new file mode 100644 index 0000000..5baf048 --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaTabConfig.java @@ -0,0 +1,35 @@ +/** + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.plugin.parser.impl; + +/** + * Un parseur java pour scanner les annotations TabContentConfig. + * + * @author chemit + * @goal parserJavaTabConfig + * @phase generate-resources + */ +public class ParserJavaTabConfig extends ParserJavaActionConfig { + + @Override + protected String getOutGetter() { + return "java-tab-config.getter"; + } + +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJaxx.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJaxx.java new file mode 100644 index 0000000..e7054bb --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJaxx.java @@ -0,0 +1,113 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ + +package org.nuiton.i18n.plugin.parser.impl; + +import org.nuiton.util.SourceEntry; +import org.nuiton.util.FileUpdater; +import org.nuiton.util.FileUpdaterHelper; + +import java.io.File; + +/** + * Récupération des chaine à traduire depuis les fichiers xml Jaxx. + * + * @author julien + * @goal parserJaxx + * @phase generate-resources + * @deprecated since 1.0.0, prefer use the java parser since xml parser can not + * be easly extendable + */ +@Deprecated +public class ParserJaxx extends ParserXml { + + /** + * Source entries (src+includes+excludes) . + * + * @parameter expression="${i18n.defaultIncludes}" default-value="**\\/*.jaxx" + */ + protected String defaultIncludes; + + /** + * Where jaxx files should have been generated. + * + * @parameter expression="${i18n.defaultGenerateBasedir}" default-value="${basedir}/target/generated-sources/java" + */ + protected File defaultGenerateBasedir; + + /** + * Regles xml. + * + * @parameter expression="${i18n.rulesJaxx}" default-value="jaxx.rules" + */ + protected String rulesJaxx; + + @Override + public String[] getDefaultIncludes() { + return new String[]{defaultIncludes}; + } + + @Override + public String[] getDefaultExcludes() { + return new String[]{}; + } + + @Override + public FileUpdater newFileUpdater(SourceEntry entry) { + return FileUpdaterHelper.newJavaFileUpdater(entry.getBasedir(), defaultGenerateBasedir); + } + + @Override + protected String getOutGetter() { + return "jaxx.getter"; + } + + @Override + protected String getKeyModifierStart() { + return "=\\s*[\"\']"; + } + + @Override + protected String getKeyModifierEnd() { + return "[\"\']"; + } + + @Override + protected String getFileRules() { + return rulesJaxx; + } + + @Override + protected String getCoreFileRules() { + return "jaxx.rules"; + } + + public void setRulesJaxx(String rulesJaxx) { + this.rulesJaxx = rulesJaxx; + } + + /* + * (non-Javadoc) + * @see org.codelutin.i18n.plugin.extension.XmlParser#extract(java.lang.String) + */ + @Override + public String extract(String i18nString) { + return i18nString.length() == 0 ? null : i18nString; + } + +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserSwixat.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserSwixat.java new file mode 100644 index 0000000..a5b311a --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserSwixat.java @@ -0,0 +1,104 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ + +package org.nuiton.i18n.plugin.parser.impl; + +import org.nuiton.util.SourceEntry; +import org.nuiton.util.FileUpdater; + +/** + * Recuperation des chaines à traduire depuis les fichiers xml Swixat. + * + * @author julien + * @goal parserSwixat + * @phase generate-resources + * @deprecated since 1.0.0 : swixat is dead... + */ +@Deprecated +public class ParserSwixat extends ParserXml { + + /** + * Source entries (src+includes) . + * + * @parameter expression="${i18n.defaultIncludes}" default-value="**\\/*.xml" + */ + protected String defaultIncludes; + + /** + * Source entries (src+excludes) . + * + * @parameter expression="${i18n.defaultIncludes}" default-value="**\\/context.xml" + */ + protected String defaultExcludes; + + /** + * Regles xml. + * + * @parameter expression="${i18n.rulesSwixat}" default-value="swixat.rules" + */ + protected String rulesSwixat; + + @Override + public String[] getDefaultIncludes() { + return new String[]{defaultIncludes}; + } + + @Override + public String[] getDefaultExcludes() { + return new String[]{defaultExcludes}; + } + + @Override + public FileUpdater newFileUpdater(SourceEntry entry) { + return null; + } + + @Override + protected String getKeyModifierStart() { + return "=\\s*[\"\']"; + } + + @Override + protected String getKeyModifierEnd() { + return "[\"\']"; + } + + @Override + protected String getOutGetter() { + return "swixat.getter"; + } + + @Override + protected String getFileRules() { + return rulesSwixat; + } + + @Override + protected String getCoreFileRules() { + return "swixat.rules"; + } + + /* + * (non-Javadoc) + * @see org.codelutin.i18n.plugin.extension.XmlParser#extract(java.lang.String) + */ + @Override + public String extract(String i18nString) { + return i18nString; + } +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserValidation.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserValidation.java new file mode 100644 index 0000000..d080ee8 --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserValidation.java @@ -0,0 +1,194 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package org.nuiton.i18n.plugin.parser.impl; + +import java.io.IOException; +import java.net.URLConnection; +import org.nuiton.util.SourceEntry; +import org.nuiton.util.FileUpdater; +import org.nuiton.util.MirroredFileUpdater; + +import java.io.File; +import java.net.SocketTimeoutException; +import java.net.URL; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * Récupération des chaine à traduire depuis les fichiers xml de validation. + * <p/> + * Le goal doit etre execute avant que les resources soient copiees dans target/classes + * pour rendre operatne le file updater (sinon lesfichiers sont toujours a jour...) + * + * @author chemit + * @goal parserValidation + * @phase generate-resources + */ +public class ParserValidation extends ParserXml { + + public static final String XWORK_PUBLIC_ID = "-//OpenSymphony Group//XWork Validator 1.0.2//EN"; + final URL xworksResource = getClass().getResource("/xwork-validator-1.0.2.dtd"); + /** + * Source entries (src+includes+excludes) . + * + * @parameter expression="${i18n.defaultIncludes}" default-value="**\\/**-validation.xml" + */ + protected String defaultIncludes; + /** + * Where jaxx files should have been generated. + * + * @parameter expression="${i18n.cp}" default-value="${basedir}/target/classes" + */ + protected File cp; + /** + * Regles xml. + * + * @parameter expression="${i18n.rulesValidation}" default-value="validation.rules" + */ + protected String rulesValidation; + /** + * default src for an entry. + * + * @parameter expression="${i18n.defaultBasedir}" default-value="${basedir}/src/main/resources" + * @required + */ + protected File defaultBasedir; + /** + * Always use the local xowrks dtd to increase performance. + * + * @parameter expression="${i18n.useLocalResolver}" default-value="true" + * @since 1.6.0 + */ + protected boolean useLocalResolver; + + @Override + public String[] getDefaultIncludes() { + return new String[]{defaultIncludes}; + } + + @Override + public String[] getDefaultExcludes() { + return new String[]{}; + } + + @Override + public File getDefaultBasedir() { + return defaultBasedir; + } + + @Override + public FileUpdater newFileUpdater(SourceEntry entry) { + return new MirroredFileUpdater("", "", entry.getBasedir(), this.cp) { + + @Override + public File getMirrorFile(File f) { + String file = f.getAbsolutePath().substring(this.prefixSourceDirecotory); + return new File(this.destinationDirectory + File.separator + file); + } + }; + } + + @Override + protected String getOutGetter() { + return "validation.getter"; + } + + @Override + protected String getKeyModifierStart() { + return "=\\s*[\"\']"; + } + + @Override + protected String getKeyModifierEnd() { + return "[\"\']"; + } + + @Override + protected String getFileRules() { + return rulesValidation; + } + + @Override + protected String getCoreFileRules() { + return "validation.rules"; + } + +// public void setRulesJaxx(String rulesJaxx) { +// this.rulesValidation = rulesJaxx; +// } + + @Override + public String extract(String i18nString) { + String s = null; + if (!i18nString.trim().isEmpty()) { + s = i18nString.trim(); + int end = s.indexOf("##"); + if (end > 0) { + // remove params from key + s = s.substring(0, end); + } + } + if (getLog().isDebugEnabled()) { + getLog().debug(i18nString + " = " + s); + } + return s; + } + + @Override + public EntityResolver getEntityResolver() { + + return new EntityResolver() { + + public static final String XWORK_PUBLIC_ID = "-//OpenSymphony Group//XWork Validator 1.0.2//EN"; + boolean useLocal = useLocalResolver; + + @Override + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + if (getLog().isDebugEnabled()) { + getLog().debug("publicID:" + publicId + ", systemId:" + systemId); + } + if (XWORK_PUBLIC_ID.equals(publicId)) { + if (!useLocal) { + URL uri = new URL(systemId); + if (verbose) { + getLog().info("try to connect to " + uri); + } + URLConnection openConnection = uri.openConnection(); + openConnection.setUseCaches(true); + openConnection.setConnectTimeout(1000); + try { + openConnection.connect(); + return new InputSource(openConnection.getInputStream()); + } catch (SocketTimeoutException e) { + useLocal = true; + } catch (IOException e) { + useLocal = true; + } + } + + // use directly local resource + InputSource inputSource = new InputSource(xworksResource.openStream()); + return inputSource; + } + // use the default behaviour + return null; + } + }; + } +} diff --git a/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXml.java b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXml.java new file mode 100644 index 0000000..8b78c3a --- /dev/null +++ b/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXml.java @@ -0,0 +1,255 @@ +/* + * *##% Plugin maven pour i18n + * Copyright (C) 2007 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package org.nuiton.i18n.plugin.parser.impl; + +import javax.xml.parsers.ParserConfigurationException; +import org.nuiton.i18n.plugin.parser.AbstractI18nParser; +import org.nuiton.i18n.plugin.parser.ParserEvent; +import org.nuiton.i18n.plugin.parser.ParserException; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathFactory; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.w3c.dom.Document; +import org.xml.sax.EntityResolver; + +/** + * Récupération des chaines à traduire depuis les fichiers xml. + * + * @author julien + */ +public abstract class ParserXml extends AbstractI18nParser { + + /** Taille du buffer pour les lectures/écritures */ + protected static final int BUFFER_SIZE = 8 * 1024; + /** + * default src for an entry. + * + * @parameter expression="${i18n.defaultBasedir}" default-value="${basedir}/src/main/uimodel" + * @required + */ + protected File defaultBasedir; + protected String rules; + protected XPathFactory factory; + protected XPath xpath; + protected DocumentBuilder builder; + + /** + * Fonction d'extraction de la chaine + * + * @param i18nString le clef i18n + * @return la chaine + */ + public abstract String extract(String i18nString); + + /** @return le fichier des rules */ + protected abstract String getFileRules(); + + /** @return le fichier des rules de base à toujours charger */ + protected abstract String getCoreFileRules(); + + @Override + public void init() { + super.init(); + this.factory = XPathFactory.newInstance(); + this.rules = getRules(getFileRules()); + this.xpath = factory.newXPath(); + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); // never forget this! + + try { + // never forget this! + builder = documentBuilderFactory.newDocumentBuilder(); + + EntityResolver resolver = getEntityResolver(); + + if (resolver != null) { + builder.setEntityResolver(resolver); + } + + } catch (ParserConfigurationException ex) { + throw new IllegalStateException("could not load DocumentBuilder for reason " + ex.getMessage(), ex); + } + } + + public EntityResolver getEntityResolver() { + return null; + } + + public InputSource getSystemId(String publicId) { + return null; + } + + @Override + public void parseFile(File file) { + NodeList list; +// InputSource inputSource = new InputSource(file.getAbsolutePath()); // TODO: A deplacer pour les performances + + try { + int size = result.size(); + + // Recherche des clés à partir d'un xpath + + Document doc = builder.parse(file.getAbsolutePath()); +// Document doc = builder.parse(new FileInputStream(file.getAbsolutePath()),xworksResource.getFile()); + XPathExpression expression = xpath.compile(rules); + list = (NodeList) expression.evaluate(doc, XPathConstants.NODESET); +// list = (NodeList) expression.evaluate(inputSource, XPathConstants.NODESET); + + for (int index = 0; index < list.getLength(); index++) { + Node node = list.item(index); + parseLine(file, node.getTextContent()); + } + if (safeMode) { + // Détection de nouvelles clés, sauvegarde du fichier pour pouvoir le restaurer en cas de plantage + if (size != result.size()) { + saveGetterFile(); + } + } + } catch (Exception e) { + throw new ParserException(e); + } + } + + @Override + public void parseLine(File file, String key) { + key = extract(key); + if (key != null) { + touchFile = true; + String keyModified = key; + for (ParserEvent event : events) { + event.eventChangeKey(key, !oldLanguage.containsKey(key)); + keyModified = event.eventGetRealKey(); + } + + if (oldParser.containsKey(key)) { + result.put(keyModified, oldParser.get(key)); + } else { + result.put(keyModified, key); + } + } + } + + @Override + public File getDefaultBasedir() { + return defaultBasedir; + } + + /** + * Récupère le xpath à partir d'un fichier + * + * @param fileRules le nom du fichier contant les règles + * @return le xpath à partir d'un fichier + */ + private String getRules(String fileRules) { + StringBuilder buffer = new StringBuilder(); + + try { + String readInputStream; + + // load core rules + readInputStream = loadRulesFile(getCoreFileRules()); + if (!silent && verbose) { + getLog().info("core rules : " + getCoreFileRules()); + } + buffer.append(readInputStream); + + if (!fileRules.equals(getCoreFileRules())) { + // add custom rules + readInputStream = loadRulesFile(fileRules); + if (!silent && verbose) { + getLog().info("custom rules : " + fileRules); + } + buffer.append(" | ").append(readInputStream); + } + } catch (IOException e) { + throw new ParserException(e); + } + + return buffer.toString(); + } + + private String loadRulesFile(String fileRules) throws IOException { + File f = new File(fileRules); + + InputStream inputStream; + if (f.exists()) { + // load from a file + try { + inputStream = new FileInputStream(f); + } catch (FileNotFoundException e) { + throw new ParserException(e); + } + } else { + // load from classpath + ClassLoader classLoader = getClass().getClassLoader(); + inputStream = classLoader.getResourceAsStream(fileRules); + } + if (inputStream == null) { + throw new ParserException("could not found file of rules : " + fileRules); + } + + inputStream = new BufferedInputStream(inputStream); + + try { + // Lecture + String readInputStream; + readInputStream = readInputStream(inputStream); + return readInputStream; + } catch (IOException e) { + throw new ParserException(e); + } finally { + inputStream.close(); + } + } + + /** + * Permet la lecture d'un InputStream et Suppressions. + * + * @param in le flux entrant + * @return le contenu du flux + * @throws IOException si problème de lecture dans flux entrant + */ + private String readInputStream(InputStream in) throws IOException { + StringBuilder sb = new StringBuilder(); + byte[] buffer = new byte[BUFFER_SIZE]; + while (in.read(buffer, 0, BUFFER_SIZE) != -1) { + String tmp = new String(buffer); + sb.append(tmp); + } + in.close(); + // Suppression + String txt = sb.toString().trim(); + txt = txt.replaceAll("#.*\n", ""); // suppression des commentaires + txt = txt.replaceAll("\\s+", " | "); // contruction du xpath avec des ou + txt = txt.replaceAll("(^ \\| )|( \\| $)", ""); // suppression des ou de début ee fin + return txt; + } +} diff --git a/maven-i18n-plugin/src/main/resources/META-INF/services/org.apache.commons.logging.LogFactory b/maven-i18n-plugin/src/main/resources/META-INF/services/org.apache.commons.logging.LogFactory new file mode 100644 index 0000000..c617f1c --- /dev/null +++ b/maven-i18n-plugin/src/main/resources/META-INF/services/org.apache.commons.logging.LogFactory @@ -0,0 +1 @@ +org.apache.commons.logging.impl.LogFactoryImpl \ No newline at end of file diff --git a/maven-i18n-plugin/src/main/resources/jaxx.rules b/maven-i18n-plugin/src/main/resources/jaxx.rules new file mode 100644 index 0000000..a9a98fd --- /dev/null +++ b/maven-i18n-plugin/src/main/resources/jaxx.rules @@ -0,0 +1,37 @@ +# Règles pour JAXX + +//JDialog/@title +//JFrame/@title + +//tab/@title +//tab/@toolTipText + +//JMenu/@text +//JMenu/@toolTipText + +//JMenuItem/@text +//JMenuItem/@toolTipText + +//JButton/@text +//JButton/@toolTipText + +//JToggleButton/@text +//JToggleButton/@toolTipText + +//JRadioButton/@text +//JRadioButton/@toolTipText + +//JCheckBox/@text +//JCheckBox/@toolTipText + +//JPasswordField/@text +//JPasswordField/@toolTipText + +//JToolBar/@text +//JToolBar/@toolTipText + +//JLabel/@text +//JLabel/@toolTipText + +//JTextField/@text +//JTextField/@toolTipText diff --git a/maven-i18n-plugin/src/main/resources/log4j.properties b/maven-i18n-plugin/src/main/resources/log4j.properties new file mode 100644 index 0000000..4c30f3f --- /dev/null +++ b/maven-i18n-plugin/src/main/resources/log4j.properties @@ -0,0 +1,10 @@ +# Global logging configuration +log4j.rootLogger=ERROR, stdout +# Console output... +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) %M - %m%n + +# package level +log4j.logger.org.codelutin.util=INFO +log4j.logger.org.codelutin.i18n.plugin=INFO diff --git a/maven-i18n-plugin/src/main/resources/swixat.rules b/maven-i18n-plugin/src/main/resources/swixat.rules new file mode 100644 index 0000000..fe549c9 --- /dev/null +++ b/maven-i18n-plugin/src/main/resources/swixat.rules @@ -0,0 +1,33 @@ +# Règles pour swixat +//Frame/@title +//frame/@title + +//Label/@text +//label/@text + +//Button/@text +//button/@text + +//Menu/@text +//menu/@text + +//Checkbox/@text +//checkbox/@text + +//RadioButton/@text +//radioButton/@text + +//Menuitem/@text +//menuitem/@text + +//Textarea/@text +//textarea/@text + +//Panel/@name +//panel/@name + +//MatrixPanel/@name +//matrixPanel/@name + +//Table/@name +//table/@name diff --git a/maven-i18n-plugin/src/main/resources/validation.rules b/maven-i18n-plugin/src/main/resources/validation.rules new file mode 100644 index 0000000..9f0f8a8 --- /dev/null +++ b/maven-i18n-plugin/src/main/resources/validation.rules @@ -0,0 +1,3 @@ +# Règles pour la validation XWorks + +//validators/field/field-validator/message diff --git a/maven-i18n-plugin/src/main/resources/xwork-validator-1.0.2.dtd b/maven-i18n-plugin/src/main/resources/xwork-validator-1.0.2.dtd new file mode 100644 index 0000000..18ced6c --- /dev/null +++ b/maven-i18n-plugin/src/main/resources/xwork-validator-1.0.2.dtd @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + XWork Validators DTD. + Used the following DOCTYPE. + + <!DOCTYPE validators PUBLIC + "-//OpenSymphony Group//XWork Validator 1.0.2//EN" + "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> +--> + + +<!ELEMENT validators (field|validator)+> + +<!ELEMENT field (field-validator+)> +<!ATTLIST field + name CDATA #REQUIRED +> + +<!ELEMENT field-validator (param*, message)> +<!ATTLIST field-validator + type CDATA #REQUIRED + short-circuit (true|false) "false" +> + +<!ELEMENT validator (param*, message)> +<!ATTLIST validator + type CDATA #REQUIRED + short-circuit (true|false) "false" +> + +<!ELEMENT param (#PCDATA)> +<!ATTLIST param + name CDATA #REQUIRED +> + +<!ELEMENT message (#PCDATA)> +<!ATTLIST message + key CDATA #IMPLIED +> + + diff --git a/maven-i18n-plugin/src/site/apt/index.apt b/maven-i18n-plugin/src/site/apt/index.apt new file mode 100644 index 0000000..794360b --- /dev/null +++ b/maven-i18n-plugin/src/site/apt/index.apt @@ -0,0 +1,42 @@ +---- +Introduction +---- +---- +2009-08-22 +---- + +Maven I18n Plugin + + The Maven I18n Plugin is used to compute i18n bundles for a given maven module. + +Goals Overview + + The I18n plugin has the following goals: + + * {{{parserJava-mojo.html} i18n:parserJava}} parse Java sources. + + * {{{parserJaxx-mojo.html} i18n:parserJaxx}} parse Jaxx sources. + + * {{{parserSwixat-mojo.html} i18n:parserSwixat}} parse Jaxx sources. + + * {{{parserValidation-mojo.html} i18n:parserValidation}} parse XWorks validation sources. + + * {{{parserJavaActionConfig-mojo.html} i18n:parserJavaActionConfig}} parse actions jaxx. + + * {{{parserJavaTabConfig-mojo.html} i18n:parserJavaTabConfig}} parse tabs jaxx. + + * {{{get-mojo.html} i18n:get}} assembly getter computed by parser-like goals. + + * {{{gen-mojo.html} i18n:gen}} generate i18n bundle from getters. + + * {{{bundle-mojo.html} i18n:bundle}} generate unique i18n bundle for final application. + + * {{{help-mojo.html} i18n:help}} display help. + +Usage + + Instructions on how to use the Help Plugin can be found in {{{usages.html} usages}} page. + +Examples + + <to be done.> diff --git a/maven-i18n-plugin/src/site/apt/usages.apt b/maven-i18n-plugin/src/site/apt/usages.apt new file mode 100644 index 0000000..b7e8c6d --- /dev/null +++ b/maven-i18n-plugin/src/site/apt/usages.apt @@ -0,0 +1,8 @@ +---- +Usages +---- +---- +2009-08-22 +---- + + <To be done...> \ No newline at end of file diff --git a/maven-i18n-plugin/src/site/site.xml b/maven-i18n-plugin/src/site/site.xml new file mode 100644 index 0000000..cda222c --- /dev/null +++ b/maven-i18n-plugin/src/site/site.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="${project.name}"> + + <bannerLeft> + <name>${project.name}</name> + <href>index.html</href> + </bannerLeft> + + <body> + + <breadcrumbs> + <item name="${project.name}" href="${project.url}" /> + </breadcrumbs> + + <menu ref="parent"/> + + <menu name="Utilisateur"> + <item name="Introduction" href="index.html"/> + <item name="Usages" href="usages.html"/> + <item name="Goals" href="plugin-info.html"> + <item name="parserJava" href="parserJava-mojo.html"/> + <item name="parserJaxx" href="parserJaxx-mojo.html"/> + <item name="parserSwixat" href="parserSwixat-mojo.html"/> + <item name="parserJavaActionConfig" href="parserJavaActionConfig-mojo.html"/> + <item name="parserJavaTabConfig" href="parserJavaTabConfig-mojo.html"/> + <item name="parserXWorks" href="parserValidation-mojo.html"/> + <item name="get" href="get-mojo.html"/> + <item name="gen" href="gen-mojo.html"/> + <item name="bundle" href="bundle-mojo.html"/> + <item name="help" href="help-mojo.html"/> + </item> + </menu> + + <menu name="Téléchargement"> + <item href="${repository.home.url}/org/nuiton/i18n/${project.artifactId}/${project.version}/${project.build.finalName}.jar" + name="Librairie (jar)"/> + <item href="${repository.home.url}/org/nuiton/i18n/${project.artifactId}/${project.version}/${project.build.finalName}-javadoc.jar" + name="Javadoc (jar)"/> + <item href="${repository.home.url}/org/nuiton/i18n/${project.artifactId}/${project.version}/${project.build.finalName}-sources.jar" + name="Sources (jar)"/> + </menu> + + <menu ref="reports"/> + + </body> +</project> diff --git a/nuiton-i18n-api/LICENSE.txt b/nuiton-i18n-api/LICENSE.txt new file mode 100644 index 0000000..3f7b8b1 --- /dev/null +++ b/nuiton-i18n-api/LICENSE.txt @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/nuiton-i18n-api/README.txt b/nuiton-i18n-api/README.txt new file mode 100644 index 0000000..d2e50d3 --- /dev/null +++ b/nuiton-i18n-api/README.txt @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install diff --git a/nuiton-i18n-api/changelog.txt b/nuiton-i18n-api/changelog.txt new file mode 100644 index 0000000..d9bea52 --- /dev/null +++ b/nuiton-i18n-api/changelog.txt @@ -0,0 +1,2 @@ +1.0.0 ? + * initial release diff --git a/nuiton-i18n-api/doc/FormatConverter-uml.uxf b/nuiton-i18n-api/doc/FormatConverter-uml.uxf new file mode 100644 index 0000000..78bb4bf --- /dev/null +++ b/nuiton-i18n-api/doc/FormatConverter-uml.uxf @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?><umlet_diagram><element><type>com.umlet.element.base.SequenceDiagram</type><coordinates><x>80</x><y>20</y><w>975</w><h>500</h></coordinates><panel_attributes>_factory:CFactory_|_XMLConverter_|_SQLConverter_|_values:FormatMap_|_App_ +5->4:put(FORMAT_SQL, val) +5->4:5,4:convert(FORMAT_XML) +4->1:4,1:convert(clazz, FORMAT_XML, values) +1->2:1,2:convert(factory, clazz, FORMAT_XML, values) +2->4:2,4:containsKey(FORMAT_SQL) +4.>2:2,4:true +2->4:2,4:convert(factory, FORMAT_SQL) +4.>2:2,4:result +2->2:2:sqlToXML +2.>1:2,1:result +1.>4:1,4:result +4->4:4:put(FORMAT_XML, result) +4.>5:4,5:result +</panel_attributes><additional_attributes></additional_attributes></element><element><type>com.umlet.element.base.Note</type><coordinates><x>400</x><y>0</y><w>340</w><h>20</h></coordinates><panel_attributes>Convertion entre deux format compatible</panel_attributes><additional_attributes></additional_attributes></element><element><type>com.umlet.element.base.Note</type><coordinates><x>380</x><y>530</y><w>340</w><h>20</h></coordinates><panel_attributes>Convertion entre deux format imcompat [...] +5->4:put(FORMAT_YYY, val) +5->4:5,4:convert(FORMAT_XML) +4->1:4,1:convert(clazz, FORMAT_XML, values) +1->2:1,2:convert(factory, clazz, FORMAT_XML, values) +2->4:2,4:containsKey(FORMAT_SQL) +4.>2:2,4:false +2->4:2,4:convert(factory, FORMAT_JAVA) +4->4:4:unconvert(factory, FORMAT_YYY) +4->1:1,4:unconvert(clazz, FORMAT_YYY, values) +1->3:1,3:unconvert(factory, clazz, FORMAT_YYY, values) +3.>1:1,3:result[java] +1.>4:1,4:result[java] +4->4:4:put(FORMAT_JAVA, result) +4.>2:2,4:result[java] +2->2:2:javaToXML +2.>1:2,1:result[xml] +1.>4:1,4:result[xml] +4->4:4:put(FORMAT_XML, result) +4.>5:4,5:result[xml]</panel_attributes><additional_attributes></additional_attributes></element></umlet_diagram> \ No newline at end of file diff --git a/nuiton-i18n-api/pom.xml b/nuiton-i18n-api/pom.xml new file mode 100644 index 0000000..009f1b4 --- /dev/null +++ b/nuiton-i18n-api/pom.xml @@ -0,0 +1,102 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + + <parent> + <groupId>org.nuiton</groupId> + <artifactId>i18n</artifactId> + <version>1.0.0</version> + </parent> + + <groupId>org.nuiton.i18n</groupId> + <artifactId>nuiton-i18n-api</artifactId> + + <dependencies> + + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + </dependency> + + <dependency> + <groupId>commons-beanutils</groupId> + <artifactId>commons-beanutils</artifactId> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + + </dependencies> + + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>nuiton-i18n - api</name> + <description>Api of i18n system</description> + <inceptionYear>2004</inceptionYear> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + + <packaging>jar</packaging> + + <build> + + <defaultGoal>install</defaultGoal> + + </build> + + <!-- ************************************************************* --> + <!-- *** Build Environment ************************************** --> + <!-- ************************************************************* --> + + <profiles> + <profile> + <id>release-profile</id> + <activation> + <property> + <name>performRelease</name> + <value>true</value> + </property> + </activation> + <build> + <plugins> + + <!-- launch in a release the assembly automaticly --> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <executions> + <execution> + <id>create-assemblies</id> + <phase>verify</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + <configuration> + <attach>false</attach> + <descriptorRefs> + <descriptorRef>deps</descriptorRef> + <descriptorRef>full</descriptorRef> + </descriptorRefs> + </configuration> + </plugin> + + </plugins> + + </build> + </profile> + </profiles> + +</project> diff --git a/nuiton-i18n-api/src/main/java/org/nuiton/i18n/CountryEnum.java b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/CountryEnum.java new file mode 100644 index 0000000..61604c0 --- /dev/null +++ b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/CountryEnum.java @@ -0,0 +1,284 @@ +/* + * *##% Lutin utilities library + * Copyright (C) 2004 - 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package org.nuiton.i18n; + +/** + * Une énumération pour représenter le pays d'une locale + * <p/> + * <a href="http://www.iso.org/iso/country_codes"><code>ISO 3166-1:1998 (ICS n° 01.140.20)</code></a>. + * <p/> + * <a href="http://www.iso.org/iso/french_country_names_and_code_elements">la liste des codes</a> + * <p/> + * Chaque pays est repésenté ainsi : + * <pre>A2, // A3 Number Country name</pre> + * + * @author chemit + */ +public enum CountryEnum { + + AF, // AFG 004 AFGHANISTAN + AL, // ALB 008 ALBANIA + DZ, // DZA 012 ALGERIA + AS, // ASM 016 AMERICAN SAMOA + AD, // AND 020 ANDORRA + AO, // AGO 024 ANGOLA + AI, // AIA 660 ANGUILLA + AQ, // ATA 010 ANTARCTICA + AG, // ATG 028 ANTIGUA AND BARBUDA + AR, // ARG 032 ARGENTINA + AM, // ARM 051 ARMENIA + AW, // ABW 533 ARUBA + AU, // AUS 036 AUSTRALIA + AT, // AUT 040 AUSTRIA + AZ, // AZE 031 AZERBAIJAN + BS, // BHS 044 BAHAMAS + BH, // BHR 048 BAHRAIN + BD, // BGD 050 BANGLADESH + BB, // BRB 052 BARBADOS + BY, // BLR 112 BELARUS + BE, // BEL 056 BELGIUM + BZ, // BLZ 084 BELIZE + BJ, // BEN 204 BENIN + BM, // BMU 060 BERMUDA + BT, // BTN 064 BHUTAN + BO, // BOL 068 BOLIVIA + BA, // BIH 070 BOSNIA AND HERZEGOWINA + BW, // BWA 072 BOTSWANA + BV, // BVT 074 BOUVET ISLAND + BR, // BRA 076 BRAZIL + IO, // IOT 086 BRITISH INDIAN OCEAN TERRITORY + BN, // BRN 096 BRUNEI DARUSSALAM + BG, // BGR 100 BULGARIA + BF, // BFA 854 BURKINA FASO + BI, // BDI 108 BURUNDI + KH, // KHM 116 CAMBODIA + CM, // CMR 120 CAMEROON + CA, // CAN 124 CANADA + CV, // CPV 132 CAPE VERDE + KY, // CYM 136 CAYMAN ISLANDS + CF, // CAF 140 CENTRAL AFRICAN REPUBLIC + TD, // TCD 148 CHAD + CL, // CHL 152 CHILE + CN, // CHN 156 CHINA + CX, // CXR 162 CHRISTMAS ISLAND + CC, // CCK 166 COCOS (KEELING) ISLANDS + CO, // COL 170 COLOMBIA + KM, // COM 174 COMOROS + CG, // COG 178 CONGO + CK, // COK 184 COOK ISLANDS + CR, // CRI 188 COSTA RICA + CI, // CIV 384 COTE D'IVOIRE + HR, // HRV 191 CROATIA (local name: Hrvatska) + CU, // CUB 192 CUBA + CY, // CYP 196 CYPRUS + CZ, // CZE 203 CZECH REPUBLIC + DK, // DNK 208 DENMARK + DJ, // DJI 262 DJIBOUTI + DM, // DMA 212 DOMINICA + DO, // DOM 214 DOMINICAN REPUBLIC + TP, // TMP 626 EAST TIMOR + EC, // ECU 218 ECUADOR + EG, // EGY 818 EGYPT + SV, // SLV 222 EL SALVADOR + GQ, // GNQ 226 EQUATORIAL GUINEA + ER, // ERI 232 ERITREA + EE, // EST 233 ESTONIA + ET, // ETH 210 ETHIOPIA + FK, // FLK 238 FALKLAND ISLANDS (MALVINAS) + FO, // FRO 234 FAROE ISLANDS + FJ, // FJI 242 FIJI + FI, // FIN 246 FINLAND + FR, // FRA 250 FRANCE + FX, // FXX 249 FRANCE, METROPOLITAN + GF, // GUF 254 FRENCH GUIANA + PF, // PYF 258 FRENCH POLYNESIA + TF, // ATF 260 FRENCH SOUTHERN TERRITORIES + GA, // GAB 266 GABON + GM, // GMB 270 GAMBIA + GE, // GEO 268 GEORGIA + DE, // DEU 276 GERMANY + GH, // GHA 288 GHANA + GI, // GIB 292 GIBRALTAR + GR, // GRC 300 GREECE + GL, // GRL 304 GREENLAND + GD, // GRD 308 GRENADA + GP, // GLP 312 GUADELOUPE + GU, // GUM 316 GUAM + GT, // GTM 320 GUATEMALA + GN, // GIN 324 GUINEA + GW, // GNB 624 GUINEA-BISSAU + GY, // GUY 328 GUYANA + HT, // HTI 332 HAITI + HM, // HMD 334 HEARD AND MC DONALD ISLANDS + HN, // HND 340 HONDURAS + HK, // HKG 344 HONG KONG + HU, // HUN 348 HUNGARY + IS, // ISL 352 ICELAND + IN, // IND 356 INDIA + ID, // IDN 360 INDONESIA + IR, // IRN 364 IRAN (ISLAMIC REPUBLIC OF) + IQ, // IRQ 368 IRAQ + IE, // IRL 372 IRELAND + IL, // ISR 376 ISRAEL + IT, // ITA 380 ITALY + JM, // JAM 388 JAMAICA + JP, // JPN 392 JAPAN + JO, // JOR 400 JORDAN + KZ, // KAZ 398 KAZAKHSTAN + KE, // KEN 404 KENYA + KI, // KIR 296 KIRIBATI + KP, // PRK 408 KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF + KR, // KOR 410 KOREA, REPUBLIC OF + KW, // KWT 414 KUWAIT + KG, // KGZ 417 KYRGYZSTAN + LA, // LAO 418 LAO PEOPLE'S DEMOCRATIC REPUBLIC + LV, // LVA 428 LATVIA + LB, // LBN 422 LEBANON + LS, // LSO 426 LESOTHO + LR, // LBR 430 LIBERIA + LY, // LBY 434 LIBYAN ARAB JAMAHIRIYA + LI, // LIE 438 LIECHTENSTEIN + LT, // LTU 440 LITHUANIA + LU, // LUX 442 LUXEMBOURG + MO, // MAC 446 MACAU + MK, // MKD 807 (provis) MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF + MG, // MDG 450 MADAGASCAR + MW, // MWI 454 MALAWI + MY, // MYS 458 MALAYSIA + MV, // MDV 462 MALDIVES + ML, // MLI 466 MALI + MT, // MLT 470 MALTA + MH, // MHL 584 MARSHALL ISLANDS + MQ, // MTQ 474 MARTINIQUE + MR, // MRT 478 MAURITANIA + MU, // MUS 480 MAURITIUS + YT, // MYT 175 MAYOTTE + MX, // MEX 484 MEXICO + FM, // FSM 583 MICRONESIA, FEDERATED STATES OF + MD, // MDA 498 MOLDOVA, REPUBLIC OF + MC, // MCO 492 MONACO + MN, // MNG 496 MONGOLIA + MS, // MSR 500 MONTSERRAT + MA, // MAR 504 MOROCCO + MZ, // MOZ 508 MOZAMBIQUE + MM, // MMR 104 MYANMAR + NA, // NAM 516 NAMIBIA + NR, // NRU 520 NAURU + NP, // NPL 524 NEPAL + NL, // NLD 528 NETHERLANDS + AN, // ANT 530 NETHERLANDS ANTILLES + NC, // NCL 540 NEW CALEDONIA + NZ, // NZL 554 NEW ZEALAND + NI, // NIC 558 NICARAGUA + NE, // NER 562 NIGER + NG, // NGA 566 NIGERIA + NU, // NIU 570 NIUE + NF, // NFK 574 NORFOLK ISLAND + MP, // MNP 580 NORTHERN MARIANA ISLANDS + NO, // NOR 578 NORWAY + OM, // OMN 512 OMAN + PK, // PAK 586 PAKISTAN + PW, // PLW 585 PALAU + PA, // PAN 591 PANAMA + PG, // PNG 598 PAPUA NEW GUINEA + PY, // PRY 600 PARAGUAY + PE, // PER 604 PERU + PH, // PHL 608 PHILIPPINES + PN, // PCN 612 PITCAIRN + PL, // POL 616 POLAND + PT, // PRT 620 PORTUGAL + PR, // PRI 630 PUERTO RICO + QA, // QAT 634 QATAR + RE, // REU 638 REUNION + RO, // ROM 642 ROMANIA + RU, // RUS 643 RUSSIAN FEDERATION + RW, // RWA 646 RWANDA + KN, // KNA 659 SAINT KITTS AND NEVIS + LC, // LCA 662 SAINT LUCIA + VC, // VCT 670 SAINT VINCENT AND THE GRENADINES + WS, // WSM 882 SAMOA + SM, // SMR 674 SAN MARINO + ST, // STP 678 SAO TOME AND PRINCIPE + SA, // SAU 682 SAUDI ARABIA + SN, // SEN 686 SENEGAL + SC, // SYC 690 SEYCHELLES + SL, // SLE 694 SIERRA LEONE + SG, // SGP 702 SINGAPORE + SK, // SVK 703 SLOVAKIA (Slovak Republic) + SI, // SVN 705 SLOVENIA + SB, // SLB 090 SOLOMON ISLANDS + SO, // SOM 706 SOMALIA + ZA, // ZAF 710 SOUTH AFRICA + ES, // ESP 724 SPAIN + LK, // LKA 144 SRI LANKA + SH, // SHN 654 ST. HELENA + PM, // SPM 666 ST. PIERRE AND MIQUELON + SD, // SDN 736 SUDAN + SR, // SUR 740 SURINAME + SJ, // SJM 744 SVALBARD AND JAN MAYEN ISLANDS + SZ, // SWZ 748 SWAZILAND + SE, // SWE 752 SWEDEN + CH, // CHE 756 SWITZERLAND + SY, // SYR 760 SYRIAN ARAB REPUBLIC + TW, // TWN 158 TAIWAN, PROVINCE OF CHINA + TJ, // TJK 762 TAJIKISTAN + TZ, // TZA 834 TANZANIA, UNITED REPUBLIC OF + TH, // THA 764 THAILAND + TG, // TGO 768 TOGO + TK, // TKL 772 TOKELAU + TO, // TON 776 TONGA + TT, // TTO 780 TRINIDAD AND TOBAGO + TN, // TUN 788 TUNISIA + TR, // TUR 792 TURKEY + TM, // TKM 795 TURKMENISTAN + TC, // TCA 796 TURKS AND CAICOS ISLANDS + TV, // TUV 798 TUVALU + UG, // UGA 800 UGANDA + UA, // UKR 804 UKRAINE + AE, // ARE 784 UNITED ARAB EMIRATES + GB, // GBR 826 UNITED KINGDOM + US, // USA 840 UNITED STATES + UM, // UMI 581 UNITED STATES MINOR OUTLYING ISLANDS + UY, // URY 858 URUGUAY + UZ, // UZB 860 UZBEKISTAN + VU, // VUT 548 VANUATU + VA, // VAT 336 VATICAN CITY STATE (HOLY SEE) + VE, // VEN 862 VENEZUELA + VN, // VNM 704 VIET NAM + VG, // VGB 092 VIRGIN ISLANDS (BRITISH) + VI, // VIR 850 VIRGIN ISLANDS (U.S.) + WF, // WLF 876 WALLIS AND FUTUNA ISLANDS + EH, // ESH 732 WESTERN SAHARA + YE, // YEM 887 YEMEN + YU, // YUG 891 YUGOSLAVIA + ZR, // ZAR 180 ZAIRE + ZM, // ZMB 894 ZAMBIA + ZW; // ZWE 716 ZIMBABWE + + public static CountryEnum valueOf(String country, CountryEnum defaultValue) { + CountryEnum countryValue = null; + try { + countryValue = CountryEnum.valueOf(country.toUpperCase()); + } catch (IllegalArgumentException e) { + System.err.println("unfound country " + country + ", will use default one : " + defaultValue); + } catch (NullPointerException e) { + System.err.println("unfound country " + country + ", will use default one : " + defaultValue); + } + return countryValue == null ? defaultValue : countryValue; + } +} diff --git a/nuiton-i18n-api/src/main/java/org/nuiton/i18n/I18nDefaultTooltipFilter.java b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/I18nDefaultTooltipFilter.java new file mode 100644 index 0000000..abaf2ce --- /dev/null +++ b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/I18nDefaultTooltipFilter.java @@ -0,0 +1,43 @@ +/* *##% Lutin utilities library + * Copyright (C) 2004 - 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ + +/* * + * i18nDefaultTooltipFilter.java + * + * Created: 2 déc. 2003 + * + * @author Benjamin Poussin <poussin@codelutin.com> + * Copyright Code Lutin + * @version $Revision$ + * + * Mise a jour: $Date$ + * par : $Author$ + */ + +package org.nuiton.i18n; + +public class I18nDefaultTooltipFilter implements I18nFilter { // I18nDefaultTooltipFilter + + @Override + public String applyFilter(String message) { + if (message != null && message.startsWith("defaultToolTip-")) { + return null; + } + return message; + } +} // I18nDefaultTooltipFilter + diff --git a/nuiton-i18n-api/src/main/java/org/nuiton/i18n/I18nFileReader.java b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/I18nFileReader.java new file mode 100644 index 0000000..725b6ad --- /dev/null +++ b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/I18nFileReader.java @@ -0,0 +1,131 @@ +/* *##% Lutin utilities library + * Copyright (C) 2004 - 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ + +/* * + * I18nFileReader.java + * + * Created: Nov 22, 2004 + * + * @author Cédric Pineau <pineau@codelutin.com> + * @version $Revision$ + * + * Last update : $Date$ + * by : $Author$ + */ + +package org.nuiton.i18n; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.Properties; +import java.util.regex.Pattern; + +/** Classe assurant la lecture et les possibles traitement nécessaires à I18n. */ +public class I18nFileReader extends Properties { + + protected static final Pattern commentPattern = Pattern.compile("[^\\\\]#"); + + protected static final Pattern splitPattern = Pattern.compile("[^\\\\]="); + private static final long serialVersionUID = 3611718334066783394L; + + public void load(InputStream inStream, String encodingTo) throws IOException { + Charset charsetTo = Charset.forName(encodingTo); + BufferedReader readerFile; + readerFile = new BufferedReader(new InputStreamReader(inStream, charsetTo)); + String lineFile; + StringBuilder builderFile; + builderFile = new StringBuilder(); + while ((lineFile = readerFile.readLine()) != null) { + builderFile.append(lineFile).append('\n'); + } + readerFile.close(); + super.load(new ByteArrayInputStream(builderFile.toString().getBytes())); + } + + protected String interpretBackslashes(String message) { + int backslashIndex = -1; + while ((backslashIndex = message.indexOf("\\", backslashIndex + 1)) != -1) { + if (message.length() >= backslashIndex + 1) { + char charNextToBackslash = message.charAt(backslashIndex + 1); + char replacementChar; + switch (charNextToBackslash) { + case '\\': + replacementChar = '\\'; + break; + case 't': + replacementChar = '\t'; + break; + case 'n': + replacementChar = '\n'; + break; + case ' ': + replacementChar = ' '; + break; + case '=': + replacementChar = '='; + break; + case ':': + replacementChar = ':'; + break; + default: + replacementChar = '\\'; + break; + } + message = message.substring(0, backslashIndex) + replacementChar + message.substring(backslashIndex + 2); + } + } + return message; + } + + private static char[] chars = {'\\', '\n', '\t', ' ', '=', ':'}; + + protected String serializeBackslashes(String message) { + for (char c : chars) { + int charIndex = -1; + while ((charIndex = message.indexOf(c, charIndex + 2)) != -1) { + String replacementString = "" + c; + switch (c) { + case '\\': + replacementString = "\\\\"; + break; + case '\t': + replacementString = "\\t"; + break; + case '\n': + replacementString = "\\n"; + break; + case ' ': + replacementString = "\\ "; + break; + case '=': + replacementString = "\\="; + break; + case ':': + replacementString = "\\:"; + break; + } + message = message.substring(0, charIndex) + replacementString + message.substring(charIndex + 1); + } + } + return message; + } + +} //I18nFileReader diff --git a/nuiton-i18n-api/src/main/java/org/nuiton/i18n/I18nFilter.java b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/I18nFilter.java new file mode 100644 index 0000000..0bd566d --- /dev/null +++ b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/I18nFilter.java @@ -0,0 +1,37 @@ +/* *##% Lutin utilities library + * Copyright (C) 2004 - 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ + +/* * + * i18nFilter.java + * + * Created: 2 déc. 2003 + * + * @author Benjamin Poussin <poussin@codelutin.com> + * Copyright Code Lutin + * @version $Revision$ + * + * Mise a jour: $Date$ + * par : $Author$ + */ + +package org.nuiton.i18n; + +public interface I18nFilter { // I18nFilter + + public String applyFilter(String message); +} // I18nFilter + diff --git a/nuiton-i18n-api/src/main/java/org/nuiton/i18n/I18nUtil.java b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/I18nUtil.java new file mode 100644 index 0000000..67d4cd0 --- /dev/null +++ b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/I18nUtil.java @@ -0,0 +1,194 @@ +package org.nuiton.i18n; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.logging.Logger; +import java.util.zip.ZipFile; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.util.LocaleConverter; + +/** + * + * @author chemit + */ +public class I18nUtil { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static final Log log = LogFactory.getLog(I18nUtil.class); + public static final String ISO_8859_1_ENCONDING = "ISO-8859-1"; + public static final String UTF_8_ENCONDING = "UTF-8"; + public static final String DEFAULT_ENCODING = ISO_8859_1_ENCONDING; + public static final Locale DEFAULT_LOCALE = Locale.UK; + + /** + * Parse a list of {@link Locale} seperated by comma. + * + * Example : fr_FR,en_GB + * + * @param str the string representation of locale separated by comma + * @return list of available locales + * @throws IllegalArgumentException ia a locale is not valid + */ + public static Locale[] parseLocales(String str) throws IllegalArgumentException { + List<Locale> result = new java.util.ArrayList<Locale>(); + String[] bundlesToUse = str.split(","); + for (int i = 0, j = bundlesToUse.length; i < j; i++) { + String s = bundlesToUse[i].trim(); + // on devrait verifier que le bundle existe + try { + Locale l = (Locale) new LocaleConverter().convert(Locale.class, s); + result.add(l); + } catch (Exception e) { + throw new IllegalArgumentException("bundle " + s + " is not a valid locale,e"); + } + } + return result.toArray(new Locale[result.size()]); + } + + public static Locale newLocale(String str) { + if (str == null) { + // get use locale + return newLocale(null, null); + } + try { + return (Locale) new LocaleConverter().convert(Locale.class, str); + } catch (Exception e) { + Logger.getLogger("org.nuiton.i18n.I18n").warning("could not load locale '" + str + " for reason : " + e.getMessage()); + // use default locale + return DEFAULT_LOCALE; + } + } + + public static Locale newLocale(String language, String country) { + if (language == null) { + // get user locale + language = System.getProperty("user.language", DEFAULT_LOCALE.getLanguage()); + country = System.getProperty("user.country", DEFAULT_LOCALE.getCountry()); + } + return newLocale(language + (country == null ? "" : '_' + country)); + } + + /** + * Test if an url contains the given directory with no recurse seeking. + * + * @param url the url to seek + * @param directory the directory to find + * @return <code>true</code> if directory was found, <code>false</code> otherwise. + * @throws java.io.IOException if any io pb + */ + public static boolean containsDirectDirectory(URL url, String directory) throws IOException { + String fileName = url.getFile(); + // TODO deal with encoding in windows, this is very durty, but it works... + File file = new File(fileName.replaceAll("%20", " ")); + if (!file.exists()) { + return false; + } + if (isJar(fileName) || isZip(fileName)) { + // cas ou le fichier du classLoader est un fichier jar ou zip + if (log.isTraceEnabled()) { + log.trace("zip to search " + file); + } + return new ZipFile(file).getEntry(directory + "/") != null; + } + if (file.isDirectory()) { + // cas ou le ichier du classLoader est un repertoire + if (log.isTraceEnabled()) { + log.trace("directory to search " + file); + } + return new File(file, directory).exists(); + } + + if (log.isWarnEnabled()) { + log.warn("unknown resource type " + url); + } + return false; + } + + /** + * Verifie si le fichier est un fichier jar. + * + * @param name nom du fichier a tester + * @return vrai si le fichier se termine par .jar faux sinon + */ + static public boolean isJar(String name) { + if (name != null && name.length() > 4) { + String ext = name.substring(name.length() - 4, name.length()); + return ".jar".equalsIgnoreCase(ext); + } + return false; + } + + /** + * Verifie si le fichier est un fichier zip + * + * @param name nom du fichier a tester + * @return vrai si le fichier se termine par .zip faux sinon + */ + static public boolean isZip(String name) { + if (name != null && name.length() > 4) { + String ext = name.substring(name.length() - 4, name.length()); + return ".zip".equalsIgnoreCase(ext); + } + return false; + } + + /** + * Retourne la liste des fichiers correspondant au pattern donne, aucun + * ordre ne doit être supposé sur les fichiers. + * + * @param repository repertoire dans lequel on recherche les fichiers + * @param pattern le nom du fichier a extraire du fichier du repertoire doit + * correspondre au pattern (repertoire + nom compris). si le + * pattern est null, tous les fichiers trouvé sont retourné. + * @return la liste des urls correspondant au pattern + */ + static public List<URL> getURLsFromDirectory(File repository, String pattern) { + try { + if (log.isTraceEnabled()) { + log.trace("search '" + pattern + "' in " + repository); + } + + List<URL> urlList = new ArrayList<URL>(); + File[] filesList = repository.listFiles(); + + if (filesList != null) { + + for (File file : filesList) { + + String name = file.getAbsolutePath(); + + if (log.isTraceEnabled()) { + log.trace("directory: " + repository + " name: " + name); + } + + // cas de recursivite : repertoire dans un repertoire + if (file.exists() && file.isDirectory()) { + urlList.addAll(getURLsFromDirectory(file, + pattern)); + // si le fichier du repertoire n'est pas un repertoire + // on verifie s'il correspond au pattern + } else if (pattern == null || name.matches(pattern)) { + URL url = file.toURI().toURL(); + if (log.isTraceEnabled()) { + log.trace("directory: " + repository + " url: " + url); + } + urlList.add(url); + } + } + } + if (log.isTraceEnabled()) { + log.trace("found with pattern '" + pattern + "' : " + urlList); + } + return urlList; + } catch (MalformedURLException eee) { + throw new IllegalArgumentException("Erreur lors de la conversion de l'url " + repository + " (pattern " + pattern + ") " + eee.getMessage(), eee); + //throw new ResourceException("Le fichier n'a pu être converti en URL", eee); + } + } +} diff --git a/nuiton-i18n-api/src/main/java/org/nuiton/i18n/LanguageEnum.java b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/LanguageEnum.java new file mode 100644 index 0000000..fae1ace --- /dev/null +++ b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/LanguageEnum.java @@ -0,0 +1,181 @@ +/* + * *##% Lutin utilities library + * Copyright (C) 2004 - 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package org.nuiton.i18n; + +/** + * Une énumération pour représenter le langue d'une locale définie dans la norme + * <a href="http://www.iso.org/iso/iso_catalogue/catalogue_ics/catalogue_detail_ics.htm?csnumber=22109&ICS1=1&ICS2=140&ICS3=20"><code>ISO 639-1:1998 (ICS n° 01.140.20)</code></a>. + * <p/> + * <a href="http://www.loc.gov/standards/iso639-2/php/French_list.php">la liste des codes</a> + * + * @author chemit + */ +public enum LanguageEnum { + + aa, // Afar + ab, // Abkhazian + af, // Afrikaans + am, // Amharic + ar, // Arabic + as, // Assamese + ay, // Aymara + az, // Azerbaijani + ba, // Bashkir + be, // Byelorussian + bg, // Bulgarian + bh, // Bihari + bi, // Bislama + bn, // Bengali; Bangla + bo, // Tibetan + br, // Breton + ca, // Catalan + co, // Corsican + cs, // Czech + cy, // Welsh + da, // Danish + de, // German + dz, // Bhutani + el, // Greek + en, // English + eo, // Esperanto + es, // Spanish + et, // Estonian + eu, // Basque + fa, // Persian + fi, // Finnish + fj, // Fiji + fo, // Faroese + fr, // French + fy, // Frisian + ga, // Irish + gd, // Scots Gaelic + gl, // Galician + gn, // Guarani + gu, // Gujarati + ha, // Hausa + he, // Hebrew (formerly iw) + hi, // Hindi + hr, // Croatian + hu, // Hungarian + hy, // Armenian + ia, // Interlingua + id, // Indonesian (formerly in) + ie, // Interlingue + ik, // Inupiak + is, // Icelandic + it, // Italian + iu, // Inuktitut + ja, // Japanese + jw, // Javanese + ka, // Georgian + kk, // Kazakh + kl, // Greenlandic + km, // Cambodian + kn, // Kannada + ko, // Korean + ks, // Kashmiri + ku, // Kurdish + ky, // Kirghiz + la, // Latin + ln, // Lingala + lo, // Laothian + lt, // Lithuanian + lv, // Latvian, Lettish + mg, // Malagasy + mi, // Maori + mk, // Macedonian + ml, // Malayalam + mn, // Mongolian + mo, // Moldavian + mr, // Marathi + ms, // Malay + mt, // Maltese + my, // Burmese + na, // Nauru + ne, // Nepali + nl, // Dutch + no, // Norwegian + oc, // Occitan + om, // (Afan) Oromo + or, // Oriya + pa, // Punjabi + pl, // Polish + ps, // Pashto, Pushto + pt, // Portuguese + qu, // Quechua + rm, // Rhaeto-Romance + rn, // Kirundi + ro, // Romanian + ru, // Russian + rw, // Kinyarwanda + sa, // Sanskrit + sd, // Sindhi + sg, // Sangho + sh, // Serbo-Croatian + si, // Sinhalese + sk, // Slovak + sl, // Slovenian + sm, // Samoan + sn, // Shona + so, // Somali + sq, // Albanian + sr, // Serbian + ss, // Siswati + st, // Sesotho + su, // Sundanese + sv, // Swedish + sw, // Swahili + ta, // Tamil + te, // Telugu + tg, // Tajik + th, // Thai + ti, // Tigrinya + tk, // Turkmen + tl, // Tagalog + tn, // Setswana + to, // Tonga + tr, // Turkish + ts, // Tsonga + tt, // Tatar + tw, // Twi + ug, // Uighur + uk, // Ukrainian + ur, // Urdu + uz, // Uzbek + vi, // Vietnamese + vo, // Volapuk + wo, // Wolof + xh, // Xhosa + yi, // Yiddish (formerly ji) + yo, // Yoruba + za, // Zhuang + zh, // Chinese + zu; // Zulu + + public static LanguageEnum valueOf(String language, LanguageEnum defaultValue) { + LanguageEnum languageValue = null; + try { + languageValue = LanguageEnum.valueOf(language.toLowerCase()); + } catch (IllegalArgumentException e) { + System.err.println("Unfound language " + language + ", will use default one " + defaultValue); + } catch (NullPointerException e) { + System.err.println("Unfound language " + language + ", will use default one " + defaultValue); + } + return languageValue == null ? defaultValue : languageValue; + } +} diff --git a/nuiton-i18n-api/src/main/java/org/nuiton/i18n/bundle/I18nBundle.java b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/bundle/I18nBundle.java new file mode 100644 index 0000000..556e1e7 --- /dev/null +++ b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/bundle/I18nBundle.java @@ -0,0 +1,160 @@ +/* +* *##% Lutin utilities library + * Copyright (C) 2004 - 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package org.nuiton.i18n.bundle; + +import java.util.Iterator; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +/** + * Class to represent a i18n Bundle. + * <p/> + * A bundle is defined by a resource prefix (eg /tmp/bundle.properties), and a list of locale implemented entries. + * <p/> + * The property {@link #bundlePrefix} is the equals order property. + * <p/> + * The property {@link #entries} contains all entries defined for this bundle. + * <p/> + * The method {@link #getEntries(java.util.Locale)} filter entries for a given locale, including scope inclusive property. + * <p/> + * The method {@link #getEntries(I18nBundleScope)} filter entries for a givne scope, with no inclusive logi. + * <p/> + * Thoses filter methods return result in the order defines in {@link I18nBundleEntry}, e.g + * <pre> + * XXX.properties + * XXX-fr.properties + * XXX-fr_FR.properties + * </pre> + * In that way, we can load resource in the good order : load before more general scope to more specialized. + * + * @author chemit + * @see I18nBundleScope + * @see I18nBundleEntry + */ +public class I18nBundle implements Iterable<I18nBundleEntry>{ + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static final Log log = LogFactory.getLog(I18nBundle.class); + + /** les entrés du bundle */ + protected List<I18nBundleEntry> entries; + + /** le nom du bundle encapsulé (correspond au prefix de l'url de chargement) */ + final String bundlePrefix; + + public I18nBundle(String bundlePrefix) { + this.bundlePrefix = bundlePrefix; + } + + public String getBundlePrefix() { + return bundlePrefix; + } + + /** + * Obtain the entries for a given locale, with a inclusive scope search. + * <p/> + * The order of result respect {@link I18nBundleEntry} order. + * + * @param locale the required locale + * @return the array of entries matching extacly the locale or one of the lesser scope one. + */ + public I18nBundleEntry[] getEntries(Locale locale) { + I18nBundleScope scope = I18nBundleScope.valueOf(locale); + + List<I18nBundleEntry> result = new ArrayList<I18nBundleEntry>(); + for (I18nBundleEntry entry : entries) { + I18nBundleScope i18nBundleScope = entry.getScope(); + // load from general to the max scope and always if there is only one bundle entry found + if ((i18nBundleScope == scope || i18nBundleScope.ordinal() < scope.ordinal()) && entry.matchLocale(locale, scope)) { + result.add(entry); + } + } + return result.toArray(new I18nBundleEntry[result.size()]); + } + + /** + * Obtain the entries for a given <code>scope</code> <ith no incluvie logic. + * <p/> + * The order of result respect {@link I18nBundleEntry} order. + * + * @param scope the required scope + * @return the list of entries matching exactly the given scope + */ + public I18nBundleEntry[] getEntries(I18nBundleScope scope) { + List<I18nBundleEntry> result = new ArrayList<I18nBundleEntry>(); + for (I18nBundleEntry entry : entries) { + I18nBundleScope i18nBundleScope = entry.getScope(); + // load from general to the max scope and always if there is only one bundle entry found + if (i18nBundleScope == scope) { + result.add(entry); + } + } + return result.toArray(new I18nBundleEntry[result.size()]); + } + + /** @return number of entries in bundle */ + public int size() { + return entries == null ? 0 : entries.size(); + } + + @Override + public String toString() { + String s = super.toString(); + return "<" + s.substring(s.lastIndexOf(".") + 1) + ", bundlePrefix:" + bundlePrefix + ", size:" + size() + ">"; + } + + protected List<I18nBundleEntry> getEntries() { + return entries; + } + + protected boolean matchLocale(Locale locale) { + I18nBundleScope scope = I18nBundleScope.valueOf(locale); + boolean result = false; + if (size() != 0) { + for (I18nBundleEntry entry : entries) { + if (entry.matchLocale(locale, scope)) { + result = true; + break; + } + } + } + return result; + } + + public boolean addEntry(I18nBundleEntry entry) { + if (entries == null) { + entries = new ArrayList<I18nBundleEntry>(); + } + boolean b = entries.add(entry); + if (log.isDebugEnabled()) { + log.info(this + "\n\t" + entry); + } + return b; + } + + @Override + public Iterator<I18nBundleEntry> iterator() { + return entries.iterator(); + } + + +} diff --git a/nuiton-i18n-api/src/main/java/org/nuiton/i18n/bundle/I18nBundleEntry.java b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/bundle/I18nBundleEntry.java new file mode 100644 index 0000000..744b2eb --- /dev/null +++ b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/bundle/I18nBundleEntry.java @@ -0,0 +1,192 @@ +/* + * *##% Lutin utilities library + * Copyright (C) 2004 - 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package org.nuiton.i18n.bundle; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Locale; +import java.util.Map.Entry; +import java.util.Properties; +import org.nuiton.i18n.I18nUtil; +import org.nuiton.i18n.I18nFileReader; + +/** + * A class to represent an entry in a bundle. + * <p/> + * The object matches exactly one resource file in a given scope. + * <p/> + * The object has three properties : + * <ul> + * <li> {@link #path} : the path to resource file where to find transaltion for the entry. + * <li> {@link #locale} : the locale of the entry + * <li> {link #scope} ; the scope of the entry + * </ul> + * This object defines a equals order base on property {@link #path}. + * <p/> + * This object is {@link Comparable}, the order relation is defined like this : + * <ul> + * <li> sort first on {@link #scope}, in the scope order (see {@link I18nBundleScope}), + * <li> if scopes are equals, sort on {@link #locale} string representation. + * </ul> + * + * @author chemit + * @see I18nBundleScope + */ +public class I18nBundleEntry implements Comparable<I18nBundleEntry> { + + /** path to resource file */ + protected URL path; + /** local of the entry, can be null if general scope */ + protected Locale locale; + /** scope of the entry */ + protected I18nBundleScope scope; + + /** + * Constructor if an bundle entry. + * <p/> + * It is defined by a <code>path</code> of the resource file, a scope and a locale. + * + * @param path the path of the resource file fo the bundle entry + * @param locale the given locale of the bundle entry + * @param scope the scope of the given entry + */ + public I18nBundleEntry(URL path, Locale locale, I18nBundleScope scope) { + this.path = path; + this.locale = locale; + this.scope = scope; + } + + public URL getPath() { + return path; + } + + public Locale getLocale() { + return locale; + } + + public I18nBundleScope getScope() { + return scope; + } + + /** + * Method to match or not a bundle entry for a given scope and locale. + * <p/> + * We use the inclusive property of scope, means that we accept all entries on the path + * to the generalest entry for a givne locale. + * + * @param locale the locale to match + * @param scope the highest scope to match + * @return <code>true</code> if the entry match the scope and locale + * * + */ + public boolean matchLocale(Locale locale, I18nBundleScope scope) { + if (this.locale == null) { + // a general bundle entry is always matched! + return true; + } + if (locale == null) { + // can not match a specialized entry with a general scope + return false; + } + // match full locale, or at least a language + return this.locale.equals(locale) || + (this.scope.ordinal() < scope.ordinal() && locale.getLanguage().equals(this.locale.getLanguage())); + } + + /** + * For a given language, load the resource file of this entry into the <code>resource</code> + * properties object. + * + * @param resource the save of resources already loaded + * @throws IOException if any pb while reading resource file + */ + public void load(Properties resource) throws IOException { + InputStream inputStream = null; + StringBuilder sb = new StringBuilder(); + try { + I18nFileReader fileReader = new I18nFileReader(); + inputStream = getPath().openStream(); + //String encoding = language.getEncoding(); + if (I18nBundle.log.isDebugEnabled()) { + sb.append(getPath()).append("\n"); + } + // TC 20081117 always use ISO_8859_1_ENCONDING, since java does it like this. + fileReader.load(inputStream, I18nUtil.ISO_8859_1_ENCONDING); + + if (I18nBundle.log.isDebugEnabled()) { + for (Entry<Object, Object> entry : fileReader.entrySet()) { + sb.append(I18nUtil.ISO_8859_1_ENCONDING).append(" : ").append(entry).append("\n"); + } + } + for (Entry<Object, Object> entry : fileReader.entrySet()) { + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + if (value.trim().isEmpty()) { + // if there is a previous sentence loaded but not empty + // do not override it + String oldValue = (String) resource.get(key); + if (oldValue != null) { + continue; + } + } + resource.put(key, value); + } + //resource.putAll(fileReader); + if (I18nBundle.log.isDebugEnabled()) { + sb.append("nbSentences : ").append(fileReader.size()).append("\n"); + sb.append("====================================="); + } + fileReader.clear(); + + } finally { + if (I18nBundle.log.isDebugEnabled()) { + I18nBundle.log.debug(sb.toString()); + } + if (inputStream != null) { + inputStream.close(); + } + } + } + + @Override + public int compareTo(I18nBundleEntry o) { + int i = getScope().compareTo(o.getScope()); + if (i == 0) { + // same scope, sort on locale + i = getLocale().toString().compareTo(o.getLocale().toString()); + } + return i; + } + + @Override + public boolean equals(Object o) { + return this == o || o instanceof I18nBundleEntry && path.equals(((I18nBundleEntry) o).path); + } + + @Override + public int hashCode() { + return path.hashCode(); + } + + @Override + public String toString() { + String s = super.toString(); + return "<" + s.substring(s.lastIndexOf(".") + 1) + ", locale:" + locale + ", scope " + scope + ", path:" + path + ">"; + } +} diff --git a/nuiton-i18n-api/src/main/java/org/nuiton/i18n/bundle/I18nBundleFactory.java b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/bundle/I18nBundleFactory.java new file mode 100644 index 0000000..5cab696 --- /dev/null +++ b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/bundle/I18nBundleFactory.java @@ -0,0 +1,613 @@ +package org.nuiton.i18n.bundle; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Properties; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.i18n.I18nUtil; + +/** + * Classe qui est responsable de la detection et construction + * de {@link I18nBundle}. + * + * On retrouve aussi ici des méthodes utiles de parcours de bundles. + * + * @author chemit + * + * @since 1.0.6 + */ +public class I18nBundleFactory { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static final Log log = LogFactory.getLog(I18nBundleFactory.class); + /** pattern to find all i18n bundles in classloader class path */ + public static final String SEARCH_BUNDLE_PATTERN = ".*i18n/.+\\.properties"; + public static final String DIRECTORY_SEARCH_BUNDLE_PATTERN = "i18n"; + protected static String UNIQUE_BUNDLE_PATH = "/META-INF/"; + public static String UNIQUE_BUNDLE_DEF = "%1$s-definition.properties"; + public static String UNIQUE_BUNDLE_ENTRY = "%1$s-%2$s.properties"; + public static String BUNDLE_DEF_LOCALES = "locales"; + public static String BUNDLES_FOR_LOCALE = "bundles."; + + /** + * Récuperation de toutes les locales connus par un ensemble de bundles. + * + * @param bundles les bundles a parcourir + * @return la liste des locales rencontrées + */ + public static Locale[] getLocales(I18nBundle... bundles) { + Set<Locale> result = new java.util.HashSet<Locale>(); + for (I18nBundle i18nBundle : bundles) { + for (I18nBundleEntry entry : i18nBundle.getEntries()) { + Locale o = entry.getLocale(); + if (o != null) { + result.add(o); + } + } + } + return result.toArray(new Locale[result.size()]); + } + + /** + * Récuperation des noms de bundle par un ensemble de bundles. + * + * @param bundles les bundles a parcourir + * @return la liste des noms de bundle rencontrées + */ + public static String[] getBundleNames(I18nBundle... bundles) { + List<String> result = new ArrayList<String>(); + for (I18nBundle i18nBundle : bundles) { + result.add(i18nBundle.getBundlePrefix()); + } + return result.toArray(new String[result.size()]); + } + + /** + * Filtrage des bundles qui correspondante à la locale donnée. + * + * @param l la locale à filtrer + * @param bundles les bundles a parcourir + * @return les bundles qui correspondent à la locale donnée. + */ + public static I18nBundle[] getBundles(Locale l, I18nBundle... bundles) { + List<I18nBundle> result = new ArrayList<I18nBundle>(); + for (I18nBundle i18nBundle : bundles) { + if (i18nBundle.matchLocale(l)) { + result.add(i18nBundle); + } + } + return result.toArray(new I18nBundle[result.size()]); + } + + /** + * Récupération de toutes les entrées de bundles pour les bundles données. + * + * @param bundles les bundles a parcourir + * @return toutes les entrées de bundles. + */ + public static I18nBundleEntry[] getBundleEntries(I18nBundle... bundles) { + List<I18nBundleEntry> result = new ArrayList<I18nBundleEntry>(); + for (I18nBundle i18nBundle : bundles) { + List<I18nBundleEntry> list = i18nBundle.getEntries(); + if (!list.isEmpty()) { + result.addAll(list); + } + } + return result.toArray(new I18nBundleEntry[result.size()]); + } + + /** + * Filtrage des entrées de bundles pour une locale donnée. + * + * On essaye de trouver les meilleurs entrées possibles (possibilité de + * promotion). + * + * Note: Cette méthode doit être utilisé pour trouver toutes les entrées à + * charger par le système i18n pour une locale donnée. + * + * Note: Par defaut, on n'effectue pas les promotions générales + * ({@link #getBundleEntries(Locale, Locale, boolean, I18nBundle[])} + * + * @param l la locale à filtrer + * @param defaultLocale la locale à utiliser pour les promotions + * @param bundles les bundles a parcourir + * @return les entrées de bundles filtrés. + */ + public static I18nBundleEntry[] getBundleEntries(Locale l, Locale defaultLocale, I18nBundle... bundles) { + return getBundleEntries(l, defaultLocale, false, bundles); + } + + /** + * Filtrage des entrées de bundles pour une locale donnée. + * + * On essaye de trouver les meilleurs entrées possibles (possibilité de + * promotion). + * + * Note: Cette méthode doit être utilisé pour trouver toutes les entrées à + * charger par le système i18n pour une locale donnée. + * + * @param l la locale à filtrer + * @param defaultLocale la locale à utiliser pour les promotions + * @param promuteGeneral un drapeau pour indiquer si l'on autorise le + * chargement de la locale par defaut si pour un bundle donne on a + * pas trouve de traductions pour la locale donnee. + * @param bundles les bundles a parcourir + * @return les entrées de bundles filtrés. + */ + public static I18nBundleEntry[] getBundleEntries(Locale l, Locale defaultLocale, boolean promuteGeneral, I18nBundle... bundles) { + + List<I18nBundleEntry> result = new ArrayList<I18nBundleEntry>(); + for (I18nBundle i18nBundle : bundles) { + I18nBundleEntry[] entries = i18nBundle.getEntries(l); + if (entries.length == 0) { + //no entry found for the bundle, try pomotion + entries = promuteBundle(i18nBundle, l, defaultLocale, promuteGeneral); + } + result.addAll(Arrays.asList(entries)); + } + return result.toArray(new I18nBundleEntry[result.size()]); + } + + /** + * Teste si un ensemble de bundles contient au moins une entrée. + * + * @param bundles les bundles a parcourir + * @return <code>true</code> si aucune entree trouvee, <code>false</code> + * autrement. + */ + public static boolean isEmpty(I18nBundle... bundles) { + for (I18nBundle i18nBundle : bundles) { + if (!i18nBundle.getEntries().isEmpty()) { + // on a trouve au moins une entree + return false; + } + } + return true; + } + + /** + * Recherche la liste des url de toutes les resources i18n, i.e les urls + * des fichiers de traduction en mode uniqueBundleName. + * + * On va d'abord rechercher un fichier /META-INF/unqiueBundleName-definition.properties + * + * Dans ce fichier il y a une entree locales qui contient les locales du bundle + * + * Ensuite pour chaque locale on recupere l'url du fichier : + * + * /META-INF/uniqueBundleName-locale.properties + * + * Exemple : + * + * <code> + * fichier de définition : /META-INF/monAppli-definition.properties + * locales=fr_fr,es_ES + * + * fichiers de traduction + * /META-INF/monAppli-fr_FR.properties + * /META-INF/monAppli-es_ES.properties + * + * </code> + * + * @param uniqueBundleName le nom de l'unique bundle a charger + * @return la liste des urls de bundle i18n + */ + public static URL[] getURLs(String uniqueBundleName) { + + String definitionFileName = String.format(UNIQUE_BUNDLE_DEF, uniqueBundleName); + URL[] urls = null; + + try { + URL defURL = I18nBundleFactory.class.getResource(UNIQUE_BUNDLE_PATH + definitionFileName); + Properties p = loadUniqueNameDefFile(uniqueBundleName); + + String localesAsStr = p.getProperty(BUNDLE_DEF_LOCALES); + Locale[] locales = I18nUtil.parseLocales(localesAsStr); + List<URL> lUrls = new java.util.ArrayList<URL>(1); + String prefixURL = defURL.toString(); + prefixURL = prefixURL.substring(0, prefixURL.length() - definitionFileName.length()); + //FIXME on devrait tester que la resource est disponible ? + + for (Locale l : locales) { + String url = prefixURL + String.format(UNIQUE_BUNDLE_ENTRY, uniqueBundleName, l.toString()); + log.info("detected bundle properties file : " + url); + URL u = new URL(url); +// //FIXME on devrait tester que la resource est disponible ? + + lUrls.add(u); + } + if (!lUrls.isEmpty()) { + urls = lUrls.toArray(new URL[lUrls.size()]); + } else { + // l'unique bundle n'a pas ete trouve! + // on utilise la methode classique de chargement avec recherche + // de tous les bundles i18n + log.warn("not bundle files detected in " + prefixURL); + urls = null; + } + + } catch (Exception ex) { + log.warn("could not load unique bundle " + uniqueBundleName + " for reason " + ex.getMessage(), ex); + urls = null; + + } + return urls; + } + + public static Properties loadUniqueNameDefFile(String uniqueBundleName) { + String definitionFileName = String.format(UNIQUE_BUNDLE_DEF, uniqueBundleName); + Properties p = new Properties(); + try { + URL defURL = I18nBundleFactory.class.getResource(UNIQUE_BUNDLE_PATH + definitionFileName); + log.info("definition i18n file : " + defURL); + InputStream stream = defURL.openStream(); + p.load(stream); + stream.close(); + } catch (Exception ex) { + log.warn("could not load unique bundle " + uniqueBundleName + " for reason " + ex.getMessage(), ex); + } + return p; + } + + /** + * Recherche la liste des url de toutes les resources i18n, i.e les urls + * des fichiers de traduction. + * + * @param urls des urls de resources i18n deja calcule, à ajouter au resultat sans traitement particulier + * @return la liste des urls de bundle i18n + */ + public static URL[] getURLs(URL... urls) { + + try { + // on calcule toutes les urls utilisable dans le classloader donnee + List<URL> urlToSeek = new ArrayList<URL>(); + urlToSeek.addAll(Arrays.asList(urls)); + + // on va maintenant supprimer toutes les urls qui ne respectent pas + // le pattern i18n : il faut que la resource contienne un repertoire i18n + // ce simple test permet de restreindre la recherche des resources + // i18n qui est tres couteuse + int size = urlToSeek.size(); + for (Iterator<URL> it = urlToSeek.iterator(); it.hasNext();) { + URL url = it.next(); + if (!I18nUtil.containsDirectDirectory(url, DIRECTORY_SEARCH_BUNDLE_PATTERN)) { + if (log.isDebugEnabled()) { + log.debug("skip url with no " + DIRECTORY_SEARCH_BUNDLE_PATTERN + " directory : " + url); + } + it.remove(); + } + } + + if (log.isDebugEnabled()) { + log.debug("detect " + urlToSeek.size() + " i18n capable url (out of " + size + ")"); + } + + List<URL> listURLs = new java.util.ArrayList<URL>(); + + for (URL url : urlToSeek) { + // on recherche tous les fichiers de traduction pour cet url + + List<URL> result = null; + + if (log.isDebugEnabled()) { + log.debug("seek in : " + url); + } + + String fileName = url.getFile(); + // TODO deal with encoding in windows, this is very durty, but it + // works... + File file = new File(fileName.replaceAll("%20", " ")); + + if (I18nUtil.isJar(fileName)) { + // cas ou le ichier du classLoader est un fichier jar + if (log.isDebugEnabled()) { + log.debug("jar to search " + file); + } + result = getURLsFromJar(url, file); + + } else if (file.isDirectory()) { + // cas ou le ichier du classLoader est un repertoire + if (log.isDebugEnabled()) { + log.debug("directory to search " + file); + } + // on traite le cas ou il peut y avoir des repertoire dans ce + // repertoire + result = getURLsFromDirectory(url, file); + } + if (result != null && !result.isEmpty()) { + listURLs.addAll(result); + } + + } + return listURLs.toArray(new URL[listURLs.size()]); + } catch (Exception eee) { + log.warn("Unable to find urls for urls : " + urls + " for reason " + eee.getMessage(), eee); + return new URL[0]; + } + } + + /** + * Detecte les bundles i18n a partir des urls des fichiers de traduction + * donnes. + * + * Tous les entrées de bundles sont triees dans l'ordre des scopes i18n. + * + * @param urls les urls des fichiers de traductions + * @return la liste des bundle i18n construits à partir des fichiers de + * traduction donnes. + */ + public static List<I18nBundle> detectBundles(URL... urls) { + + List<String> bundleNames = new ArrayList<String>(); + List<I18nBundle> bundles = new ArrayList<I18nBundle>(); + + for (URL url : urls) { + + if (addBundleEntry(url, I18nBundleScope.FULL, bundleNames, bundles)) { + // found a full bundle + continue; + } + if (addBundleEntry(url, I18nBundleScope.LANGUAGE, bundleNames, bundles)) { + // found a language bundle + continue; + } + // must be a general bundle with no locale defined + addBundleEntry(url, I18nBundleScope.GENERAL, bundleNames, bundles); + } + bundleNames.clear(); + + // once for all, sort entries from general to full + for (I18nBundle bundle : bundles) { + java.util.Collections.sort(bundle.getEntries()); + } + + return bundles; + } + + protected static boolean addBundleEntry(URL url, I18nBundleScope scope, List<String> bundleNames, List<I18nBundle> bundles) { + String path = url.toString(); + Matcher matcher = scope.getMatcher(path); + if (!matcher.matches()) { + // no match at this scope + return false; + } + // create a new bundle entry + I18nBundleEntry entry = new I18nBundleEntry(url, scope.getLocale(matcher), scope); + if (log.isDebugEnabled()) { + log.debug("bundle (" + bundles.size() + ") : " + entry); + } + // get the associated bundle + I18nBundle bundle = addBundle(scope.getBundlePrefix(matcher), bundleNames, bundles); + // add entry to bundle + bundle.addEntry(entry); + return true; + } + + protected static I18nBundle addBundle(String bundleName, List<String> bundleNames, List<I18nBundle> bundles) { + I18nBundle bundle; + int index = bundleNames.indexOf(bundleName); + if (index > -1) { + bundle = bundles.get(index); + } else { + bundle = new I18nBundle(bundleName); + if (log.isDebugEnabled()) { + log.debug("bundle (" + bundles.size() + ") : " + bundle); + } + bundles.add(bundle); + bundleNames.add(bundleName); + } + return bundle; + } + + /** + * Obtain some rescue entries for a given locale. + * <p/> + * Note: <b>Calling this method implies there is no entry matched by the common method + * {@link #getBundleEntries(Locale, Locale, I18nBundle[])} return a empty array. + * + * @param bundle the bundle to promute + * @param l the locale required + * @param defaultLocale the default locale to used for promotion + * @param promuteGeneral a flag to authorize promotion to default locale + * @return the table of entries promuted for the given locale + */ + protected static I18nBundleEntry[] promuteBundle(I18nBundle bundle, Locale l, Locale defaultLocale, boolean promuteGeneral) { + + I18nBundleScope scope = I18nBundleScope.valueOf(l); + + if (log.isDebugEnabled()) { + log.debug('[' + bundle.getBundlePrefix() + "] did not find matching entries for locale " + l + ". Try to detect best entries..."); + } + + if (bundle.size() == 0) { + // there is no entry to take... + log.warn("PROMUTE NO ENTRY FOUND"); + return new I18nBundleEntry[0]; + } + + if (bundle.size() == 1) { + // there is one entry take it,what ever... + I18nBundleEntry entry = bundle.getEntries().get(0); + log.warn("PROMUTE" + l + " to " + entry.getLocale() + " [" + bundle.getBundlePrefix() + ']'); + return new I18nBundleEntry[]{entry}; + } + + List<I18nBundleEntry> result = new ArrayList<I18nBundleEntry>(); + + switch (scope) { + case FULL: + promuteFull(bundle, l, defaultLocale, result, promuteGeneral); + break; + case LANGUAGE: + promuteLanguage(bundle, l, defaultLocale, result, promuteGeneral); + break; + case GENERAL: + if (promuteGeneral) { + promuteGeneral(bundle, l, defaultLocale, result); + } + break; + } + return result.toArray(new I18nBundleEntry[result.size()]); + } + + protected static void promuteFull(I18nBundle bundle, Locale locale, Locale defaultLocale, List<I18nBundleEntry> result, boolean promuteGeneral) { + if (bundle.size() == 0) { + return; + } + // try with a another FULL matching locale ? + for (I18nBundleEntry entry : bundle.getEntries()) { + I18nBundleScope i18nBundleScope = entry.getScope(); + // load from general to the max scope and always if there is only one bundle entry found + if (i18nBundleScope == I18nBundleScope.FULL && + !entry.getLocale().getCountry().equals(locale.getCountry()) && + entry.getLocale().getLanguage().equals(locale.getLanguage())) { + log.warn(locale + " to " + entry.getLocale() + " [" + bundle.getBundlePrefix() + ']'); + result.add(entry); + // we take the first one, this is a resuce!!! + break; + } + } + if (result.isEmpty()) { + // full promotion failed,trylanguage promotion + promuteLanguage(bundle, locale, defaultLocale, result, promuteGeneral); + } + + } + + protected static void promuteLanguage(I18nBundle bundle, Locale locale, Locale defaultLocale, List<I18nBundleEntry> result, boolean promuteGeneral) { + if (bundle.size() == 0) { + return; + } + for (I18nBundleEntry entry : bundle.getEntries()) { + I18nBundleScope i18nBundleScope = entry.getScope(); + // load from general to the max scope and always if there is only one bundle entry found + if (i18nBundleScope == I18nBundleScope.FULL && entry.getLocale().getLanguage().equals(locale.getLanguage())) { + result.add(entry); + log.warn(locale + " to " + entry.getLocale() + " [" + bundle.getBundlePrefix() + ']'); + // we take the first one, this is a resuce!!! + break; + } + } + if (result.isEmpty() && promuteGeneral) { + // language promotion failed,try general promotion + promuteGeneral(bundle, locale, defaultLocale, result); + } + } + + protected static void promuteGeneral(I18nBundle bundle, Locale locale, Locale defaultLocale, List<I18nBundleEntry> result) { + if (bundle.size() == 0) { + return; + } + if (bundle.size() == 1) { + // there is one entry take it,what ever... + I18nBundleEntry entry = bundle.getEntries().get(0); + result.add(entry); + log.warn(locale + " to " + entry.getLocale() + " [" + bundle.getBundlePrefix() + ']'); + return; + } + I18nBundleScope scope = I18nBundleScope.valueOf(defaultLocale); + for (I18nBundleEntry entry : bundle.getEntries(scope)) { + if (entry.getLocale().equals(defaultLocale)) { + // default locale found + log.warn(locale + " to " + entry.getLocale() + " [" + bundle.getBundlePrefix() + ']'); + result.add(entry); + return; + } + } + + // default locale not found, take the first one ? + I18nBundleEntry entry = bundle.getEntries().get(0); + result.add(entry); + log.warn(locale + " to " + entry.getLocale() + " [" + bundle.getBundlePrefix() + ']'); + //TODO Should try to load default en_GB from I18nLoader ? + //I18n.DEFAULT_LOCALE.getCountry() + } + + protected static List<URL> getURLsFromJar(URL incomingURL, File jarfile) { + + String pattern = SEARCH_BUNDLE_PATTERN; + try { + + List<URL> result = new ArrayList<URL>(); + InputStream in = new FileInputStream(jarfile); + ZipInputStream zis = new ZipInputStream(in); + ClassLoader cl = new URLClassLoader(new URL[]{incomingURL}, I18nBundleFactory.class.getClassLoader()); + while (zis.available() != 0) { + ZipEntry entry = zis.getNextEntry(); + + if (entry == null) { + break; + } + + String name = entry.getName(); + + if (pattern == null || name.matches(pattern)) { + // on recupere le fichier correspondant au pattern dans le + // classloader + if (log.isDebugEnabled()) { + log.debug(name + " accepted for pattern " + pattern); + } + URL url = cl.getResource(name); + // on ajoute le fichier correspondant au pattern dans la + // liste + result.add(url); + } + } + + return result; + } catch (Exception eee) { + throw new RuntimeException("n'a pas pu trouve la resource dans le jar " + jarfile.getAbsolutePath(), eee); + } + } + + protected static List<URL> getURLsFromDirectory(URL incomingURL, File repository) { + String pattern = SEARCH_BUNDLE_PATTERN; + try { + if (log.isDebugEnabled()) { + log.debug("search '" + pattern + "' in " + repository); + } + + List<URL> urlList = new ArrayList<URL>(); + File[] filesList = repository.listFiles(); + + if (filesList != null) { + + for (File file : filesList) { + + String name = file.getAbsolutePath(); + + // cas de recursivite : repertoire dans un repertoire + if (file.exists() && file.isDirectory()) { + urlList.addAll(I18nUtil.getURLsFromDirectory(file, + pattern)); + // si le fichier du repertoire n'est pas un repertoire + // on verifie s'il correspond au pattern + } else if (pattern == null || name.matches(pattern)) { + URL url = file.toURI().toURL(); + if (log.isDebugEnabled()) { + log.debug("directory: " + repository + " url: " + url); + } + urlList.add(url); + } + } + } + return urlList; + } catch (MalformedURLException eee) { + throw new RuntimeException("n'a pas pu trouve la resource dans le repertoire " + repository.getAbsolutePath(), eee); + } + } +} diff --git a/nuiton-i18n-api/src/main/java/org/nuiton/i18n/bundle/I18nBundleScope.java b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/bundle/I18nBundleScope.java new file mode 100644 index 0000000..924ec05 --- /dev/null +++ b/nuiton-i18n-api/src/main/java/org/nuiton/i18n/bundle/I18nBundleScope.java @@ -0,0 +1,144 @@ +/* +* *##% Lutin utilities library + * Copyright (C) 2004 - 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ +package org.nuiton.i18n.bundle; + +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.nuiton.i18n.I18nUtil; + +/** + * The enumaration defines the scope of a bundle entry. + * <p/> + * There is three scope possible: + * <ul> + * <li>{@link #GENERAL} : for a bundle entry with no locale specialized information, eg : <code>bundle.properties</code></li> + * <li>{@link #LANGUAGE} : for a bundle entry with language locale specialized information, eg : <code>bundle-en.properties</code></li> + * <li>{@link #FULL} : for a bundle entry with full locale specialized information, eg : <code>bundle-en_GB.properties</code></li> + * </ul> + * <p/> + * We define a order relation, from general to full scope : + * <p/> + * {@link #GENERAL} < {@link #LANGUAGE} < {@link #FULL} + * <p/> + * Scopes are inclusives, in a search of entries, eg the search of <code>en_GB</code> will include <code>en</code> scope... + * <p/> + * The {@link #patternAll} is the searching pattern of bundle of the scope. + * <p/> + * The method {@link #getMatcher(String)} obtain from the {@link #patternAll} the matcher for a bundle path. + * <p/> + * The method {@link #getLocale(Matcher)} obtain from the {@link #patternAll} matched in a bundle path, the + * corresponding locale. + * <p/> + * The class offer also a static method {@link #valueOf(java.util.Locale)} to obtain the scope of a locale. + * + * @author chemit + */ +public enum I18nBundleScope { + + /** default scope (with no language, nor country information) */ +// GENERAL("(.*18n/.+)\\.properties") { + GENERAL("(.*/.+)\\.properties") { + @Override + public Locale getLocale(Matcher matcher) { + // no locale for general bundle + return null; + } + }, + + /** language scope (no country information) */ +// LANGUAGE("(.*18n/.+)-(\\w\\w)\\.properties") { + LANGUAGE("(.*/.+)-(\\w\\w)\\.properties") { + @Override + public Locale getLocale(Matcher matcher) { + Locale result = null; + if (matcher.matches()) { + result = I18nUtil.newLocale(matcher.group(2)); + } + return result; + } + }, + + /** full scope : language + country */ +// FULL("(.*18n/.+)-(\\w\\w_\\w\\w)\\.properties") { + FULL("(.*/.+)-(\\w\\w_\\w\\w)\\.properties") { + @Override + public Locale getLocale(Matcher matcher) { + Locale result = null; + if (matcher.matches()) { + result = I18nUtil.newLocale(matcher.group(2)); + } + return result; + } + }; + + /** pattern used to detect bundle entry */ + private final Pattern patternAll; + + /** + * Obtain the scope of a given <code>locale</code>. + * <p/> + * The given locale can be null, which means {@link I18nBundleScope#GENERAL} scope. + * + * @param locale given locale to convert + * @return the scope of given locale + */ + public static I18nBundleScope valueOf(Locale locale) { + if (locale == null || locale.getLanguage() == null || locale.getLanguage().length() == 0) { + return GENERAL; + } + if (locale.getCountry() == null || locale.getCountry().length() == 0) { + return LANGUAGE; + } + return FULL; + } + + /** + * get a matcher fro the given path for this scope + * + * @param path the path to treate + * @return the bunle detect matcher + */ + public Matcher getMatcher(String path) { + return patternAll.matcher(path); + } + + /** + * get the locale for a given matcher. + * + * @param matcher the scope matcher to use + * @return the locale + */ + public abstract Locale getLocale(Matcher matcher); + + /** + * @param matcher the scope matcher to use + * @return the prefix of the bundle + */ + public String getBundlePrefix(Matcher matcher) { + String result = null; + if (matcher.matches()) { + result = matcher.group(1); + } + return result; + } + + private I18nBundleScope(String patternAll) { + this.patternAll = Pattern.compile(patternAll); + } +} diff --git a/nuiton-i18n-api/src/main/java/org/nuiton/util/LocaleConverter.java b/nuiton-i18n-api/src/main/java/org/nuiton/util/LocaleConverter.java new file mode 100644 index 0000000..2a2e2a8 --- /dev/null +++ b/nuiton-i18n-api/src/main/java/org/nuiton/util/LocaleConverter.java @@ -0,0 +1,126 @@ +/* + * *##% Lutin utilities library + * Copyright (C) 2004 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* */ + +package org.nuiton.util; + +import org.apache.commons.beanutils.ConversionException; +import org.apache.commons.beanutils.Converter; +import static org.apache.commons.logging.LogFactory.getLog; +import org.nuiton.i18n.CountryEnum; +import org.nuiton.i18n.LanguageEnum; + +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * classe pour convertir une chaine en un objet {@link java.util.Locale}. + * + * @author chemit + */ +public class LocaleConverter implements Converter { + + private static final Pattern FULL_SCOPE_PATTERN = Pattern.compile("([a-zA-Z]{2})_([a-zA-Z]{2})"); + + private static final Pattern MEDIUM_SCOPE_PATTERN = Pattern.compile("([a-zA-Z]{2})"); + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static org.apache.commons.logging.Log log = getLog(LocaleConverter.class); + + public Object convert(Class aClass, Object value) { + if (value == null) { + throw new ConversionException("can not convert null value in " + this + " convertor"); + } + if (isEnabled(aClass)) { + Object result; + if (isEnabled(value.getClass())) { + result = value; + return result; + } + if (value instanceof String) { + result = valueOf(((String) value).trim()); + return result; + } + } + throw new ConversionException("could not find a convertor for type " + aClass.getName() + " and value : " + value); + } + + protected Locale valueOf(String value) { + try { + Locale result = convertFullScope(value); + + if (result == null) { + result = convertMediumScope(value); + } + + if (result == null) { + throw new ConversionException("could not convert locale " + value); + } + + return result; + } catch (Exception e) { + throw new ConversionException("could not convert locale " + value + " for reason " + e.getMessage()); + } + } + + private Locale convertFullScope(String value) { + Matcher m = FULL_SCOPE_PATTERN.matcher(value); + if (m.matches()) { + // found a full scope pattern (language + country) + LanguageEnum language = LanguageEnum.valueOf(m.group(1).toLowerCase()); + CountryEnum country = CountryEnum.valueOf(m.group(2).toUpperCase()); + if (language == null || country == null) { + // not safe + throw new ConversionException("could not convert locale " + value); + } + return new Locale(language.name(), country.name()); + } + return null; + } + + private Locale convertMediumScope(String value) { + Matcher m = MEDIUM_SCOPE_PATTERN.matcher(value); + if (m.matches()) { + // found a medium scope pattern (only language) + LanguageEnum language = LanguageEnum.valueOf(m.group(1).toLowerCase()); + + if (language == null) { + // not safe + throw new ConversionException("could not convert locale " + value); + } + return new Locale(language.name()); + } + return null; + } + + + public LocaleConverter() { + if (log.isDebugEnabled()) { + log.debug(this); + } + } + + protected boolean isEnabled(Class aClass) { + return aClass == Locale.class; + } + + public Class<?> getType() { + return Locale.class; + } + +} diff --git a/nuiton-i18n-api/src/main/resources/META-INF/services/org.apache.commons.beanutils.Converter b/nuiton-i18n-api/src/main/resources/META-INF/services/org.apache.commons.beanutils.Converter new file mode 100644 index 0000000..890b48c --- /dev/null +++ b/nuiton-i18n-api/src/main/resources/META-INF/services/org.apache.commons.beanutils.Converter @@ -0,0 +1 @@ +org.nuiton.util.LocaleConverter \ No newline at end of file diff --git a/nuiton-i18n-api/src/site/apt/index.apt b/nuiton-i18n-api/src/site/apt/index.apt new file mode 100644 index 0000000..31b94eb --- /dev/null +++ b/nuiton-i18n-api/src/site/apt/index.apt @@ -0,0 +1,20 @@ +---- +Nuiton-i18n-api +---- +---- +2009-08-22 +---- + +Présentation + + Librairie permettant de rendre les programmes Java multilangue de façon + simple. Il utilise la même philosophie que gettext. C'est à dire que chaque + chaîne de caractères devant être traduite sont tagge avec I18n._("..."). + + Ensuite il suffit d'extraire ces chaînes pour les mettres dans un fichier de + propriété, et d'indiquer quel fichier de propriéttés charger au démarrage de + l'application selon la langue souhaitée. + + + <Veuillez consulter la JavaDoc pour de plus ample détails sur les différentes + librairies.> diff --git a/nuiton-i18n-api/src/site/site.xml b/nuiton-i18n-api/src/site/site.xml new file mode 100644 index 0000000..1e0b6e0 --- /dev/null +++ b/nuiton-i18n-api/src/site/site.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="${project.name}"> + + <bannerLeft> + <name>${project.name}</name> + <href>index.html</href> + </bannerLeft> + + <body> + + <breadcrumbs> + <item name="${project.name}" href="${project.url}" /> + </breadcrumbs> + + <menu ref="parent"/> + + <menu name="Utilisateur"> + <item name="Accueil" href="index.html"/> + </menu> + + <menu name="Téléchargement"> + <item href="${repository.home.url}/org/nuiton/i18n/${project.artifactId}/${project.version}/${project.build.finalName}.jar" + name="Librairie (jar)"/> + <item href="${repository.home.url}/org/nuiton/i18n/${project.artifactId}/${project.version}/${project.build.finalName}-javadoc.jar" + name="Javadoc (jar)"/> + <item href="${repository.home.url}/org/nuiton/i18n/${project.artifactId}/${project.version}/${project.build.finalName}-sources.jar" + name="Sources (jar)"/> + </menu> + + <menu ref="reports"/> + + </body> +</project> diff --git a/nuiton-i18n-api/src/test/java/org/nuiton/i18n/bundle/I18nBunsleScopeTest.java b/nuiton-i18n-api/src/test/java/org/nuiton/i18n/bundle/I18nBunsleScopeTest.java new file mode 100644 index 0000000..0d340ae --- /dev/null +++ b/nuiton-i18n-api/src/test/java/org/nuiton/i18n/bundle/I18nBunsleScopeTest.java @@ -0,0 +1,63 @@ +/** + * *##% Lutin utilities library + * Copyright (C) 2004 - 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.bundle; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Locale; + +/** @author chemit */ +public class I18nBunsleScopeTest { + + Locale locale; + I18nBundleScope excepted; + + @Test + public void testFullScope() { + excepted = I18nBundleScope.FULL; + + locale = new Locale("fr", "FR"); + Assert.assertEquals(excepted, I18nBundleScope.valueOf(locale)); + } + + @Test + public void testLanguageScope() { + excepted = I18nBundleScope.LANGUAGE; + + locale = new Locale("fr"); + Assert.assertEquals(excepted, I18nBundleScope.valueOf(locale)); + + locale = new Locale("fr", ""); + Assert.assertEquals(excepted, I18nBundleScope.valueOf(locale)); + } + + @Test + public void testGeneralScope() { + + excepted = I18nBundleScope.GENERAL; + + locale = null; + Assert.assertEquals(excepted, I18nBundleScope.valueOf(locale)); + + locale = new Locale(""); + Assert.assertEquals(excepted, I18nBundleScope.valueOf(locale)); + } + +} diff --git a/nuiton-i18n-api/src/test/java/org/nuiton/util/LocaleConverterTest.java b/nuiton-i18n-api/src/test/java/org/nuiton/util/LocaleConverterTest.java new file mode 100644 index 0000000..0f37b53 --- /dev/null +++ b/nuiton-i18n-api/src/test/java/org/nuiton/util/LocaleConverterTest.java @@ -0,0 +1,124 @@ +/** + * *##% Lutin utilities library + * Copyright (C) 2004 - 2008 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. ##%* + */ +package org.nuiton.util; + +import junit.framework.TestCase; +import org.apache.commons.beanutils.Converter; + +import java.util.Locale; + +/** @author chemit */ +public class LocaleConverterTest extends TestCase { + + String toConvert; + Locale excepted; + Converter converter; + + @Override + protected void setUp() throws Exception { + super.setUp(); + converter = new LocaleConverter(); + } + + public void testConvertFull() throws Exception { + toConvert = "fr_FR"; + excepted = Locale.FRANCE; + assertEquals(toConvert, excepted); + + toConvert = "fr_fr"; + assertEquals(toConvert, excepted); + + toConvert = "FR_fr"; + assertEquals(toConvert, excepted); + + toConvert = "FR_FR"; + assertEquals(toConvert, excepted); + + toConvert = "\n\tFr_fR "; + assertEquals(toConvert, excepted); + + toConvert = "en_GB"; + excepted = Locale.UK; + assertEquals(toConvert, excepted); + + toConvert = "en_US"; + excepted = Locale.US; + assertEquals(toConvert, excepted); + + //TODO Arch, we must also check coherence ! + toConvert = "fr_GB"; + excepted = new Locale("fr","GB"); + assertEquals(toConvert, excepted); + } + + public void testConvertMedium() throws Exception { + toConvert = "fr"; + excepted = new Locale("fr"); + assertEquals(toConvert, excepted); + + toConvert = "fR"; + assertEquals(toConvert, excepted); + + toConvert = "FR"; + assertEquals(toConvert, excepted); + + toConvert = " fR \t"; + assertEquals(toConvert, excepted); + + toConvert = "en"; + excepted = new Locale("en"); + assertEquals(toConvert, excepted); + + toConvert = "es"; + excepted = new Locale("es"); + assertEquals(toConvert, excepted); + + } + + public void testConvertFailed() throws Exception { + + toConvert = null; + assertConvertFailed(toConvert); + + toConvert = ""; + assertConvertFailed(toConvert); + + toConvert = "fr_"; + assertConvertFailed(toConvert); + + toConvert = "_FR"; + assertConvertFailed(toConvert); + + } + + protected void assertEquals(String toConvert, Locale expected) { + Object result = converter.convert(Locale.class, toConvert); + assertEquals(expected, result); + } + + protected void assertConvertFailed(String toConvert) { + try { + converter.convert(Locale.class, toConvert); + fail(); + } catch (Exception e) { + assertTrue(true); + } + + } +} diff --git a/nuiton-i18n-api/src/test/resources/log4j.properties b/nuiton-i18n-api/src/test/resources/log4j.properties new file mode 100644 index 0000000..e2b28c4 --- /dev/null +++ b/nuiton-i18n-api/src/test/resources/log4j.properties @@ -0,0 +1,11 @@ +# Global logging configuration +log4j.rootLogger=ERROR, stdout +# Console output... +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) %M - %m%n +#log4j.appender.stdout.layout.ConversionPattern=%%c=%c %%C=%C %%d=%d %%F=%F %%l=%l %%L=%L %%m=%m %%M=%M %%p=%p %%r=%r %%t=%t %%x=%x %%X=%X +# package level +log4j.logger.org.codelutin.i18n=INFO +log4j.logger.org.codelutin.util=INFO +log4j.logger.org.codelutin.option=INFO diff --git a/nuiton-i18n-editor/LICENSE.txt b/nuiton-i18n-editor/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/nuiton-i18n-editor/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/nuiton-i18n-editor/README.txt b/nuiton-i18n-editor/README.txt new file mode 100644 index 0000000..d2e50d3 --- /dev/null +++ b/nuiton-i18n-editor/README.txt @@ -0,0 +1,2 @@ +To deploy new version of pom: mvn deploy +To install localy: mvn install diff --git a/nuiton-i18n-editor/changelog.txt b/nuiton-i18n-editor/changelog.txt new file mode 100644 index 0000000..f0a3600 --- /dev/null +++ b/nuiton-i18n-editor/changelog.txt @@ -0,0 +1,8 @@ +0.3 ?? 2008???? + * 20090205 [chemit] use lutinproject 3.4, improve jnlp making + * 20081205 [chemit] use lutinproject 3.2, make minimal site + * 20081118 [chemit] use lutinproject 3.1, produce javadoc + * 20081117 [chemit] bump jaxx to 0.6 + * use src/main/java to store jaxx, no more use of uimodel directory + * Update groupId to org.codelutin + * Use org.codelutin:lutinproject:3.0 super-pom \ No newline at end of file diff --git a/nuiton-i18n-editor/pom.xml b/nuiton-i18n-editor/pom.xml new file mode 100644 index 0000000..a8fd2a8 --- /dev/null +++ b/nuiton-i18n-editor/pom.xml @@ -0,0 +1,384 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + <parent> + <groupId>org.nuiton</groupId> + <artifactId>i18n</artifactId> + <version>1.0.0-rc-5-SNAPSHOT</version> + </parent> + + <groupId>org.nuiton.i18n</groupId> + <artifactId>nuiton-i18n-editor</artifactId> + + <dependencies> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>nuiton-i18n-api</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>nuiton-utils</artifactId> + <version>${lutinutil.version}</version> + </dependency> + + <!--Jaxx--> + <dependency> + <groupId>org.nuiton.jaxx</groupId> + <artifactId>jaxx-runtime-swing</artifactId> + <version>${jaxx.version}</version> + </dependency> + + <dependency> + <groupId>org.nuiton.jaxx</groupId> + <artifactId>jaxx-runtime-swing-widget</artifactId> + <version>${jaxx.version}</version> + </dependency> + + </dependencies> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + + <name>Nuiton I18n Editor</name> + + <description>Editeur de fichier i18n</description> + <inceptionYear>2008</inceptionYear> + + <licenses> + <license> + <name>GPL</name> + <url>http://www.gnu.org/licenses/gpl.txt</url> + <distribution>repo</distribution> + </license> + </licenses> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + <packaging>jar</packaging> + + <properties> + + <!-- main class in jar --> + <maven.jar.main.class>org.nuiton.i18n.editor.I18nEditor</maven.jar.main.class> + + <jaxx.version>1.7.1-SNAPSHOT</jaxx.version> + <lutinutil.version>1.1.0-rc-9-SNAPSHOT</lutinutil.version> + + <!-- default license to use --> + <license.licenseName>gpl_v3</license.licenseName> + + <!-- jnlp --> + <!--keystorepath>${codelutin.keystorepath}</keystorepath> + <keystorealias>CodeLutin</keystorealias> + <keystorepass>codelutin</keystorepass> + <jnlp.build.directory>${project.build.directory}/jnlp</jnlp.build.directory> + <jnlpCodebase>${project.url}</jnlpCodebase--> + <!-- to test jnlp file locally --> + <!--jnlpCodebase>file://${jnlp.build.directory}</jnlpCodebase--> + + <!-- jaxx --> + <jaxx.useUIManagerForIcon>true</jaxx.useUIManagerForIcon> + <jaxx.addProjectClassPath>true</jaxx.addProjectClassPath> + <jaxx.addSourcesToClassPath>true</jaxx.addSourcesToClassPath> + </properties> + + <build> + + <resources> + <resource> + <directory>src/main/filters</directory> + <filtering>true</filtering> + <includes> + <include>nuiton-i18n-editor.properties</include> + </includes> + </resource> + <resource> + <directory>src/main/resources</directory> + <includes> + <include>**/*</include> + </includes> + </resource> + <!--resource> + <directory>${jaxx.helpTarget}</directory> + <includes> + <include>**/*</include> + </includes> + </resource--> + </resources> + + <plugins> + + <plugin> + <groupId>org.nuiton.jaxx</groupId> + <artifactId>maven-jaxx-plugin</artifactId> + <version>${jaxx.version}</version> + <executions> + <execution> + <goals> + <goal>generate</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>org.nuiton</groupId> + <artifactId>maven-helper-plugin</artifactId> + <configuration> + <copyToMETA_INF>true</copyToMETA_INF> + </configuration> + <executions> + <execution> + <id>attach-licenses</id> + <goals> + <goal>add-license</goal> + <goal>add-third-party</goal> + </goals> + </execution> + </executions> + </plugin> + + <!-- plugin i18n --> + <plugin> + <groupId>${project.groupId}</groupId> + <artifactId>maven-i18n-plugin</artifactId> + <version>${project.version}</version> + <configuration> + <silent>true</silent> + <entries> + <entry> + <basedir>${maven.gen.dir}/java/</basedir> + </entry> + </entries> + </configuration> + <executions> + <execution> + <goals> + <goal>parserJava</goal> + <goal>bundle</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <configuration> + <silent>true</silent> + </configuration> + <executions> + <execution> + <id>copy-dependencies</id> + </execution> + </executions> + + </plugin> + + </plugins> + + <pluginManagement> + <plugins> + <plugin> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <archive> + <manifest> + <addClasspath>true</addClasspath> + <classpathPrefix>./lib/</classpathPrefix> + </manifest> + </archive> + </configuration> + </plugin> + + <!-- plugin site --> + <plugin> + <artifactId>maven-site-plugin</artifactId> + <version>2.0.1</version> + <dependencies> + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>doxia-module-jrst</artifactId> + <version>1.0.2-rc-1</version> + </dependency> + </dependencies> + </plugin> + + </plugins> + </pluginManagement> + </build> + + <!-- ************************************************************* --> + <!-- *** Build Environment ************************************** --> + <!-- ************************************************************* --> + + <profiles> + <profile> + <id>release-profile</id> + <activation> + <property> + <name>performRelease</name> + <value>true</value> + </property> + </activation> + <build> + <plugins> + <!-- Ajout des libs signe par Sun dans un fichier jnlp separe --> + <!--plugin> + + <artifactId>maven-antrun-plugin</artifactId> + <executions> + <-execution> + <id>JnlpSun</id> + <phase>verify</phase> + <configuration> + <tasks> + <mkdir dir="${jnlp.build.directory}"/> + <copy file="${project.basedir}/src/main/jnlp/sun.jnlp" + verbose="${maven.verbose}" + todir="${jnlp.build.directory}" failonerror="false"> + <filterset> + <filter token="lib" value="javahelp-2.0.02.jar"/> + <filter token="url" value="${jnlpCodebase}"/> + </filterset> + </copy> + <copy file="${project.basedir}/src/main/jnlp/jxlayer.jnlp" + verbose="${maven.verbose}" + todir="${jnlp.build.directory}" failonerror="false"> + <filterset> + <filter token="lib" value="jxlayer-3.0.1.jar"/> + <filter token="url" value="${jnlpCodebase}"/> + </filterset> + </copy> + <copy file="${project.build.directory}/lib/javahelp-2.0.02.jar" + verbose="${maven.verbose}" todir="${jnlp.build.directory}/lib" + failonerror="false"/> + <copy file="${project.build.directory}/lib/jxlayer-3.0.1.jar" + verbose="${maven.verbose}" + todir="${jnlp.build.directory}/lib" failonerror="false"/> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + + <execution> + <id>JnlpToSite</id> + <phase>pre-site</phase> + <configuration> + <tasks> + <mkdir dir="${maven.site.gen.dir}/resources"/> + <copy todir="${maven.site.gen.dir}/resources" verbose="true" + failonerror="false" overwrite="false"> + <fileset dir="${jnlp.build.directory}"> + <include name="**"/> + </fileset> + <fileset dir="target"> + <include name="${project.build.finalName}-bin.zip"/> + </fileset> + + </copy> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + </executions> + </plugin--> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <configuration> + <descriptors> + <descriptor>src/main/assembly/bin.xml</descriptor> + </descriptors> + </configuration> + <executions> + <execution> + <phase>verify</phase> + <goals> + <goal>attached</goal> + </goals> + </execution> + </executions> + </plugin> + + <!--plugin> + <groupId>org.nuiton.thirdparty</groupId> + <artifactId>webstart-maven-plugin</artifactId> + <version>1.0-alpha-2-cl_20090204</version> + <executions> + <execution> + <phase>verify</phase> + <goals> + <goal>jnlp-inline</goal> + </goals> + </execution> + </executions> + <configuration> + <force>false</force> + <dependencies> + <excludes> + <exclude>javax.help:javahelp</exclude> + <exclude>org.swinglabs:jxlayer</exclude> + </excludes> + </dependencies> + <libPath>lib</libPath> + <extensions> + <sun>sun.jnlp</sun> + <jxlayer>jxlayer.jnlp</jxlayer> + </extensions> + <jnlp> + <outputFile>launch-${project.artifactId}.jnlp</outputFile> + <mainClass>${maven.jar.main.class}</mainClass> + <allPermissions>true</allPermissions> + <offlineAllowed>true</offlineAllowed> + </jnlp> + + <sign> + <keystore>${keystorepath}</keystore> + <keypass/> + <storepass>${keystorepass}</storepass> + <storetype/> + <alias>${keystorealias}</alias> + <validity/> + <dnameCn/> + <dnameOu/> + <dnameO/> + <dnameL/> + <dnameSt/> + <dnameC/> + <verify>true</verify> + <keystoreConfig> + <delete>false</delete> + <gen>false</gen> + </keystoreConfig> + </sign> + + + <pack200>false</pack200> + <gzip>true</gzip> + <verbose>false</verbose> + </configuration> + </plugin--> + </plugins> + </build> + </profile> + </profiles> + +</project> diff --git a/nuiton-i18n-editor/src/main/assembly/bin.xml b/nuiton-i18n-editor/src/main/assembly/bin.xml new file mode 100644 index 0000000..a39b7f4 --- /dev/null +++ b/nuiton-i18n-editor/src/main/assembly/bin.xml @@ -0,0 +1,53 @@ +<assembly> + <id>bin</id> + <formats> + <format>zip</format> + </formats> + <includeBaseDirectory>false</includeBaseDirectory> + + <fileSets> + + <fileSet> + <directory>target/lib</directory> + <outputDirectory>lutini18nEditor/lib</outputDirectory> + <includes> + <include>*.jar</include> + </includes> + <excludes> + <exclude>junit-4.5.jar</exclude> + </excludes> + </fileSet> + + <fileSet> + <directory>target</directory> + <outputDirectory>lutini18nEditor</outputDirectory> + <includes> + <include>*.jar</include> + </includes> + <excludes> + <exclude>*-sources.jar</exclude> + <exclude>*-javadoc.jar</exclude> + </excludes> + </fileSet> + <fileSet> + <outputDirectory>lutini18nEditor</outputDirectory> + + <includes> + <include>README*</include> + <include>LICENSE*</include> + </includes> + </fileSet> + + <fileSet> + <directory>src/main/assembly</directory> + <filtered>true</filtered> + <outputDirectory>lutini18nEditor</outputDirectory> + <fileMode>0755</fileMode> + <includes> + <include>go.sh</include> + <include>go.bat</include> + </includes> + </fileSet> + + </fileSets> +</assembly> \ No newline at end of file diff --git a/nuiton-i18n-editor/src/main/assembly/go.bat b/nuiton-i18n-editor/src/main/assembly/go.bat new file mode 100644 index 0000000..cffa0cc --- /dev/null +++ b/nuiton-i18n-editor/src/main/assembly/go.bat @@ -0,0 +1 @@ +java -Xmx512M -Xms512M -jar ${project.build.finalName}.jar %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/nuiton-i18n-editor/src/main/assembly/go.sh b/nuiton-i18n-editor/src/main/assembly/go.sh new file mode 100644 index 0000000..5557dd2 --- /dev/null +++ b/nuiton-i18n-editor/src/main/assembly/go.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +MX=512M +java -Xmx$MX -Xms$MX -jar ${project.build.finalName}.jar "$@" \ No newline at end of file diff --git a/nuiton-i18n-editor/src/main/filters/nuiton-i18n-editor.properties b/nuiton-i18n-editor/src/main/filters/nuiton-i18n-editor.properties new file mode 100644 index 0000000..eb45262 --- /dev/null +++ b/nuiton-i18n-editor/src/main/filters/nuiton-i18n-editor.properties @@ -0,0 +1,78 @@ +application.name=${project.name} +application.version=${project.version} +application.site.url=${project.url} +application.organisation.name=${project.organization.name} +application.organisation.url=${project.organization.url} + + +# icones d'action (icon.action.nomAction=*.???) +icon.action.about=action-about.png +icon.action.accept=action-accept.png +icon.action.add=action-add.png +icon.action.cancel=action-cancel.png +icon.action.closeTab=action-closeTab.png +icon.action.config=action-config.png +icon.action.edit=action-edit.png +icon.action.open=action-open.png +icon.action.save=action-save.png +icon.action.close=action-close.png +icon.action.delete=action-delete.png +icon.action.exit=action-exit.png +icon.action.error=error.png +icon.action.fullscreen=action-fullscreen.png +icon.action.fileChooser=action-fileChooser.png +icon.action.go-back=action-go-back.png +icon.action.i18n-es=action-i18n-es.png +icon.action.i18n-fr=action-i18n-fr.png +icon.action.i18n-gb=action-i18n-gb.png +icon.action.collapseAll=action-collapseAll.png +icon.action.expandAll=action-expandAll.png + +icon.action.site=action-site.png + +icon.action.show-help=action-show-help.png +icon.action.help=action-help.png +icon.action.leave-fullscreen=action-leave-fullscreen.png + +icon.action.connected=action-connected.png +icon.action.connect_creating=action-connect_creating.png +icon.action.connect_untested=action-connect_untested.png +icon.action.connect_no=action-connect_no.png +icon.action.connect_ok=action-connect_ok.png +icon.action.db-change=action-db-change.png +icon.action.db-local=action-db-local.png +icon.action.db-none=action-db-none.png +icon.action.db-remote=action-db-remote.png +icon.action.go-detail=action-go-detail.png +icon.action.go-down=action-go-down.png +icon.action.go-jump=action-go-jump.png +icon.action.next-step=action-next-step.png +icon.action.importGPS=action-import-gps.png +icon.action.previous-step=action-previous-step.png +icon.action.go-up=action-go-up.png +icon.action.information=action-information.png +icon.action.local-export=action-local-import.png +icon.action.local-import=action-local-export.png +icon.action.remote-export=action-remote-export.png +icon.action.remote-import=action-remote-import.png +icon.action.revert=action-revert.png +icon.action.select-ssl-cert=action-select-ssl-cert.png +icon.action.start=action-synchro-start.png +icon.action.stop=action-synchro-stop.png + +icon.action.wizard-state-pending=action-wizard-state-pending-16.png +icon.action.wizard-state-running=action-wizard-state-running-16.png +icon.action.wizard-state-need_fix=action-wizard-state-need_fix-16.png +icon.action.wizard-state-successed=action-wizard-state-successed-16.png +icon.action.wizard-state-failed=action-wizard-state-failed-16.png +icon.action.wizard-state-canceled=action-wizard-state-canceled-16.png + +icon.action.wizard-start=action-wizard-start-16.png +icon.action.wizard-next=action-wizard-next-16.png +icon.action.wizard-previous=action-wizard-previous-16.png +icon.action.wizard-pause=action-wizard-pause-16.png +icon.action.wizard-refresh=action-wizard-refresh-16.png + +icon.action.wizard-config=action-wizard-config-16.png +icon.action.wizard-message=action-wizard-message-16.png + diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/I18nEditor.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/I18nEditor.java new file mode 100644 index 0000000..eda2c96 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/I18nEditor.java @@ -0,0 +1,201 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor; + +import org.nuiton.i18n.editor.ui.I18nEditorUIHandler; +import org.nuiton.i18n.I18n; + +import java.io.IOException; +import javax.swing.SwingUtilities; +import jaxx.runtime.JAXXContextEntryDef; +import jaxx.runtime.SwingUtil; +import jaxx.runtime.Util; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.i18n.editor.ui.I18nEditorUI; +import org.nuiton.util.StringUtil; + +import static org.nuiton.i18n.I18n._; + +/** + * L'application. + * + * @author chemit + */ +public class I18nEditor { + + private static long startingTime = System.nanoTime(); + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static Log log = LogFactory.getLog(I18nEditor.class); + + /** + * Lancement de l'interface + * + * @param args path to manage + * @throws java.io.IOException if any IO exception + */ + public static void main(String[] args) throws IOException { + + startingTime = System.nanoTime(); + log.info("I18nEditor start at " + new java.util.Date() + " args: " + java.util.Arrays.toString(args)); + + try { + + I18nEditorContext context = init(args); + + log.info(_("i18neditor.init.context.done", StringUtil.convertTime(startingTime, System.nanoTime()))); + + Util.checkJAXXContextEntry(context, JAXXContextEntryDef.newDef(I18nEditorConfig.class)); + + I18nEditorConfig config = context.getContextValue(I18nEditorConfig.class); + + config.doAction(I18nEditorConfig.Step.AfterInit.ordinal()); + + if (config.isDisplayMainUI()) { + + I18nEditorUIHandler uiHandler = context.getContextValue(I18nEditorUIHandler.class); + + //uiHandler.openProject(context); + + final I18nEditorUI ui = uiHandler.initUI(context, config.isFullScreen()); + + log.info(_("i18neditor.init.ui.done")); + + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + ui.setVisible(true); + } + }); + + } else { + System.exit(0); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + System.exit(1); + } + + } + + public static I18nEditorContext init(String... args) throws Exception { + // to enable javassist on webstart, must remove any securityManager, + // see if this can be dangerous (should not be since jnlp is signed ?) + // moreover it speeds up the loading :) + System.setSecurityManager(null); + + long t0 = System.nanoTime(); + + //I18n.setUniqueBundleName("nuiton-i18n-editor-i18n"); + + Runtime.getRuntime().addShutdownHook(new Thread("shutdown observe") { + + @Override + public void run() { + try { + super.run(); + + I18nEditorContext.get().close(); + + // force to kill main thread + + log.info(_("i18neditor.init.closed", new java.util.Date())); + Runtime.getRuntime().halt(0); + } catch (Exception ex) { + log.error("error while closing " + ex.getMessage(), ex); + Runtime.getRuntime().halt(1); + } + } + }); + + // init root context + I18nEditorContext context = I18nEditorContext.get(); + + // init config + I18nEditorConfig config = context.getConfig(); + config.parse(args); + + // init i18n + I18n.init(config.getLocale()); + + log.info(_("i18neditor.message.config.loaded", config.getVersion())); + + // prepare ui look&feel and load ui properties + try { + SwingUtil.initNimbusLoookAndFeel(); + } catch (Exception e) { + // could not find nimbus look-and-feel + log.warn(_("i18neditor.warning.nimbus.landf")); + } catch (Throwable e) { + log.warn(_("i18neditor.warning.no.ui"), e); + // pas d'environnement d'ui + config.setCanUseUI(false); + } + + if (config.isCanUseUI()) { + // chargement de la configuration des uis + SwingUtil.loadUIConfig(I18nEditorConfig.APPLICATION_PROPERTIES, null); + } + + if (log.isDebugEnabled()) { + log.debug("init done in " + (StringUtil.convertTime(t0, System.nanoTime()))); + } + return context; + } + + public void help() { + I18nEditorContext context = I18nEditorContext.get(); + I18nEditorConfig config = context.getConfig(); + System.out.println(I18n._("i18neditor.message.help.usage", config.getVersion())); + System.out.println("Options (set with --option <key> <value>:"); + for (I18nEditorConfig.Option o : I18nEditorConfig.Option.values()) { + System.out.println("\t" + o.key + "(" + o.defaultValue + "):" + o.description); + } + + System.out.println("Actions:"); + for (I18nEditorConfig.Action a : I18nEditorConfig.Action.values()) { + System.out.println("\t" + java.util.Arrays.toString(a.aliases) + "(" + a.action + "):" + a.description); + } + disableMainUI(); + } + + public void configure() { + if (log.isDebugEnabled()) { + log.debug(this); + } + I18nEditorContext context = I18nEditorContext.get(); + I18nEditorConfig config = context.getConfig(); + I18nEditorUIHandler handler = context.getContextValue(I18nEditorUIHandler.class); + handler.showConfig(context); + config.setDisplayMainUI(false); + } + + /** + * Désactiver la possiblite de lancer l'ui principale. + */ + public void disableMainUI() { + if (log.isDebugEnabled()) { + log.debug(this); + } + I18nEditorContext context = I18nEditorContext.get(); + I18nEditorConfig config = context.getConfig(); + config.setDisplayMainUI(false); + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/I18nEditorConfig.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/I18nEditorConfig.java new file mode 100644 index 0000000..e953c92 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/I18nEditorConfig.java @@ -0,0 +1,340 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor; + +import java.io.IOException; +import java.io.InputStream; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import static org.nuiton.i18n.I18n._; +import org.nuiton.util.FileUtil; +import org.nuiton.util.Version; + +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.FilenameFilter; +import java.util.HashSet; +import java.util.Locale; +import java.util.Properties; +import java.util.Set; +import org.nuiton.util.VersionUtil; + +/** + * La configuration de l'application. + * + * Note : cette classe sera auto-instanciée par le contexte applicatif. + * + * TODO ajouter d'autres propriete pour controler quel storage est utilise + * et quel est son type (local ou pas). + * + * @author chemit + * @see jaxx.runtime.DefaultApplicationContext.AutoLoad + */ +@jaxx.runtime.DefaultApplicationContext.AutoLoad +public class I18nEditorConfig extends org.nuiton.util.ApplicationConfig { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(I18nEditorConfig.class); + /** + * le fichier de configuration de l'application avec les informations sur + * le projet (version, license,...) et la configuration des ui (icons, ...) + */ + public static final String APPLICATION_PROPERTIES = "/nuiton-i18n-editor.properties"; + /** + * le nom du repertoire ou sont les donnees de l'application + */ + public static final String USER_DIRECTORY_FILENAME = ".nuiton-i18n-editor"; + /** + * le repertoire utilisateur de l'application + */ + protected static File userDirectory; + + public static File getUserDirectory() { + if (userDirectory == null) { + userDirectory = new File(new File(I18nEditorConfig.getUserHome()), USER_DIRECTORY_FILENAME); + } + return userDirectory; + } + /** + * un drapeau pour savoir si on est en mode pleine écran + */ + protected boolean fullscreen; + /** + * un drepeau pour savoir s'il faut lancer l'interface graphique. + * Cette valeur peut être programmées lors des actions. + */ + private boolean displayMainUI = true; + /** + * drapeau pour savoir si on peut utiliser des ui dans l'environnement. + * + * Par defaut, on suppose qu'on peut utiliser l'environnement graphique + * et si on désactive explicitement ou si pas d'environnement graphique trouvé. + */ + private boolean canUseUI = true; + /** + * la liste des projets déjà connus (dans le repertoire getProjectFile()) + */ + protected Set<String> projects = new HashSet<String>(); + + public I18nEditorConfig() { + + setConfigFileName(Option.CONFIG_FILE.defaultValue); + + // chargement de la configuration interne + + InputStream stream = getClass().getResourceAsStream(APPLICATION_PROPERTIES); + + Properties p = new Properties(); + try { + p.load(stream); + for (Object k : p.keySet()) { + String key = k + ""; + Object value = p.get(k); + if (log.isDebugEnabled()) { + log.debug("install properties " + k + " : " + value); + } + setDefaultOption(key, "" + value); + } + } catch (IOException ex) { + throw new RuntimeException(ex); + } + + for (Option o : Option.values()) { + setDefaultOption(o.key, o.defaultValue); + } + + // on supprime le stamp de snapshot s'il existe + String sVersion = VersionUtil.removeSnapshot(getOption("application.version")); + Version version = VersionUtil.valueOf(sVersion); + setDefaultOption("version", version.getVersion()); + + + // initialisation des répertoires + //FileUtil.setCurrentDirectory(getUserDirectory()); + getUserDirectory().mkdirs(); + // suppression du contenu du répertoire temporaire + FileUtil.deleteRecursively(getTmpDirectory()); + + // initialisation des actions + for (Action a : Action.values()) { + for (String alias : a.aliases) { + addActionAlias(alias, a.action); + } + } + // recuperation de la liste des projets deja connus + String[] list = getProjectsDirectory().list(new FilenameFilter() { + + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".i18nproject"); + } + }); + for (String name : list) { + projects.add(name.substring(0, name.length() - ".i18nproject".length())); + } + } + + public String getCopyrightText() { + return "Version " + getVersion() + " Codelutin @ 2008-2009"; + } + + /** + * @return la version de l'application. + */ + public Version getVersion() { + Version option = getOption(Version.class, "version"); + return option; + } + + public boolean isFullScreen() { + Boolean result = getOptionAsBoolean(Option.FULL_SCREEN.key); + return result != null && result; + } + + public File getTmpDirectory() { + File result = getOptionAsFile(Option.TMP_DIRECTORY.key); + if (!result.exists()) { + result.mkdirs(); + } + return result; + } + + public File getProjectsDirectory() { + File result = getOptionAsFile(Option.PROJECTS_DIRECTORY.key); + if (!result.exists()) { + result.mkdirs(); + } + return result; + } + + public boolean isDisplayMainUI() { + return displayMainUI; + } + + public boolean isCanUseUI() { + return canUseUI; + } + + public Locale getLocale() { + Locale result = getOption(Locale.class, Option.LOCALE.key); + return result; + } + + public Set<String> getProjects() { + return projects; + } + + public void setFullscreen(boolean fullscreen) { + boolean oldValue = isFullScreen(); + setOption(Option.FULL_SCREEN.key, fullscreen + ""); + saveForUser(); + firePropertyChange("fullscreen", oldValue, fullscreen); + } + + public void setDisplayMainUI(boolean b) { + displayMainUI = b; + } + + public void setCanUseUI(boolean canUseUI) { + this.canUseUI = canUseUI; + if (!canUseUI) { + // on ne pourra pas lancer l'ui principale + setDisplayMainUI(false); + } + } + + public void setLocale(Locale newLocale) { + setOption(Option.LOCALE.key, newLocale.toString()); + Locale.setDefault(newLocale); + saveForUser(); + firePropertyChange("locale", null, newLocale); + } + + /** + * Save configuration, in user home directory using the + * {@link #getConfigFileName}. Default, env and commande line note saved + */ + public void saveForUser() { + super.saveForUser(); + } + public static final String[] DEFAULT_JAXX_PCS = { + "locale", "fullScreen" + }; + + public void removeJaxxPropertyChangeListener() { + PropertyChangeListener[] toRemove = jaxx.runtime.Util.findJaxxPropertyChangeListener(DEFAULT_JAXX_PCS, getPropertyChangeListeners()); + if (toRemove == null || toRemove.length == 0) { + return; + } + if (log.isDebugEnabled()) { + log.debug("before remove : " + getPropertyChangeListeners().length); + log.debug("toRemove : " + toRemove.length); + } + for (PropertyChangeListener listener : toRemove) { + removePropertyChangeListener(listener); + } + if (log.isDebugEnabled()) { + log.debug("after remove : " + getPropertyChangeListeners().length); + } + } + + public File getProjectStore(String name) { + return new File(getProjectsDirectory(), name + ".i18nproject"); + } + + ////////////////////////////////////////////////// + // Toutes les options disponibles + ////////////////////////////////////////////////// + public static enum Option implements OptionDef { + + CONFIG_FILE(CONFIG_FILE_NAME, _("i18neditor.config.configFileName.description"), "nuitoni18neditor-config", String.class, true, true), + // directories + TMP_DIRECTORY("tmp.directory", _("i18neditor.config.defaultTmpDirectory.description"), getUserDirectory() + File.separator + "tmp", File.class, false, false), + PROJECTS_DIRECTORY("projects.directory", _("i18neditor.config.defaultProjectsDirectory.description"), getUserDirectory() + File.separator + "projects", File.class, false, false), + // ui config + FULL_SCREEN("ui.fullscreen", _("i18neditor.config.ui.fullscreen"), "false", Boolean.class, false, false), + LOCALE("ui.locale", _("i18neditor.config.ui.locale"), Locale.FRANCE.toString(), Locale.class, false, false); + public final String key; + public final String description; + public final String defaultValue; + public final Class<?> type; + public final boolean _transient; + public final boolean _final; + + private Option(String key, String description, String defaultValue, Class<?> type, boolean _transient, boolean _final) { + this.key = key; + this.description = description; + this.defaultValue = defaultValue; + this.type = type; + this._final = _final; + this._transient = _transient; + } + + @Override + public boolean isFinal() { + return _final; + } + + @Override + public boolean isTransient() { + return _transient; + } + + @Override + public String getDefaultValue() { + return defaultValue; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public String getKey() { + return key; + } + + @Override + public Class<?> getType() { + return type; + } + } + + public static enum Step { + + AfterInit, BeforeExit + } + + public static enum Action { + + HELP(_("i18neditor.action.commandline.help"), I18nEditor.class.getName() + "#help", "-h", "--help"), + CONFIGURE(_("i18neditor.action.commandline.configure"), I18nEditor.class.getName() + "#configure", "-c", "--configure"), + NO_MAIN_UI(_("i18neditor.action.commandline.disable.main.ui"), I18nEditor.class.getName() + "#disableMainUI", "-n", "--no-main"); + public String description; + public String action; + public String[] aliases; + + private Action(String description, String action, String... aliases) { + this.description = description; + this.action = action; + this.aliases = aliases; + } + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/I18nEditorContext.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/I18nEditorContext.java new file mode 100644 index 0000000..08e319e --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/I18nEditorContext.java @@ -0,0 +1,343 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor; + +import java.beans.PropertyChangeListener; +import java.util.List; +import java.util.Locale; +import jaxx.runtime.JAXXContextEntryDef; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.i18n.editor.project.I18nProject; +import org.nuiton.i18n.editor.ui.TreeModelMode; +import org.nuiton.i18n.editor.ui.I18nEditorUI; + +/** + * Le contexte de l'application. + * <p/> + * On définit ici toutes les entrées du contexte. + * <p/> + * Note : cette classe possède une instance partagée accéssible via la méthode {@link #get()}. + * + * @author chemit + */ +public class I18nEditorContext extends jaxx.runtime.DefaultApplicationContext { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private final Log log = LogFactory.getLog(I18nEditorContext.class); + //------------------------------------------- + // UI instances + //------------------------------------------- + public static final JAXXContextEntryDef<I18nEditorUI> MAIN_UI_ENTRY_DEF = JAXXContextEntryDef.newDef("mainui", I18nEditorUI.class); + public static final JAXXContextEntryDef<I18nProject> PROJECT_DEF = JAXXContextEntryDef.newDef(I18nProject.class); + private static final JAXXContextEntryDef<String> SELECTED_KEY_DEF = JAXXContextEntryDef.newDef("selectedKey", String.class); + private static final JAXXContextEntryDef<String> RE_SELECTED_KEY_DEF = JAXXContextEntryDef.newDef("reSelectedKey", String.class); + private static final JAXXContextEntryDef<TreeModelMode> TREE_MODEL_MODE_DEF = JAXXContextEntryDef.newDef(TreeModelMode.class); + public static final String PROJECT_PROPERTY = "project"; + public static final String SELECTED_PACKAGES_PROPERTY = "selectedPackages"; + public static final String SELECTED_BUNDLES_PROPERTY = "selectedBundles"; + public static final String SELECTED_KEY_PROPERTY = "selectedKey"; + public static final String TREE_MODEL_MODE_PROPERTY = "treeModelMode"; + /** Séparateur des propriétés */ + public static final String SEPARATOR = "."; + /** + * l'intance partagée accessible après un appel à la méthode + * {@link #init()} + */ + protected static I18nEditorContext instance; + + /** + * Récupération du contexte applicatif. + * + * @return l'instance partagé du contexte. + * @throws IllegalStateException si le contexte n'a pas été initialisé via + * la méthode {@link #init()} + */ + public static synchronized I18nEditorContext get() throws IllegalStateException { + if (instance == null) { + instance = new I18nEditorContext(); + } + return instance; + } + /** + * Un objet pour bloquer le context + */ + protected final Object lock = new Object(); + + protected I18nEditorContext() { + super(); + TREE_MODEL_MODE_DEF.setContextValue(this, TreeModelMode.TREE); + } + + public I18nEditorConfig getConfig() { + return getContextValue(I18nEditorConfig.class); + } + + public I18nProject getProject() { + return PROJECT_DEF.getContextValue(this); + } + + public I18nEditorUI getMainUI() { + return MAIN_UI_ENTRY_DEF.getContextValue(this); + } + + public void addSelectedPackage(String newPackage) { + List<String> list = getProject().getSelectedPackages(); + boolean added = list.add(newPackage); + if (added) { + firePropertyChange(SELECTED_PACKAGES_PROPERTY, null, list); + } + } + + public void removeSelectedPackage(String newPackage) { + List<String> list = getProject().getSelectedPackages(); + boolean removed = list.remove(newPackage); + if (removed) { + firePropertyChange(SELECTED_PACKAGES_PROPERTY, null, list); + } + } + + public void addSelectedBundle(Locale newBundle) { + List<Locale> list = getProject().getSelectedBundles(); + boolean added = list.add(newBundle); + if (added) { + firePropertyChange(SELECTED_BUNDLES_PROPERTY, null, list); + } + } + + public void removeSelectedBundle(Locale newBundle) { + List<Locale> list = getProject().getSelectedBundles(); + boolean removed = list.remove(newBundle); + if (removed) { + firePropertyChange(SELECTED_BUNDLES_PROPERTY, null, list); + } + } + + public TreeModelMode getTreeModelMode() { + return TREE_MODEL_MODE_DEF.getContextValue(this); + } + + public void setTreeModelMode(TreeModelMode mode) { + TreeModelMode oldMode = getTreeModelMode(); + if (mode == null) { + TREE_MODEL_MODE_DEF.removeContextValue(this); + + } else { + TREE_MODEL_MODE_DEF.setContextValue(this, mode); + } + if (log.isDebugEnabled()) { + log.debug("new mode " + mode + " - old mode " + oldMode); + } + firePropertyChange(TREE_MODEL_MODE_PROPERTY, oldMode, mode); + } + + public String getSelectedKey() { + return SELECTED_KEY_DEF.getContextValue(this); + } + + public void setSelectedKey(String key) { + + if (key == null) { + SELECTED_KEY_DEF.removeContextValue(this); + } else { + SELECTED_KEY_DEF.setContextValue(this, key); + } + if (log.isDebugEnabled()) { + log.debug("new selected key : " + key); + } + firePropertyChange(SELECTED_KEY_PROPERTY, null, key); + } + + public void saveSelectedKey() { + String key = getSelectedKey(); + if (log.isDebugEnabled()) { + log.debug("store key to reselect : " + key); + } + if (key == null) { + RE_SELECTED_KEY_DEF.removeContextValue(this); + } else { + RE_SELECTED_KEY_DEF.setContextValue(this, key); + } + SELECTED_KEY_DEF.removeContextValue(this); + } + + public String popSelectedKey() { + String key = RE_SELECTED_KEY_DEF.getContextValue(this); + if (key != null) { + // on supprime la valeur du context + RE_SELECTED_KEY_DEF.removeContextValue(this); + } + if (log.isDebugEnabled()) { + log.debug("pop key to reselect : " + key); + } + return key; + } + + public void lock() throws InterruptedException { + synchronized (lock) { + lock.wait(); + } + } + + public void releaseLock() { + synchronized (lock) { + lock.notify(); + } + } + + /** + * close the application's context. + * + * @throws java.lang.Exception if any pb while closing + */ + public void close() throws Exception { + if (log.isDebugEnabled()) { + log.debug("closing context " + this); + } + + // fermeture du context principal + clear(); + + if (log.isDebugEnabled()) { + log.debug("context closed" + this); + } + } + +// public synchronized void setProject(I18nProject project) throws IOException { +// +// project.load(); +// +// setContextValue(project); +// firePropertyChange("project", null, project); +// firePropertyChange(BUNDLES_I18N_PROPERTY, null, project.getSelectedLocales()); +// firePropertyChange(PACKAGES_I18N_PROPERTY, null, project.getSelectedPackages()); +// } +// /** +// * Récupération d'un bundle utilisateur, créé si il n'existe pas +// * +// * @param bundleName nom du bundle +// * @return bundle +// */ +// public I18nFileReader getUserBundle(String bundleName) { +// String name = REP_NAME + PROJECT_NAME + "-" + bundleName + ".properties"; +// I18nFileReader bundle = getBundles().get(name); +// if (bundle == null) { +// bundle = new I18nFileReader(); +// getUserBundles().put(name, bundle); +// getBundles().put(name, bundle); +// } +// return bundle; +// } +// /** +// * Récupération des valeurs pour les bundles pour une clé +// * +// * @param locales liste des bundles +// * @param key clé +// * @return liste des valeurs pour les bundles pour une clé +// */ +// public List<String> getValues(List<Locale> locales, String key) { +// List<String> values = new ArrayList<String>(); +// +// I18nProject project = getProject(); +// if (project != null) { +// +// for (Locale locale : locales) { +// +// String value = null; +// +// project.getValue(value, locale, key); +// +// values.add(value); +// } +// } +// return values; +// } + /** + * Création d'un nouveau bundle utilistateur + * + * @param bundleName nom du bundle (ex : fr_FR) + */ + public void createBundle(String bundleName) { +// getUserBundle(bundleName); + } + + public void createPackage(String bundleName) { +// getUserBundle(bundleName); + } + + /** + * Enregistrement d'une modification de clé dans le bundle utilisateur associé + * + * @param bundleName nom du bundle + * @param key clé + * @param value nouvelle valeur + */ + public void store(Locale bundleName, String key, String value) { + I18nProject project = getProject(); + if (project != null) { +// project.updateValue(bundleName, bundleName, key, value); + } +// I18nFileReader bundle = getUserBundle(bundleName); +// bundle.put(key, value); + } + + /** + * Enregistrement des bundles utilisateur sur le disque + */ + public void store() { +// Map<String, I18nFileReader> userBundles = getUserBundles(); +// for (String name : userBundles.keySet()) { +// I18nFileReader bundle = userBundles.get(name); +// try { +// bundle.store(new FileWriter(name), null); +// } catch (IOException e) { +// throw new RuntimeException(e); //TODO: Gestion des exceptions +// } +// } + } + + @Override + public void firePropertyChange(String name, Object oldValue, Object newValue) { + super.firePropertyChange(name, oldValue, newValue); + } + public static final String[] DEFAULT_JAXX_PCS = { + SELECTED_PACKAGES_PROPERTY, + SELECTED_BUNDLES_PROPERTY, + PROJECT_PROPERTY, + SELECTED_KEY_PROPERTY, + TREE_MODEL_MODE_PROPERTY + }; + + public void removeJaxxPropertyChangeListener() { + PropertyChangeListener[] toRemove = jaxx.runtime.Util.findJaxxPropertyChangeListener(DEFAULT_JAXX_PCS, getPropertyChangeListeners()); + if (toRemove == null || toRemove.length == 0) { + return; + } + if (log.isDebugEnabled()) { + log.debug("before remove : " + getPropertyChangeListeners().length); + log.debug("toRemove : " + toRemove.length); + } + for (PropertyChangeListener listener : toRemove) { + removePropertyChangeListener(listener); + } + if (log.isDebugEnabled()) { + log.debug("after remove : " + getPropertyChangeListeners().length); + } + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/AbstractI18nProject.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/AbstractI18nProject.java new file mode 100644 index 0000000..c44efae --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/AbstractI18nProject.java @@ -0,0 +1,425 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.project; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.i18n.bundle.I18nBundle; +import org.nuiton.i18n.bundle.I18nBundleEntry; +import org.nuiton.i18n.bundle.I18nBundleFactory; + +/** + * + * @author chemit + */ +public class AbstractI18nProject implements I18nProject { + + public static final String NAME_PROPERTY_NAME = "name"; + public static final String URLS_PROPERTY_NAME = "urls"; + public static final String STORE_PROJECT_PROPERTY_NAME = "storeProject"; + public static final String STORE_FILE_PROPERTY_NAME = "storeFile"; + public static final Locale[] EMPTY_LOCALE_ARRAY = new Locale[0]; + public static final String EMPTY_STRING = ""; + public static final String[] EMPTY_STRING_ARRAY = new String[0]; + public static final Log log = LogFactory.getLog(AbstractI18nProject.class); + /** le nom du projet */ + protected String name; + /** les urls des fichiers de traduction a charger */ + protected List<URL> urls; + /** les definitions de bundles du projet */ + protected I18nBundle[] i18nBundles; + /** le fichier où conserver le projet (si null, on ne persiste pas le projet) */ + protected File storeFile = new File(""); + /** un drapeau pour savoir si on persiste le projet */ + protected boolean storeProject; + /** un drapeau pour savoir si le modele a ete charge */ + boolean loaded; + /** Les locales selectionnees dans ce projet */ + protected List<Locale> selectedBundles; + /** les paquetages selectionnes dans ce projet */ + protected List<String> selectedPackages; + /** le dictionnaire des fichiers de traductions charges */ + protected Map<String, Properties> resources; + /** pour propager les changements du modele */ + protected PropertyChangeSupport pcs; + + protected AbstractI18nProject() { + this.resources = new LinkedHashMap<String, Properties>(); + this.selectedBundles = new ArrayList<Locale>(); + this.selectedPackages = new ArrayList<String>(); + this.pcs = new PropertyChangeSupport(this); + } + + @Override + public String getName() { + return name; + } + + @Override + public List<URL> getUrls() { + return urls; + } + + @Override + public boolean isStoreProject() { + return storeProject; + } + + @Override + public File getStoreFile() { + return storeFile; + } + + @Override + public void setName(String name) { + String oldValue = this.name; + this.name = name; + firePropertyChange(NAME_PROPERTY_NAME, oldValue, name); + } + + @Override + public void setUrls(List<URL> urls) { + this.urls = urls; + } + + @Override + public void setStoreProject(boolean storeProject) { + boolean oldValue = this.storeProject; + this.storeProject = storeProject; + firePropertyChange(STORE_PROJECT_PROPERTY_NAME, oldValue, storeProject); + } + + @Override + public void setStoreFile(File storeFile) { + File oldValue = this.storeFile; + this.storeFile = storeFile; + firePropertyChange(STORE_FILE_PROPERTY_NAME, oldValue, storeFile); + } + + @Override + public String[] getPackages() { + return I18nBundleFactory.getBundleNames(i18nBundles); + } + + @Override + public Locale[] getBundles() { + return I18nBundleFactory.getLocales(i18nBundles); + } + + @Override + public List<String> getSelectedPackages() { + return selectedPackages; + } + + @Override + public List<Locale> getSelectedBundles() { + return selectedBundles; + } + + @Override + public String[] getKeys() { + if (!loaded) { + return EMPTY_STRING_ARRAY; + } + + List<String> paquetages = getSelectedPackages(); + List<Locale> locales = getSelectedBundles(); + Set<String> keys = new HashSet<String>(); + + for (I18nBundle bundle : i18nBundles) { + if (paquetages.contains(bundle.getBundlePrefix())) { + for (I18nBundleEntry entry : bundle) { + if (!locales.contains(entry.getLocale())) { + continue; + } + Set<Object> keySet = resources.get(entry.getPath().toString()).keySet(); + for (Object object : keySet) { + keys.add(object.toString()); + } + } + } + } + List<String> r = new ArrayList<String>(keys); + return r.toArray(new String[r.size()]); + } + + @Override + public void deleteKey(String packageName, Locale locale, String key) { + checkLoaded(); + Properties resource = getResource(packageName, locale); + if (resource != null) { + resource.remove(key); + } + } + + @Override + public Map<Locale, String> getValues(String packageName, String key) { + if (!loaded) { + return null; + } + + List<String> paquetages = getSelectedPackages(); + + if (!paquetages.contains(packageName)) { + return null; + } + + Map<Locale, String> r = new LinkedHashMap<Locale, String>(); + + List<Locale> locales = getSelectedBundles(); + + I18nBundle bundle = getI18nBundle(packageName); + + for (I18nBundleEntry entry : bundle) { + Locale locale = entry.getLocale(); + if (!locales.contains(locale)) { + continue; + } + Properties resource = resources.get(entry.getPath().toString()); + if (resource.containsKey(key)) { + r.put(locale, resource.getProperty(key).toString()); + } + } + return r; + } + + @Override + public String getValue(String packageName, Locale locale, String key) { + if (!loaded) { + return EMPTY_STRING; + } + Properties resource = getResource(packageName, locale); + if (resource != null) { + Object object = resource.get(key); + return object.toString(); + } + return null; + + } + + @Override + public void addValue(String packageName, Locale locale, String key, String value) { + checkLoaded(); + Properties resource = getResource(packageName, locale); + if (resource != null) { + resource.put(key, value); + } + } + + @Override + public void updateValue(String packageName, Locale locale, String key, String value) { + checkLoaded(); + Properties resource = getResource(packageName, locale); + if (resource != null) { + resource.put(key, value); + } + } + + @Override + public void copyDefinitionTo(I18nProject project) { + // check we are on the same type of project + if (project.getClass() != getClass()) { + throw new IllegalArgumentException("copyDefinitionTo method must use same project type, but was not! (required : " + getClass() + ", but find " + project.getClass() + 3); + } + project.setName(name); + project.setUrls(urls); + project.setStoreProject(storeProject); + // always clean storeFile (could be init in project from ui, but only keep it if necessary) + project.setStoreFile(storeProject ? storeFile : null); + } + + @Override + public void load() throws IOException { + try { + synchronized (this) { + resources.clear(); + selectedBundles.clear(); + selectedPackages.clear(); + + // detections des bundles i18n a partir des urls donnees + List<I18nBundle> tmp = I18nBundleFactory.detectBundles(urls.toArray(new URL[urls.size()])); + i18nBundles = tmp.toArray(new I18nBundle[tmp.size()]); + + selectedBundles.addAll(Arrays.asList(getBundles())); + selectedPackages.addAll(Arrays.asList(getPackages())); + + for (I18nBundle bundle : i18nBundles) { + for (I18nBundleEntry entry : bundle) { + URL path = entry.getPath(); + Properties properties = new Properties(); + entry.load(properties); + resources.put(path.toString(), properties); + } + } + } + } finally { + loaded = true; + } + } + + @Override + public void store() throws IOException { + checkLoaded(); + } + + @Override + public void saveDefinition() throws IOException { + Properties p = new Properties(); + fillDefinition(p); + FileOutputStream stream = null; + try { + stream = new FileOutputStream(getStoreFile()); + p.store(stream, "generated by " + getClass().getName()); + } finally { + if (stream != null) { + stream.close(); + } + } + + } + + @Override + public void fillDefinition(Properties p) { + p.setProperty("name", name); + p.setProperty("class", getClass().getName()); + StringBuilder buffer = new StringBuilder(); + for (URL u : urls) { + buffer.append(',').append(u.toString()); + } + p.setProperty("urls", buffer.substring(1)); + } + + @Override + public String toString() { + return super.toString() + "<name: " + name + ">"; + } + + @Override + public void addPropertyChangeListener(PropertyChangeListener listener) { + if (log.isDebugEnabled()) { + log.debug(this + " / " + listener); + } + pcs.addPropertyChangeListener(listener); + } + + @Override + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + if (log.isDebugEnabled()) { + log.debug(this + " / " + propertyName + " : " + listener); + } + pcs.addPropertyChangeListener(propertyName, listener); + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener listener) { + if (log.isDebugEnabled()) { + log.debug(this + " / " + listener); + } + pcs.removePropertyChangeListener(listener); + } + + @Override + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + if (log.isDebugEnabled()) { + log.debug(this + " / " + propertyName + " : " + listener); + } + pcs.removePropertyChangeListener(propertyName, listener); + } + + @Override + public void removePropertyChangeListeners() { + for (PropertyChangeListener l : pcs.getPropertyChangeListeners()) { + pcs.removePropertyChangeListener(l); + } + } + + @Override + public void fireAllProperties() { + firePropertyChange(NAME_PROPERTY_NAME, null, name); + firePropertyChange(URLS_PROPERTY_NAME, null, urls); + firePropertyChange(STORE_PROJECT_PROPERTY_NAME, null, storeProject); + firePropertyChange(STORE_FILE_PROPERTY_NAME, null, storeFile); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + i18nBundles = null; + resources.clear(); + selectedBundles.clear(); + selectedPackages.clear(); + } + + protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + pcs.firePropertyChange(propertyName, oldValue, newValue); + } + + protected I18nBundle getI18nBundle(String packageName) { + if (i18nBundles != null) { + for (I18nBundle b : i18nBundles) { + if (b.getBundlePrefix().equals(packageName)) { + return b; + } + } + } + return null; + } + + protected I18nBundleEntry getI18nBundleEntry(String packageName, Locale locale) { + I18nBundle bundle = getI18nBundle(packageName); + if (bundle != null) { + for (I18nBundleEntry entry : bundle) { + if (locale.equals(entry.getLocale())) { + return entry; + } + } + } + return null; + } + + protected Properties getResource(String packageName, Locale locale) { + I18nBundleEntry entry = getI18nBundleEntry(packageName, locale); + if (entry != null) { + Properties resource = resources.get(entry.getPath().toString()); + return resource; + } + return null; + } + + protected void checkLoaded() throws IllegalStateException { + if (!loaded) { + throw new IllegalStateException("project was not loaded"); + } + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/AbstractI18nProjectProvider.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/AbstractI18nProjectProvider.java new file mode 100644 index 0000000..989f0dd --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/AbstractI18nProjectProvider.java @@ -0,0 +1,107 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.nuiton.i18n.editor.project; + +import java.util.Collections; +import java.util.Map; +import java.util.Map.Entry; +import org.nuiton.i18n.I18n; +import org.nuiton.i18n.editor.project.impl.DirectoryI18nProject; +import org.nuiton.i18n.editor.ui.project.ProjectUIModel; + +/** + * + * @param <P> le type de projet supporte. + * + * @author chemit + */ +public abstract class AbstractI18nProjectProvider<P extends I18nProject> implements I18nProjectProvider<P> { + + public static final String CLASS_PARAMETER = "class"; + protected final Class<P> type; + protected final String label; + protected final String description; + protected Map<String, Class<?>> authorizedParameters; + + protected abstract Map<String, Class<?>> initAuthorizedParameters(); + + public AbstractI18nProjectProvider(Class<P> type, String label, String description) { + this.type = type; + this.label = label; + this.description = description; + } + + @Override + public Class<P> getType() { + return type; + } + + @Override + public String getLabel() { + return label; + } + + @Override + public String getDescription() { + return I18n._(description); + } + + @Override + public Map<String, Class<?>> getAuthorizedParameters() { + if (authorizedParameters == null) { + this.authorizedParameters = Collections.unmodifiableMap(initAuthorizedParameters()); + } + return authorizedParameters; + } + + @Override + public P newProject(ProjectUIModel model) { + I18nProject project = model.getProject(); + P p = newProject(); + project.copyDefinitionTo(p); + return p; + } + + public <T extends Object> T getParameter(Class<T> returnType, String propertyName, Map<String, Object> parameters, boolean mustExist) { + Map<String, Class<?>> map = getAuthorizedParameters(); + // check name + if (!map.containsKey(propertyName)) { + throw new IllegalArgumentException("the property " + propertyName + " is unknown for this project.\nKnown parameters :" + map.keySet()); + } + // check type + Class<?> requiredType = map.get(propertyName); + if (returnType != requiredType && !returnType.isAssignableFrom(requiredType)) { + throw new IllegalArgumentException("the property " + propertyName + " must be of the type " + requiredType + ", but was : " + requiredType); + } + + for (Entry<String, Object> e : parameters.entrySet()) { + if (propertyName.equals(e.getKey())) { + return (T) e.getValue(); + } + } + if (mustExist) { + throw new IllegalArgumentException("could not find property " + propertyName + ".\nKnown properties in :\n" + parameters.keySet()); + } + return null; + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/I18nProject.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/I18nProject.java new file mode 100644 index 0000000..a94ba57 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/I18nProject.java @@ -0,0 +1,198 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.project; + +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; + +/** + * + * @author chemit + */ +public interface I18nProject { + + ///////////////////////////////////////////////////////////////////// + // definition accessor ////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////// + /** + * @return le nom du projet + */ + String getName(); + + /** + * @return les urls du projet + */ + List<URL> getUrls(); + + /** + * + * @return <code>true</code> si la definition du projet est persiste + */ + boolean isStoreProject(); + + /** + * + * @return le chemin du fichier ou persister la definition du projet + * + * Note : n'est pris en compte uniquement si {@link #isStoreProject()} est + * vrai. + */ + File getStoreFile(); + + ///////////////////////////////////////////////////////////////////// + // definition mutator ////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////// + void setName(String name); + + void setUrls(List<URL> urls); + + void setStoreProject(boolean storeProject); + + void setStoreFile(File storeFile); + + ///////////////////////////////////////////////////////////////////// + // runtime accessor ///////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////// + /** + * @return les paquetages du projet + */ + String[] getPackages(); + + /** + * @return les locales du projet + */ + Locale[] getBundles(); + + /** + * @return les paquetages selectionnes + */ + List<String> getSelectedPackages(); + + /** + * @return les locales selectionnees + */ + List<Locale> getSelectedBundles(); + + /** + * @return les clefs de traductions pour les packages selectionnee et les locales selectionnes + */ + String[] getKeys(); + + /** + * @param packageName + * @param key la clef de traductions + * @return les traductions pour les packages, locales et clef selectionnees + */ + Map<Locale, String> getValues(String packageName, String key); + + /** + * @param key la clef de traductions + * @param locale la locale + * @param packageName le nom du package + * @return les traductions + */ + String getValue(String packageName, Locale locale, String key); + + /** + * Copy roject definition to the given project. + * + * @param project the destination project + */ + void copyDefinitionTo(I18nProject project); + + /** + * Supprime une traduction pour une clef donnee dans une langue et un paquetage donne. + * + * @param packageName le paquetage ou supprimer la clef + * @param locale la locale de la traduction + * @param key la clef de traduction + */ + void deleteKey(String packageName, Locale locale, String key); + + /** + * Ajouter une traduction dans le projet. + * + * @param packageName le paquetage ou ajouter la clef + * @param locale la locale de la traduction + * @param key la clef de traduction + * @param value la traduction + */ + void addValue(String packageName, Locale locale, String key, String value); + + /** + * Mettre a jour une traduction dans le projet. + * + * @param packageName le paquetage ou ajouter la clef + * @param locale la locale de la traduction + * @param key la clef de traduction + * @param value la traduction + */ + void updateValue(String packageName, Locale locale, String key, String value); + + /** + * Chargement des traductions du projet. + * + * @throws IOException + */ + void load() throws IOException; + + /** + * Enregistrement des traductions du projet. + * + * @throws IOException + */ + void store() throws IOException; + + /** + * Sauvegarde la definition du projet. + * + * @throws IOException pour tout pb lors de la sauvegarde + */ + void saveDefinition() throws IOException; + + /** + * Remplit un dictionnaire avec les proprietes de la definition du projet. + * + * @param p le dictionnaire des proprietes de la definition du projet + */ + void fillDefinition(Properties p); + + ///////////////////////////////////////////////////////////////////// + // property change listeners //////////////////////////////////////// + ///////////////////////////////////////////////////////////////////// + void addPropertyChangeListener(PropertyChangeListener listener); + + void addPropertyChangeListener(String propertyName, PropertyChangeListener listener); + + void removePropertyChangeListener(PropertyChangeListener listener); + + void removePropertyChangeListener(String propertyName, PropertyChangeListener listener); + + void removePropertyChangeListeners(); + + void fireAllProperties(); + + +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/I18nProjectConfigurePanelUI.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/I18nProjectConfigurePanelUI.java new file mode 100644 index 0000000..1b27af0 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/I18nProjectConfigurePanelUI.java @@ -0,0 +1,40 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.project; + +import org.nuiton.i18n.editor.ui.project.*; +import jaxx.runtime.JAXXObject; + +/** + * Le contrat a respecter pour configurer un type de projet. + * + * @param <P> le type de projet + * + * @author chemit + */ +public interface I18nProjectConfigurePanelUI<P extends I18nProject> extends JAXXObject { + + /** + * + * @return l'instance partagee du modele de creation de projet + */ + ProjectUIModel getModel(); + + P getProject(); +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/I18nProjectFactory.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/I18nProjectFactory.java new file mode 100644 index 0000000..365eb4f --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/I18nProjectFactory.java @@ -0,0 +1,177 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.project; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; +import java.util.ServiceLoader; +import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.i18n.editor.ui.project.ProjectUIModel; + +/** + * L'usine de projets. + * + * @author chemit + * @see I18nProject + * @see I18nProjectProvider + */ +public class I18nProjectFactory { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + private static final Log log = LogFactory.getLog(I18nProjectFactory.class); + /** le cache des provideurs de projet. */ + protected static Set<I18nProjectProvider<?>> providers; + + /** + * Creer un projet a partir d'un dictionnaire de parametres. + * + * @param <P> le type de projet + * @param projectClass le type de la classe + * @param params le dictionnaire des paramètres pour créer le projet + * @return le projet instancie mais non ouvert. + */ + public static <P extends I18nProject> P newProject(Class<P> projectClass, Map<String, Object> params) { + I18nProjectProvider<P> provider = getProvider(projectClass); + if (provider == null) { + throw new IllegalArgumentException("could not provider for " + projectClass); + } + P result = provider.newProject(params); + return result; + } + + /** + * Creer un projet a partir de l'ui de creation de projet. + * + * @param <P> le type du projet + * @param projectClass le type du projet + * @param model le model de l'ui de creation de projet + * @return le projet instantie mais non ouvert + */ + public static <P extends I18nProject> P newProject(Class<P> projectClass, ProjectUIModel model) { + + I18nProjectProvider<P> provider = getProvider(projectClass); + if (provider == null) { + throw new IllegalArgumentException("could not provider for " + projectClass); + } + P result = provider.newProject(model); + return result; + } + + /** + * Creer un projet a partir d'un fichier de definition de projet. + * + * @param <P> le type du projet + * @param projectFile le fichier contenant la definition du projet + * @return le projet instantie mais non ouvert. + */ + public static <P extends I18nProject> P newProject(File projectFile) { + + FileInputStream stream = null; + try { + Properties p = new Properties(); + stream = new FileInputStream(projectFile); + p.load(stream); + + String tmp = p.getProperty(AbstractI18nProjectProvider.CLASS_PARAMETER); + Class<? extends I18nProject> projectClass = (Class<? extends I18nProject>) Class.forName(tmp); + + I18nProjectProvider<P> provider = (I18nProjectProvider<P>) getProvider(projectClass); + if (provider == null) { + throw new IllegalArgumentException("could not provider for " + projectClass); + } + // validate definition + provider.validateDefinition(p); + // instanciate safe project + P result = provider.newProject(p); + result.setStoreFile(projectFile); + return result; + + } catch (Exception ex) { + throw new RuntimeException("could not load project for reason " + ex.getMessage(), ex); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException ex) { + throw new RuntimeException("could not close project for reason " + ex.getMessage(), ex); + } + } + } + + + } + + /** + * Recupere l'ensemble des provideurs de projet connus par le systeme. + * + * Note: pour ajouter de nouveaux types de projet, on utilise la mecanique + * de chargement de service de la jdk {@link ServiceLoader}. + * + * @return l'ensemble des provideurs de projet connus par le systeme. + * + */ + public static Set<I18nProjectProvider<?>> getProviders() { + if (providers == null) { + synchronized (I18nProjectProvider.class) { + discoverProviders(); + } + } + return providers; + } + + /** + * Recupere le provideur d'un type de projet donne. + * + * @param <P> le type de projet + * @param projectClass le type de projet + * @return le provideur pour le le type de projet donne, ou <code>null</code> + * si aucun provideur ne prend en charge ce type de projet. + */ + public static <P extends I18nProject> I18nProjectProvider<P> getProvider(Class<P> projectClass) { + + for (I18nProjectProvider<?> p : getProviders()) { + if (p.getType() == projectClass) { + return (I18nProjectProvider<P>) p; + } + } + return null; + } + + /** + * Decouvrer les provideurs de projet via la mecanique {@link ServiceLoader} + * de la jdk + */ + protected static void discoverProviders() { + if (providers == null) { + providers = new HashSet<I18nProjectProvider<?>>(); + } else { + providers.clear(); + } + for (I18nProjectProvider<?> p : ServiceLoader.load(I18nProjectProvider.class)) { + log.info("loaded " + p); + providers.add(p); + } + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/I18nProjectProvider.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/I18nProjectProvider.java new file mode 100644 index 0000000..adf6a21 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/I18nProjectProvider.java @@ -0,0 +1,120 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.project; + +import java.io.IOException; +import java.net.URL; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import org.nuiton.i18n.editor.ui.project.ProjectUIModel; + +/** + * Le contrat d'un provider du projet. + * + * @param <P> le type de projet connu par le provider. + * @author chemit + */ +public interface I18nProjectProvider<P extends I18nProject> { + + /** + * + * @return le type du projet + */ + Class<P> getType(); + + /** + * + * @return le label du type de projet + */ + String getLabel(); + + /** + * + * @return la description de ce type de projet + */ + String getDescription(); + + /** + * + * @return le dictionnaire des paramètres autorisés pour ce type de projet + */ + Map<String, Class<?>> getAuthorizedParameters(); + + P newProject(); + /** + * + * @param params les paramètres pour instancier le projet + * @return le projet instancié (mais non chargé?) + */ + P newProject(Map<String, Object> params); + + /** + * + * @param model le model d'ui + * @return le projet instancié (mais non chargé?) + */ + P newProject(ProjectUIModel model); + + /** + * + * @param properties le model d'ui + * @return le projet instancié (mais non chargé?) + */ + P newProject(Properties properties); + + /** + * Decouvre et retourne tous les fichiers de traductions disponibles a + * partir du modele de cration de projet. + * + * @param model le modele a utiliser + * @return la liste des urls des fichiers de traductions trouves a partir + * du modele. + * @throws IOException pour toute erreur + */ + List<URL> detectBundles(ProjectUIModel model) throws IOException; + + /** + * + * @return le type de l'ui pour configurer ce type de projet + */ + Class<? extends I18nProjectConfigurePanelUI<?>> getUIClass(); + + /** + * Valide dans l'ui de creation de projet la partie specifique a + * ce type de projet. + * + * @param model le model a valider + * @return <code>true</code> si la partie specifique a ce type de projet + * est valide, <code>false</code> autrement. + */ + boolean validateUIModel(ProjectUIModel model); + + /** + * Valide un projet a partir de sa definition contenue dans un fichier de + * proprietes. + * + * Cette methode est appellee avant tout chargement de projet en memoire, + * afin de verifier la coherence du projet. + * + * @param properties les proprietes de la definition du projet + * @return <code>true</code> si le projet est valide. + */ + boolean validateDefinition(Properties properties); +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/DirectoryI18nProject.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/DirectoryI18nProject.java new file mode 100644 index 0000000..59e2d94 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/DirectoryI18nProject.java @@ -0,0 +1,67 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.project.impl; + +import java.io.File; +import org.nuiton.i18n.editor.project.AbstractI18nProject; +import java.util.Properties; +import org.nuiton.i18n.editor.project.I18nProject; + +/** + * + * @author chemit + */ +public class DirectoryI18nProject extends AbstractI18nProject { + + public static final String DIRECTORY_SOURCE_PROPERTY_NAME = "directorySource"; + /** la source pour un projet de type directory */ + protected File directorySource = new File(""); + + public DirectoryI18nProject() { + super(); + } + + public File getDirectorySource() { + return directorySource; + } + + public void setDirectorySource(File directorySource) { + File oldValue = this.directorySource; + this.directorySource = directorySource; + firePropertyChange(DIRECTORY_SOURCE_PROPERTY_NAME, oldValue, directorySource); + } + + @Override + public void fillDefinition(Properties p) { + super.fillDefinition(p); + p.setProperty(DIRECTORY_SOURCE_PROPERTY_NAME, directorySource.getAbsolutePath()); + } + + @Override + public void copyDefinitionTo(I18nProject project) { + super.copyDefinitionTo(project); + ((DirectoryI18nProject) project).setDirectorySource(directorySource); + } + + @Override + public void fireAllProperties() { + super.fireAllProperties(); + firePropertyChange(DIRECTORY_SOURCE_PROPERTY_NAME, null, directorySource); + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/DirectoryI18nProjectConfigurePanelUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/DirectoryI18nProjectConfigurePanelUI.jaxx new file mode 100644 index 0000000..d21961e --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/DirectoryI18nProjectConfigurePanelUI.jaxx @@ -0,0 +1,94 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<Table fill='both' constraints='DirectoryI18nProject.class.getName()' + implements='org.nuiton.i18n.editor.project.I18nProjectConfigurePanelUI<DirectoryI18nProject>'> + + <script><![CDATA[ +import jaxx.runtime.SwingUtil; + +import org.nuiton.i18n.editor.*; +import org.nuiton.i18n.editor.project.I18nProject; +import org.nuiton.i18n.editor.project.impl.*; +import org.nuiton.i18n.editor.ui.project.*; + +import java.io.File; + +protected ProjectUIModel model = getContextValue(ProjectUIModel.class); + +protected DirectoryI18nProject project = model.getProject(DirectoryI18nProject.class); + +@Override +public ProjectUIModel getModel() { + return model; +} + +@Override +public DirectoryI18nProject getProject() { + return project; + //I18nProject p = model.getProject(); + //if (p instanceof DirectoryI18nProject) { + // return (DirectoryI18nProject) p; + //} + //return null; +} + +public void chooseDirectorySource() { + File f = model.chooseDirectory( + this, + _("i18neditor.title.choose.directory.source"), + _("i18neditor.action.choose.directory.source.description"), + getProject().getDirectorySource()); + getProject().setDirectorySource(f); +} +]]> + </script> + + <row> + <cell columns="2"> + <JLabel text='i18neditor.createproject.name.label'/> + </cell> + </row> + <row> + <cell columns="2"> + <JTextField text='{SwingUtil.getStringValue(getProject().getName())}' + onKeyReleased='getProject().setName(((JTextField)event.getSource()).getText())'/> + </cell> + </row> + <row> + <cell columns="2"> + <JLabel text='i18neditor.createproject.directory.source.label'/> + </cell> + </row> + <row> + <cell weightx='1' fill="both"> + <JTextField id="directorySourceFile" + text='{SwingUtil.getStringValue(getProject().getDirectorySource()+"")}' + onKeyReleased='getProject().setDirectorySource(new File(((JTextField)event.getSource()).getText()))'/> + </cell> + <cell anchor="east"> + <JButton actionIcon="fileChooser" + onActionPerformed="chooseDirectorySource()"/> + </cell> + </row> +</Table> diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/DirectoryI18nProjectProvider.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/DirectoryI18nProjectProvider.java new file mode 100644 index 0000000..d5b1625 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/DirectoryI18nProjectProvider.java @@ -0,0 +1,124 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.project.impl; + +import java.io.File; +import java.io.IOException; +import org.nuiton.i18n.editor.project.AbstractI18nProjectProvider; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; +import org.nuiton.i18n.I18n; +import org.nuiton.i18n.editor.project.I18nProjectConfigurePanelUI; +import org.nuiton.i18n.editor.ui.project.ProjectUIModel; +import org.nuiton.util.ConverterUtil; + +/** + * + * @author chemit + */ +public class DirectoryI18nProjectProvider extends AbstractI18nProjectProvider<DirectoryI18nProject> { + + public DirectoryI18nProjectProvider() { + super(DirectoryI18nProject.class, I18n.n_("i18neditor.project.type.directory"), I18n.n_("i18neditor.project.type.directory.description")); + } + + @Override + protected Map<String, Class<?>> initAuthorizedParameters() { + Map<String, Class<?>> result = new TreeMap<String, Class<?>>(); + result.put(DirectoryI18nProject.NAME_PROPERTY_NAME, String.class); + result.put(DirectoryI18nProject.URLS_PROPERTY_NAME, List.class); + result.put(DirectoryI18nProject.DIRECTORY_SOURCE_PROPERTY_NAME, File.class); + return result; + } + + @Override + public DirectoryI18nProject newProject() { + return new DirectoryI18nProject(); + } + + @Override + public DirectoryI18nProject newProject(Map<String, Object> params) { + // mandatory parameters + String name = getParameter(String.class, DirectoryI18nProject.NAME_PROPERTY_NAME, params, true); + List<URL> urls = getParameter(List.class, DirectoryI18nProject.URLS_PROPERTY_NAME, params, true); + + // optional parameters + File directorySource = getParameter(File.class, DirectoryI18nProject.DIRECTORY_SOURCE_PROPERTY_NAME, params, false); + + DirectoryI18nProject p = new DirectoryI18nProject(); + p.setName(name); + p.setUrls(urls); + p.setDirectorySource(directorySource); + return p; + } + + @Override + public DirectoryI18nProject newProject(Properties properties) { + Map<String, Object> params = new TreeMap<String, Object>(); + String tmp; + + // name + tmp = properties.getProperty(DirectoryI18nProject.NAME_PROPERTY_NAME); + params.put(DirectoryI18nProject.NAME_PROPERTY_NAME, tmp); + + // urls + tmp = properties.getProperty(DirectoryI18nProject.URLS_PROPERTY_NAME); + String[] urlsStr = tmp.split(","); + List<URL> urls = new ArrayList<URL>(); + for (String u : urlsStr) { + URL url = ConverterUtil.convert(URL.class, u); + urls.add(url); + } + params.put(DirectoryI18nProject.URLS_PROPERTY_NAME, urls); + + // directorySource + tmp = properties.getProperty(DirectoryI18nProject.DIRECTORY_SOURCE_PROPERTY_NAME); + File directorySource = new File(tmp); + params.put(DirectoryI18nProject.DIRECTORY_SOURCE_PROPERTY_NAME, directorySource); + DirectoryI18nProject p = newProject(params); + return p; + } + + @Override + public List<URL> detectBundles(ProjectUIModel model) throws IOException { + //TODO + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean validateUIModel(ProjectUIModel model) { + DirectoryI18nProject project = (DirectoryI18nProject) model.getProject(); + return project.getDirectorySource() != null && project.getDirectorySource().exists() && project.getName() != null && !project.getName().isEmpty(); + } + + @Override + public boolean validateDefinition(Properties properties) { + //TODO + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Class<? extends I18nProjectConfigurePanelUI<?>> getUIClass() { + return DirectoryI18nProjectConfigurePanelUI.class; + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/JarI18nProject.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/JarI18nProject.java new file mode 100644 index 0000000..9e034c2 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/JarI18nProject.java @@ -0,0 +1,86 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.project.impl; + +import java.io.File; +import java.util.Properties; +import org.nuiton.i18n.editor.project.AbstractI18nProject; +import org.nuiton.i18n.editor.project.I18nProject; + +/** + * + * @author chemit + */ +public class JarI18nProject extends AbstractI18nProject { + + public static final String JAR_SOURCE_PROPERTY_NAME = "jarSource"; + public static final String UNIQUE_JAR_DEFINITION_PROPERTY_NAME = "uniqueJarDefinition"; + /** la source pour un projet de type jar */ + protected File jarSource = new File(""); + /** + * un drapeau (pour les projets de type jar) pour savoir si on utilise le + * système i18n avec nom unique. + */ + protected boolean uniqueJarDefinition; + + public JarI18nProject() { + super(); + } + + public File getJarSource() { + return jarSource; + } + + public void setJarSource(File jarSource) { + File oldValue = this.jarSource; + this.jarSource = jarSource; + firePropertyChange(JAR_SOURCE_PROPERTY_NAME, oldValue, jarSource); + } + + public boolean isUniqueJarDefinition() { + return uniqueJarDefinition; + } + + public void setUniqueJarDefinition(boolean uniqueJarDefinition) { + boolean oldValue = this.uniqueJarDefinition; + this.uniqueJarDefinition = uniqueJarDefinition; + firePropertyChange(UNIQUE_JAR_DEFINITION_PROPERTY_NAME, oldValue, uniqueJarDefinition); + } + + @Override + public void fillDefinition(Properties p) { + super.fillDefinition(p); + p.setProperty(JAR_SOURCE_PROPERTY_NAME, jarSource.getAbsolutePath()); + p.setProperty(UNIQUE_JAR_DEFINITION_PROPERTY_NAME, Boolean.valueOf(uniqueJarDefinition).toString()); + } + + @Override + public void copyDefinitionTo(I18nProject project) { + super.copyDefinitionTo(project); + ((JarI18nProject) project).setJarSource(jarSource); + ((JarI18nProject) project).setUniqueJarDefinition(uniqueJarDefinition); + } + + @Override + public void fireAllProperties() { + super.fireAllProperties(); + firePropertyChange(JAR_SOURCE_PROPERTY_NAME, null, jarSource); + firePropertyChange(UNIQUE_JAR_DEFINITION_PROPERTY_NAME, null, uniqueJarDefinition); + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/JarI18nProjectConfigurePanelUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/JarI18nProjectConfigurePanelUI.jaxx new file mode 100644 index 0000000..17aee4b --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/JarI18nProjectConfigurePanelUI.jaxx @@ -0,0 +1,106 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<Table fill='both' constraints='JarI18nProject.class.getName()' + implements='org.nuiton.i18n.editor.project.I18nProjectConfigurePanelUI<JarI18nProject>'> + + <script><![CDATA[ +import jaxx.runtime.SwingUtil; + +import org.nuiton.i18n.editor.*; +import org.nuiton.i18n.editor.project.I18nProject; +import org.nuiton.i18n.editor.project.impl.*; +import org.nuiton.i18n.editor.ui.project.*; + +import java.io.File; + +protected ProjectUIModel model = getContextValue(ProjectUIModel.class); + +protected JarI18nProject project = model.getProject(JarI18nProject.class); + +@Override +public ProjectUIModel getModel() { + return model; +} + +@Override +public JarI18nProject getProject() { + return project; + //I18nProject p = model.getProject(); + //if (p instanceof JarI18nProject) { + // return (JarI18nProject) p; + //} + //return null; +} + +public void chooseJarSource() { + File f = model.chooseFile ( + this, + _("i18neditor.title.choose.jar.source"), + _("i18neditor.action.choose.jar.source"), + getProject().getJarSource(), + "^.+\\.jar$", + _("i18neditor.action.choose.jar.source.description")); + getProject().setJarSource(f); +} +]]> + </script> + + <row> + <cell columns="2"> + <JLabel text='i18neditor.createproject.name.label'/> + </cell> + </row> + <row> + <cell columns="2"> + <JTextField text='{SwingUtil.getStringValue(getProject().getName())}' + onKeyReleased='getProject().setName(((JTextField)event.getSource()).getText())'/> + </cell> + </row> + <row> + <cell columns="2"> + <JLabel text='i18neditor.createproject.jar.source.label'/> + </cell> + </row> + <row> + <cell weightx='1' fill="both"> + <JTextField id="jarSourceFile" + text='{SwingUtil.getStringValue(getProject().getJarSource()+"")}' + onKeyReleased='getProject().setJarSource(new File(((JTextField)event.getSource()).getText()))'/> + </cell> + <cell anchor="east"> + <JButton actionIcon="fileChooser" + onActionPerformed="chooseJarSource()"/> + </cell> + </row> + <row> + <cell columns="2"> + <JCheckBox id='uniqueJarDefinition' + text='i18neditor.createproject.uniqueJarDefinition' + toolTipText='i18neditor.createproject.uniqueJarDefinition.tip' + selected='{getProject().isUniqueJarDefinition()}' + onItemStateChanged='getProject().setUniqueJarDefinition(event.getStateChange() == ItemEvent.SELECTED)'/> + </cell> + </row> +</Table> + diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/JarI18nProjectProvider.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/JarI18nProjectProvider.java new file mode 100644 index 0000000..828da7a --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/project/impl/JarI18nProjectProvider.java @@ -0,0 +1,186 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.project.impl; + +import java.io.File; +import java.io.IOException; +import org.nuiton.i18n.editor.project.AbstractI18nProjectProvider; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.i18n.I18n; +import org.nuiton.i18n.bundle.I18nBundleFactory; +import org.nuiton.i18n.editor.project.I18nProjectConfigurePanelUI; +import org.nuiton.i18n.editor.ui.project.ProjectUIModel; +import org.nuiton.util.ConverterUtil; +import org.nuiton.util.Resource; + +/** + * + * @author chemit + */ +public class JarI18nProjectProvider extends AbstractI18nProjectProvider<JarI18nProject> { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(JarI18nProjectProvider.class); + + public JarI18nProjectProvider() { + super(JarI18nProject.class, + I18n.n_("i18neditor.project.type.jar"), + I18n.n_("i18neditor.project.type.jar.description")); + } + + @Override + protected Map<String, Class<?>> initAuthorizedParameters() { + Map<String, Class<?>> result = new TreeMap<String, Class<?>>(); + result.put(JarI18nProject.NAME_PROPERTY_NAME, String.class); + result.put(JarI18nProject.URLS_PROPERTY_NAME, List.class); + result.put(JarI18nProject.JAR_SOURCE_PROPERTY_NAME, File.class); + result.put(JarI18nProject.UNIQUE_JAR_DEFINITION_PROPERTY_NAME, Boolean.class); + return result; + } + + @Override + public JarI18nProject newProject() { + return new JarI18nProject(); + } + + @Override + public JarI18nProject newProject(Map<String, Object> params) { + + // mandatory parameters + String name = getParameter(String.class, JarI18nProject.NAME_PROPERTY_NAME, params, true); + List<URL> urls = getParameter(List.class, JarI18nProject.URLS_PROPERTY_NAME, params, true); + + // optional parameters + File jarSource = getParameter(File.class, JarI18nProject.JAR_SOURCE_PROPERTY_NAME, params, false); + Boolean uniqueJarDefinition = getParameter(Boolean.class, JarI18nProject.UNIQUE_JAR_DEFINITION_PROPERTY_NAME, params, false); + JarI18nProject p = new JarI18nProject(); + p.setName(name); + p.setUrls(urls); + p.setJarSource(jarSource); + p.setUniqueJarDefinition(uniqueJarDefinition != null && uniqueJarDefinition); + return p; + } + + @Override + public JarI18nProject newProject(Properties properties) { + Map<String, Object> params = new TreeMap<String, Object>(); + String tmp; + + // name + tmp = properties.getProperty(JarI18nProject.NAME_PROPERTY_NAME); + params.put(JarI18nProject.NAME_PROPERTY_NAME, tmp); + + // urls + tmp = properties.getProperty(JarI18nProject.URLS_PROPERTY_NAME); + String[] urlsStr = tmp.split(","); + List<URL> urls = new ArrayList<URL>(); + for (String u : urlsStr) { + URL url = ConverterUtil.convert(URL.class, u); + urls.add(url); + } + params.put(JarI18nProject.URLS_PROPERTY_NAME, urls); + + // jarSource + tmp = properties.getProperty(JarI18nProject.JAR_SOURCE_PROPERTY_NAME); + File jarSource = new File(tmp); + params.put(JarI18nProject.JAR_SOURCE_PROPERTY_NAME, jarSource); + + // uniqueJarDefinition + tmp = properties.getProperty(JarI18nProject.UNIQUE_JAR_DEFINITION_PROPERTY_NAME, "false"); + Boolean uniqueJarDefinition = Boolean.valueOf(tmp); + params.put(JarI18nProject.UNIQUE_JAR_DEFINITION_PROPERTY_NAME, uniqueJarDefinition); + + JarI18nProject p = newProject(params); + return p; + } + + @Override + public List<URL> detectBundles(ProjectUIModel model) throws IOException { + List<URL> urls = new ArrayList<URL>(); + JarI18nProject project = (JarI18nProject) model.getProject(); + URL source = project.getJarSource().toURI().toURL(); + URLClassLoader loader = new URLClassLoader(new URL[]{source}); + log.info("jar source : " + source); + if (project.isUniqueJarDefinition()) { + // on recherche l'unique bundle dans META-INF/ + List<URL> defs = Resource.getURLs("META-INF/.*-i18n-definition\\.properties", loader); + log.info("detected unique bundle definition " + defs); + if (!defs.isEmpty()) { + // on ne traite que le premier ??? + URL u = defs.get(0); + String path = u.toString(); + int index = path.lastIndexOf("/"); + path = path.substring(index + 1); + String bundleName = path.substring(0, path.length() - "-i18n-definition.properties".length()); + log.info("bundleName : " + bundleName); + urls = Resource.getURLs("META-INF/" + bundleName + "-.*\\.properties", loader); + urls.remove(u); + } + } else { + urls = Resource.getURLs(I18nBundleFactory.SEARCH_BUNDLE_PATTERN, loader); + log.info("detected bundles : " + urls); + } + return urls; + } + + @Override + public boolean validateUIModel(ProjectUIModel model) { + JarI18nProject project = (JarI18nProject) model.getProject(); + return project.getJarSource() != null && project.getJarSource().exists() && project.getName() != null && !project.getName().isEmpty(); + } + + @Override + public boolean validateDefinition(Properties properties) { + + // verifie que les proprietes sont presentes : + if (!properties.containsKey(CLASS_PARAMETER)) { + throw new IllegalStateException("could not find property " + CLASS_PARAMETER); + } + if (!properties.containsKey(JarI18nProject.NAME_PROPERTY_NAME)) { + throw new IllegalStateException("could not find property " + JarI18nProject.NAME_PROPERTY_NAME); + } + if (!properties.containsKey(JarI18nProject.URLS_PROPERTY_NAME)) { + throw new IllegalStateException("could not find property " + JarI18nProject.URLS_PROPERTY_NAME); + } + // verifie que les urls existent + String tmp = properties.getProperty(JarI18nProject.URLS_PROPERTY_NAME); + String[] urlsStr = tmp.split(","); + for (String u : urlsStr) { + int lastIndex = u.lastIndexOf("/"); + u = u.substring(0, lastIndex); + URL url = ConverterUtil.convert(URL.class, u); + // check if url is an existing file + log.info(url + " to check"); + } + return false; + } + + @Override + public Class<? extends I18nProjectConfigurePanelUI<?>> getUIClass() { + return JarI18nProjectConfigurePanelUI.class; + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/BundleCheckBoxMenuUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/BundleCheckBoxMenuUI.jaxx new file mode 100644 index 0000000..ecebe70 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/BundleCheckBoxMenuUI.jaxx @@ -0,0 +1,56 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<JCheckBoxMenuItem id='content' text='{getBundle().getDisplayName()}' toolTipText='{_("i18neditor.bundle.name", getBundle().getDisplayName())}' onItemStateChanged='updateState(event)'> + + <!-- le nom du bundle --> + <Locale id='bundle' javaBean='Locale.FRANCE'/> + + <script><![CDATA[ +import org.nuiton.i18n.editor.*; +import java.util.Locale; +import jaxx.runtime.JAXXContext; + +public BundleCheckBoxMenuUI(JAXXContext parentContext, Locale bundle, boolean selected) { + super(null, selected); + setContextValue(parentContext); + setBundle(bundle); +} + +protected void updateState(ItemEvent e) { + I18nEditorContext context = getContextValue(I18nEditorContext.class); + if (context == null) { + // pas encore de context (ui en construction) + return; + } + boolean selected = e.getStateChange() == ItemEvent.SELECTED; + if (selected) { + context.addSelectedBundle(bundle); + } else { + context.removeSelectedBundle(bundle); + } +} +]]> + </script> + +</JCheckBoxMenuItem> diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/BundleValueUI.css b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/BundleValueUI.css new file mode 100644 index 0000000..d95ab1e --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/BundleValueUI.css @@ -0,0 +1,52 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +JToolBar { + borderPainted:false; + floatable:false; + opaque:false; +} + +#reset { + actionIcon:"cancel"; + toolTipText:"i18neditor.action.reset.value.tip"; + enabled:{isModified()}; +} +#delete{ + actionIcon:"delete"; + toolTipText:"i18neditor.action.delete.key.tip"; +} +#save { + actionIcon:"save"; + toolTipText:"i18neditor.action.save.value.tip"; + enabled:{isModified()}; +} + +#label { + text:{updateLabel(getBundle())}; +} + +#editorPane { + columnHeaderView:{toolbar}; +} + +#editor { + wrapStyleWord:true; + lineWrap:true; + text:{SwingUtil.getStringValue(getInitialValue())}; +} \ No newline at end of file diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/BundleValueUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/BundleValueUI.jaxx new file mode 100644 index 0000000..2fdf5ce --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/BundleValueUI.jaxx @@ -0,0 +1,87 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<JPanel layout='{new BorderLayout()}'> + + <style source='BundleValueUI.css'/> + + <!-- la locale --> + <Locale id='bundle' javaBean='null'/> + + <!-- le nom du package --> + <String id='packageName' javaBean='null'/> + + <!-- la clef --> + <String id='key' javaBean='null'/> + + <!-- la valeur initiale --> + <String id='initialValue' javaBean='null'/> + + <Boolean id='modified' javaBean='Boolean.FALSE'/> + + <script><![CDATA[ +import java.util.Locale; +import jaxx.runtime.SwingUtil; +import org.nuiton.i18n.editor.*; + +protected I18nEditorUIHandler handler = getContextValue(I18nEditorUIHandler.class); +protected I18nEditorContext context = getContextValue(I18nEditorContext.class); + +public void updateValue(String newValue) { + if (initialValue.equals(newValue)) { + // valeur non changee + return; + } + setModified(true); +} + +protected String updateLabel(Locale l) { + String result = null; + if (l != null) { + result = _("i18neditor.bundle.name", l.getDisplayName()); + } + return result; +} + +protected String getValue() { + return editor.getText(); +} +]]> + </script> + + <JToolBar id='toolbar'> + + <JLabel id='label'/> + + <javax.swing.Box.Filler constructorParams='SwingUtil.newMinDimension(), SwingUtil.newMinDimension(), SwingUtil.newMaxXDimension()'/> + + <JButton id='delete' onActionPerformed='handler.deleteSelectedValueForLocale(context, this, packageName, bundle, key)'/> + <JButton id='reset' onActionPerformed='String t = initialValue; initialValue=null; setInitialValue(t);setModified(false);'/> + <JButton id='save' onActionPerformed='handler.updateSelectedValue(context, packageName, bundle, key, getValue()); initialValue = getValue();setModified(false);'/> + </JToolBar> + + <JScrollPane id='editorPane' constraints='BorderLayout.CENTER'> + <JTextArea id='editor' + onKeyReleased='updateValue(((JTextArea) event.getSource()).getText())'/> + </JScrollPane> +</JPanel> \ No newline at end of file diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/BundleValuesUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/BundleValuesUI.jaxx new file mode 100644 index 0000000..a2a17ae --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/BundleValuesUI.jaxx @@ -0,0 +1,54 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<org.jdesktop.swingx.JXTitledPanel id='content' + title='{updateTitle(getPackageName())}'> + + <!-- les locales --> + <java.util.List id='bundles' javaBean='null' genericType='Locale'/> + + <!-- le nom du package --> + <String id='packageName' javaBean='null'/> + + <!-- le nom de la cef --> + <String id='key' javaBean='null'/> + + <script><![CDATA[ +protected String updateTitle(String l) { + String result = ""; + if (l != null) { + int index = l.lastIndexOf("/"); + if (index > -1) { + l = l.substring(index + 1); + } + result = _("i18neditor.package.name", l); + } + return result; +} +]]> + </script> + <JPanel id='bundlesContent' + layout='{new GridLayout(0,1)}' + border='{BorderFactory.createTitledBorder((String)null)}' + preferredSize='{new Dimension(-1, 150)}'/> +</org.jdesktop.swingx.JXTitledPanel> diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/CreateBundleUI.css b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/CreateBundleUI.css new file mode 100644 index 0000000..6894a10 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/CreateBundleUI.css @@ -0,0 +1,43 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +#countryLabel { + text:"i18neditor.createbundle.newlocale"; + labelFor:{country}; +} + +#languageLabel { + text:"i18neditor.createbundle.newlanguage"; + labelFor:{language}; +} + +#label { + text:"i18neditor.createbundle.label"; +} +#buttonCancel { + text:"i18neditor.action.cancel"; +} + +#buttonCreate{ + text:"i18neditor.action.create"; +} + +#main { + title:"i18neditor.createbundle.title"; + modal:true; +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/CreateBundleUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/CreateBundleUI.jaxx new file mode 100644 index 0000000..eb0833f --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/CreateBundleUI.jaxx @@ -0,0 +1,80 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<JDialog id='main'> + + <style source='CreateBundleUI.css'/> + + <String id='bundle'/> + <script><![CDATA[ +import java.util.Locale; +import org.nuiton.i18n.editor.*; + +public boolean acceptLocale(Locale l, String expected) { + return l !=null && l.toString().equals(expected); +} + +public I18nEditorUIHandler getHandler() { + return getContextValue(I18nEditorUIHandler.class); +} + +protected I18nEditorContext getContext() { + return I18nEditorContext.get(); +} + +void $afterCompleteSetup() { + + //getBroker().setHandler(getHandler()); +} +]]> + </script> + <JPanel layout='{new BorderLayout()}'> + <JPanel constraints='BorderLayout.NORTH' background='{Color.WHITE}'> + <JLabel id='label'/> + </JPanel> + + <Table fill="both" constraints='BorderLayout.CENTER'> + <row weightx="1" weighty="1"> + <cell> + <JLabel id='languageLabel'/> + </cell> + <cell> + <jaxx.runtime.swing.editor.EnumEditor id='language' constructorParams='org.nuiton.i18n.LanguageEnum.class'/> + </cell> + </row> + <row weightx="1" weighty="1"> + <cell> + <JLabel id='countryLabel'/> + </cell> + <cell> + <jaxx.runtime.swing.editor.EnumEditor id='country' constructorParams='org.nuiton.i18n.CountryEnum.class'/> + </cell> + </row> + </Table> + + <JPanel constraints='BorderLayout.SOUTH' layout='{new GridLayout()}'> + <JButton id='buttonCancel' onActionPerformed='bundle = null;dispose();'/> + <JButton id='buttonCreate' onActionPerformed='getContext().createBundle(bundle = language.getSelectedItem() + "_" + country.getSelectedItem());dispose();'/> + </JPanel> + </JPanel> +</JDialog> diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/CreatePackageUI.css b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/CreatePackageUI.css new file mode 100644 index 0000000..2722155 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/CreatePackageUI.css @@ -0,0 +1,40 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +#packageLabel { + text:"i18neditor.createpackage.newpackage"; + labelFor:{packageName}; +} + +#label { + text:"i18neditor.createpackage.label"; +} + +#buttonCancel { + text:"i18neditor.action.cancel"; +} + +#buttonCreate{ + text:"i18neditor.action.create"; +} + +#main { + title:"i18neditor.createpackage.title"; + modal:true; +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/CreatePackageUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/CreatePackageUI.jaxx new file mode 100644 index 0000000..b2ac183 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/CreatePackageUI.jaxx @@ -0,0 +1,72 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<JDialog id='main'> + + <style source='CreatePackageUI.css'/> + + <String id='bundle'/> + <script><![CDATA[ +import java.util.Locale; +import org.nuiton.i18n.editor.*; + +public boolean acceptLocale(Locale l, String expected) { + return l !=null && l.toString().equals(expected); +} + +public I18nEditorUIHandler getHandler() { + return getContextValue(I18nEditorUIHandler.class); +} + +protected I18nEditorContext getContext() { + return I18nEditorContext.get(); +} + +void $afterCompleteSetup() { + + //getBroker().setHandler(getHandler()); +} +]]> + </script> + <JPanel layout='{new BorderLayout()}'> + <JPanel constraints='BorderLayout.NORTH' background='{Color.WHITE}'> + <JLabel id='label'/> + </JPanel> + + <Table fill="both" constraints='BorderLayout.CENTER'> + <row weightx="1" weighty="1"> + <cell> + <JLabel id='packageLabel'/> + </cell> + <cell> + <JTextField id='packageName'/> + </cell> + </row> + </Table> + + <JPanel constraints='BorderLayout.SOUTH' layout='{new GridLayout()}'> + <JButton id='buttonCancel' onActionPerformed='bundle = null;dispose();'/> + <JButton id='buttonCreate' onActionPerformed='getContext().createPackage(bundle = packageName.getText());dispose();'/> + </JPanel> + </JPanel> +</JDialog> diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/I18nEditorUI.css b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/I18nEditorUI.css new file mode 100644 index 0000000..3b92b28 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/I18nEditorUI.css @@ -0,0 +1,260 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* +*/ + +JToolBar { + borderPainted:false; + floatable:false; + opaque:false; +} + +JSplitPane { + oneTouchExpandable:true; + continuousLayout:true; + dividerSize:6; +} + +#mainFrame { + defaultCloseOperation:"do_nothing_on_close"; + title:{updateTitle(context.getProject())}; +/*iconImage:{createImageIcon("logo-OT_web.png").getImage()};*/ +} + +#menu { + _help:{"ui.main.menu"}; +} + +#menuFile { + text:"i18neditor.main.menu.file"; + mnemonic:F; + _help:{"ui.main.menu.file"}; +} + +#menuFileConfiguration { + text:"i18neditor.action.configuration"; + toolTipText:"i18neditor.action.configuration.tip"; + actionIcon:"config"; + mnemonic:C; + _help:{"ui.main.menu.file.configuration"}; +} + +#menuFileEditProject { + text:"i18neditor.action.editProject"; + actionIcon:"edit"; + enabled:{context.getProject() != null}; +} + +#menuFileCreateProject { + text:"i18neditor.action.createProject"; + actionIcon:"add"; + enabled:{context.getProject() == null}; +} + +#menuFileOpenProject { + text:"i18neditor.action.openProject"; + actionIcon:"open"; + enabled:{context.getProject() == null}; +} + +#menuFileOpenProjectOther{ + text:"i18neditor.action.openOtherProject"; + actionIcon:"open"; +} + +#menuFileDeleteProject{ + text:"i18neditor.action.deleteProject"; + actionIcon:"delete"; +} + +#menuFileCloseProject { + text:"i18neditor.action.closeProject"; + actionIcon:"close"; + enabled:{context.getProject() != null}; +} +#menuFileStore { + text:"i18neditor.menu.storeall"; + actionIcon:"save"; + enabled:{context.getProject() != null}; +} + +#menuFileFullscreen { + text:"i18neditor.action.fullscreen"; + toolTipText:"i18neditor.action.fullscreen.tip"; + actionIcon:"fullscreen"; + mnemonic:P; + visible:{!isUndecorated()}; +_help:{"ui.main.menu.file.fullscreen"}; +} + +#menuFileNormalscreen { + text:"i18neditor.action.normalscreen"; + toolTipText:"i18neditor.action.normalscreen.tip"; + actionIcon:"leave-fullscreen"; + mnemonic:N; + visible:{isUndecorated()}; +_help:{"ui.main.menu.file.leave-fullscreen"}; +} + +#menuFileQuit{ + text:"i18neditor.action.exit"; + toolTipText:"i18neditor.action.exit.tip"; + actionIcon:"exit"; + mnemonic:X; + _help:{"ui.main.menu.file.exit"}; +} + +#menuPackages { + text:"i18neditor.menu.packages" ; + mnemonic:P; + enabled:{context.getProject() != null}; +} + +#menuPackagesCreate { + text:"i18neditor.action.new.package" ; + actionIcon:"add"; + mnemonic:N; +} + +#menuBundles { + text:"i18neditor.menu.bundles"; + mnemonic:B; + enabled:{context.getProject() != null}; +} + +#menuBundlesCreate { + text:"i18neditor.action.new.bundle" ; + actionIcon:"add"; + mnemonic:N; +} + + +#menuHelp{ + text:"i18neditor.menu.help"; + mnemonic:e; + _help:{"ui.main.menu.help"}; +} + +#menuHelpHelp{ + text:"i18neditor.action.help"; + toolTipText:"i18neditor.action.help.tip"; + actionIcon:"help"; + mnemonic:e; + _help:{"ui.main.menu.help.help"}; +} + +#menuHelpSite{ + text:"i18neditor.action.site"; + toolTipText:"i18neditor.action.site.tip"; + actionIcon:"site"; + mnemonic:s; + _help:{"ui.main.menu.help.site"}; +} + +#menuHelpAbout{ + text:"i18neditor.action.about"; + toolTipText:"i18neditor.action.about.tip"; + actionIcon:"about"; + mnemonic:A; + _help:{"ui.main.menu.help.about"}; +} + +#showHelp{ + toolTipText:"i18neditor.action.showHelp.tip"; + actionIcon:"show-help"; + borderPainted:false; + visible:true; +} + +#showProjectInfo { + actionIcon:"information"; + toolTipText:"i18neditor.project.info.tip"; + borderPainted:false; + rolloverEnabled:false; +} + +#closeTab{ + actionIcon:"closeTab"; + borderPainted:false; + rolloverEnabled:false; + focusable:false; + toolTipText:"i18neditor.action.quitHelp.tip"; + _help:{"ui.main.body.help.closeTab"}; +} + +#keysView{ + _help:{"ui.main.body.view.keys"}; +} + +#valuesView{ + _help:{"ui.main.body.view.values"}; +} + +#splitpane{ + orientation:{JSplitPane.HORIZONTAL_SPLIT}; +_help:{"ui.main.body.db"}; +/*resizeWeight:1.0;*/ +} + +#toolbar{ + _help:{"ui.main.toolbar"}; +} + +#treeToolBar{ + enabled:{context.getProject() != null}; +} + +#toTreeMode { + + buttonGroup:"treeModelMode"; + text:{TreeModelMode.TREE.toString()}; +enabled:{context.getProject() != null}; +selected:{context.getTreeModelMode() == TreeModelMode.TREE}; +value:{TreeModelMode.TREE}; +} + +#toFlatMode { + buttonGroup:"treeModelMode"; + text:{TreeModelMode.FLAT.toString()}; +enabled:{context.getProject() != null}; +selected:{context.getTreeModelMode() == TreeModelMode.FLAT}; +value:{TreeModelMode.FLAT}; +} + +#collapseAll { + actionIcon:"collapseAll"; + enabled:{context.getProject() != null && context.getSelectedKey() != null}; +} + +#expandAll{ + actionIcon:"expandAll"; + enabled:{context.getProject() != null && context.getSelectedKey() != null}; +} + +#keysView { + columnHeaderView:{treeToolBar}; +} + +#tree{ + showsRootHandles:false; + rootVisible:false; + selectionModel:{treeSelectionModel}; +} + +#valuesView { + horizontalScrollBarPolicy:horizontal_scrollbar_never; +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/I18nEditorUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/I18nEditorUI.jaxx new file mode 100644 index 0000000..012e587 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/I18nEditorUI.jaxx @@ -0,0 +1,343 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<JFrame id='mainFrame' implements='PropertyChangeListener' + width='800' + height='800' + onWindowClosing='handler.close(context)' + undecorated='{config.isFullScreen()}'> + + <style source='I18nEditorUI.css'/> + + <script><![CDATA[ +import jaxx.runtime.SwingUtil; +import javax.swing.tree.*; +import java.util.Locale; +import org.nuiton.i18n.editor.*; +import org.nuiton.i18n.editor.project.I18nProject; + +protected I18nEditorUIHandler handler = getContextValue(I18nEditorUIHandler.class); +protected I18nEditorConfig config = getContextValue(I18nEditorConfig.class); +protected I18nEditorContext context = getContextValue(I18nEditorContext.class); + +@Override +public void propertyChange(PropertyChangeEvent evt) { + String name = evt.getPropertyName(); + if (log.isDebugEnabled()) { + log.debug(name+" <old:"+evt.getOldValue()+" - new:"+evt.getNewValue()+">"); + } +// log.info(name+" <old:"+evt.getOldValue()+" - new:"+evt.getNewValue()+">"); + if (I18nEditorContext.SELECTED_KEY_PROPERTY.equals(name)) { + // mise a jour du menu packages + String newValue = (String) evt.getNewValue(); + handler.reloadValues(this, newValue); + selectKeyInTree(newValue); + return; + } + if (I18nEditorContext.PROJECT_PROPERTY.equals(name)) { + I18nProject newValue = (I18nProject) evt.getNewValue(); + I18nProject oldValue = (I18nProject) evt.getOldValue(); + if (newValue != null) { + handler.openProjectUI( this, newValue); + } else { + handler.closeProjectUI( this, oldValue); + } + return; + } + if (I18nEditorContext.SELECTED_BUNDLES_PROPERTY.equals(name)) { + context.saveSelectedKey(); + handler.reloadKeys(this); + handler.reloadValues(this); + return; + } + if (I18nEditorContext.SELECTED_PACKAGES_PROPERTY.equals(name)) { + context.saveSelectedKey(); + handler.reloadKeys(this); + handler.reloadValues(this); + return; + } + if (I18nEditorContext.TREE_MODEL_MODE_PROPERTY.equals(name)) { + handler.reloadKeys(this); + handler.reloadValues(this); + return; + } + if (jaxx.runtime.swing.editor.I18nEditor.SELECTED_LOCALE_PROPERTY.equals(name)) { + // mise a jour du menu packages + Locale newValue = (Locale) evt.getNewValue(); + handler.changeLanguage(context, newValue); + return; + } + if ("projects".equals(name)) { + // mise a jour du menu projects + handler.updateProjectsMenuUI(context); + return; + } +} + +public String updateTitle(I18nProject p) { + String txt = null; + if (p==null) { + txt = _("i18neditor.title.noproject"); + } else { + txt = _("i18neditor.title", p.getName() + " - " + p.getStoreFile()); + } + return txt; +} +public void updateSelectedKey(PropertieNode node) { + String key = null; + if (node == null && !treeSelectionModel.isSelectionEmpty()) { + node = (PropertieNode) tree.getSelectionPath().getLastPathComponent(); + } + if (node != null) { + key = node.getUserObject().toString(); + } + log.debug(node + " : " + key); + context.setSelectedKey(key); +} + +public void selectKeyInTree(final String selectedKey) { + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + log.debug("selectKeyInTree ==========================================================="); + if (selectedKey == null) { + // pas de clef selectionnee + log.debug("no key to select (selectedKey null or not in model)!"); + if (!treeSelectionModel.isSelectionEmpty()) { + // on vide la selection dans l'arbre + treeSelectionModel.clearSelection(); + } + return; + } + log.debug("reselected key " + selectedKey); + PropertieNode selectedNode = treeModel.getNode(selectedKey); + log.debug("reselected node " + selectedNode); + TreePath path = new TreePath(treeModel.getPathToRoot(selectedNode)); + log.debug("reselected path " + path); + tree.setSelectionPath(path); + tree.scrollPathToVisible(path); + TreePath leadSelectionPath = treeSelectionModel.getLeadSelectionPath(); + log.debug("new selected path " + leadSelectionPath); + log.debug("selectKeyInTree ==========================================================="); + } + }); +} + +public void collapseAll(final PropertieNode node) { + if (node != null) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + TreePath path = new TreePath(treeModel.getPathToRoot(node)); + if (path != null) { + tree.collapsePath(path); + //TODO faire un collapse recursive + } + } + }); + } +} + +public void expandAll(final PropertieNode node) { + if (node != null) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + TreePath path = new TreePath(treeModel.getPathToRoot(node)); + if (path != null) { + tree.expandPath(path); + //TODO faire un expand recursive + } + } + }); + } +} + +public I18nEditorContext getContext() { + return context; +} + +@Override +public void dispose() { + super.dispose(); + context.removePropertyChangeListener(I18nEditorContext.SELECTED_PACKAGES_PROPERTY, this); + context.removePropertyChangeListener(I18nEditorContext.SELECTED_BUNDLES_PROPERTY, this); + context.removePropertyChangeListener(I18nEditorContext.SELECTED_KEY_PROPERTY, this); + context.removePropertyChangeListener(I18nEditorContext.PROJECT_PROPERTY, this); + context.removePropertyChangeListener(I18nEditorContext.TREE_MODEL_MODE_PROPERTY, this); + context.removePropertyChangeListener("projects", this); + context.removePropertyChangeListener(this); +} + +// register listeners +changeI18n.addPropertyChangeListener(jaxx.runtime.swing.editor.I18nEditor.SELECTED_LOCALE_PROPERTY, this); +context.addPropertyChangeListener(I18nEditorContext.SELECTED_PACKAGES_PROPERTY, this); +context.addPropertyChangeListener(I18nEditorContext.SELECTED_BUNDLES_PROPERTY, this); +context.addPropertyChangeListener(I18nEditorContext.SELECTED_KEY_PROPERTY, this); +context.addPropertyChangeListener(I18nEditorContext.PROJECT_PROPERTY, this); +context.addPropertyChangeListener(I18nEditorContext.TREE_MODEL_MODE_PROPERTY, this); +context.addPropertyChangeListener("projects", this); + +treeSelectionModel.addTreeSelectionListener(new TreeSelectionListener() { + + @Override + public void valueChanged(TreeSelectionEvent e) { + TreePath path = e.getPath(); + TreeNode node = (TreeNode) path.getLastPathComponent(); + log.debug(path + " " + node.isLeaf()); + if (!node.isLeaf() && !tree.isExpanded(path)) { + // expand the node to avoid a click :) + log.info("expand path " + path); + tree.expandPath(path); + } + } +}); + +// register help broker +//broker.setHandler(handler); + +]]> + </script> + <JMenuBar> + <JMenu id='menuFile'> + <JMenuItem id='menuFileConfiguration' onActionPerformed="handler.showConfig(context)"/> + <JMenuItem id="menuFileCreateProject" onActionPerformed="handler.createProject(context)"/> + <JMenuItem id="menuFileEditProject" onActionPerformed="handler.editProject(context)"/> + <JMenu id="menuFileOpenProject"> + <JMenuItem id="menuFileOpenProjectOther" + onActionPerformed="handler.openOtherProject(context)" + _doNotRemove='Boolean.TRUE'/> + <JMenuItem id="menuFileDeleteProject" + onActionPerformed="handler.deleteProject(context)" + _doNotRemove='Boolean.TRUE'/> + <JSeparator/> + </JMenu> + + <JMenuItem id="menuFileStore" onActionPerformed="context.store()"/> + <JMenuItem id="menuFileCloseProject" onActionPerformed="handler.closeProject(context, context.getProject())"/> + <JSeparator/> + <JMenuItem id='menuFileFullscreen' onActionPerformed="handler.changeScreen(context, true)"/> + <JMenuItem id='menuFileNormalscreen' onActionPerformed="handler.changeScreen(context, false)"/> + <JSeparator/> + <JMenuItem id="menuFileQuit" onActionPerformed="handler.close(context)"/> + </JMenu> + <JMenu id='menuPackages'> + <JMenuItem id="menuPackagesCreate" onActionPerformed="handler.createPackage(context)"/> + <JSeparator/> + </JMenu> + <JMenu id='menuBundles'> + <JMenuItem id="menuBundlesCreate" onActionPerformed="handler.createBundle(context)"/> + <JSeparator/> + </JMenu> + <JMenu id='menuHelp'> + <JMenuItem id='menuHelpHelp' onActionPerformed="handler.showHelp(context, null)"/> + <JMenuItem id='menuHelpSite' onActionPerformed="handler.gotoSite(context)"/> + <JMenuItem id='menuHelpAbout' onActionPerformed="handler.showAbout(context)"/> + </JMenu> + <JToolBar id='toolbar' _help='"ui.main.toolbar"'> + + <JButton id='showHelp'/> + + <javax.swing.Box.Filler constructorParams='SwingUtil.newMinDimension(), SwingUtil.newMinDimension(), SwingUtil.newMaxXDimension()'/> + <JSeparator orientation='vertical'/> + <JButton id='showProjectInfo' onActionPerformed='handler.showStorageInfo(context)'/> + + <jaxx.runtime.swing.editor.I18nEditor id='changeI18n' + opaque='false' + showText='false' + locales='{java.util.Arrays.asList(org.nuiton.i18n.I18n.getLoader().getLocales())}' + selectedLocale='{config.getLocale()}'/> + </JToolBar> + </JMenuBar> + + <ButtonGroup id='treeModelMode' + onStateChanged='handler.changeTreeModelMode(context, (TreeModelMode) treeModelMode.getSelectedValue())'/> + + <JToolBar id='treeToolBar'> + <JToggleButton id='toTreeMode'/> + <JToggleButton id='toFlatMode'/> + <JSeparator orientation='vertical'/> + <javax.swing.Box.Filler constructorParams='SwingUtil.newMinDimension(), SwingUtil.newMinDimension(), SwingUtil.newMaxXDimension()'/> + <JButton id='collapseAll' onActionPerformed='collapseAll((PropertieNode)tree.getSelectionValue())'/> + <JButton id='expandAll' onActionPerformed='expandAll((PropertieNode)tree.getSelectionValue())'/> + </JToolBar> + + <PropertiesTreeModel id='treeModel' mode='{context.getTreeModelMode()}'/> + + <javax.swing.tree.DefaultTreeSelectionModel id='treeSelectionModel'/> + <!--onValueChanged='updateSelectedKey((PropertieNode) tree.getSelectionValue())'/--> + + <JSplitPane id='splitpane' constraints="BorderLayout.CENTER"> + + <!-- left : bundles keys --> + + <!--JScrollPane id='keysView' columnHeaderView='{treeToolBar}'--> + <JScrollPane id='keysView'> + <JTree id="tree" constructorParams='treeModel' + onKeyReleased='updateSelectedKey((PropertieNode) tree.getSelectionValue())' + onMouseClicked='updateSelectedKey((PropertieNode) tree.getSelectionValue())' + cellRenderer='{ + new DefaultTreeCellRenderer() { + private static final long serialVersionUID=1L; + + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + PropertieNode n = (PropertieNode) value; + if (n != null) { + String text = n.toString(); + switch(getTreeModel().getMode()) { + case TREE: + if (!n.isRoot()) { + int lastSeparator = text.lastIndexOf("."); + text = text.substring(lastSeparator + 1); + } + break; + case FLAT: + break; + } + value = text; + } + return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + } + + } + }'/> + </JScrollPane> + + + <!-- right : bundles values (for the selected key) --> + + <!--JScrollPane id='valuesView' horizontalScrollBarPolicy="horizontal_scrollbar_never"--> + <JScrollPane id='valuesView'> + <JPanel id="values" layout='{new GridLayout(0,1)}'/> + </JScrollPane> + + </JSplitPane> + + <!-- status message bar --> + <jaxx.runtime.swing.StatusMessagePanel id='status' + _help='"ui.main.statusBar"' + constraints="BorderLayout.SOUTH"/> + +</JFrame> diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/I18nEditorUIHandler.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/I18nEditorUIHandler.java new file mode 100644 index 0000000..33d1305 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/I18nEditorUIHandler.java @@ -0,0 +1,937 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.ui; + +import java.awt.Component; +import java.awt.Container; +import java.awt.event.ActionEvent; +import java.io.IOException; +import java.util.Map; +import java.util.Set; +import javax.swing.JMenu; +import org.nuiton.i18n.editor.*; +import java.awt.Desktop; +import java.io.File; +import java.io.FileInputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import jaxx.runtime.DefaultApplicationContext.AutoLoad; +import jaxx.runtime.JAXXContext; +import jaxx.runtime.swing.AboutPanel; +import jaxx.runtime.swing.editor.config.ConfigUI; +import jaxx.runtime.swing.editor.config.ConfigUIBuilder; +import jaxx.runtime.swing.editor.config.model.ConfigUIModel; +import jaxx.runtime.swing.wizard.WizardUILancher; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.i18n.I18n; +import org.nuiton.i18n.editor.project.I18nProject; +import org.nuiton.i18n.editor.project.I18nProjectFactory; +import org.nuiton.i18n.editor.project.I18nProjectProvider; +import org.nuiton.i18n.editor.ui.project.ProjectStep; +import org.nuiton.i18n.editor.ui.project.ProjectUI; +import org.nuiton.i18n.editor.ui.project.ProjectUIModel; +import static org.nuiton.i18n.I18n._; +import static org.nuiton.i18n.I18n.n_; + +/** + * + * @author chemit + */ +@AutoLoad +public class I18nEditorUIHandler { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(I18nEditorUIHandler.class); + + /** + * Methode pour initialiser l'ui principale sans l'afficher. + * + * Si un projet est charge dans le context, alors on le charge dans l'ui. + * + * @param context le context applicatif + * @param fullscreen flag pour indiquer si on doit ouvrir l'ui en model console (pleine ecran). + * @return l'ui instancie et initialisee mais non visible encore + */ + public I18nEditorUI initUI(I18nEditorContext context, boolean fullscreen) { + + final I18nEditorUI ui = new I18nEditorUI(context); + + I18nEditorContext.MAIN_UI_ENTRY_DEF.setContextValue(context, ui); + + // set fullscreen propery on main ui + ui.getGraphicsConfiguration().getDevice().setFullScreenWindow(fullscreen ? ui : null); + + // chargement du menu des projets existants + context.firePropertyChange("projects", null, context.getConfig().getProjects()); + + I18nProject project = context.getProject(); + if (project != null) { + + openProjectUI(ui, project); + } + return ui; + } + + /** + * Permet de recharger l'ui principale et de changer de le mode d'affichage. + * + * @param context le contexte applicatif + */ + public void reloadUI(I18nEditorContext context) { + + // on conserve la clef actuellement selectionnee + context.saveSelectedKey(); + + // must remove all properties listener on config + context.getContextValue(I18nEditorConfig.class).removeJaxxPropertyChangeListener(); + context.removeJaxxPropertyChangeListener(); + + boolean fullscreen = context.getConfig().isFullScreen(); + // scan main ui + I18nEditorUI ui = getUI(context); + + + if (ui != null) { + + I18nEditorContext.MAIN_UI_ENTRY_DEF.removeContextValue(context); + + ui.dispose(); + + ui.setVisible(false); + } + + ui = initUI(context, fullscreen); + + // show ui + ui.setVisible(true); + } + + /** + * Creer un projet. + * + * @param context le context applicatif + */ + public void createProject(I18nEditorContext context) { + try { + createProjectUI(context); + + I18nProject project = context.getProject(); + + if (project == null) { + return; + } + + log.info("open project " + project); + + context.firePropertyChange(I18nEditorContext.PROJECT_PROPERTY, null, project); + context.firePropertyChange("projects", null, context.getConfig().getProjects()); + + } catch (Exception ex) { + throw new RuntimeException("could not open project for reason " + ex.getMessage(), ex); + } + } + + /** + * Ouvre un projet. + * + * @param context le context applicatif + */ + public void openOtherProject(I18nEditorContext context) { + try { + + File f = ProjectUIModel.chooseFile(getUI(context), + _("i18neditor.title.choose.project"), + _("i18neditor.action.choose.project"), + null, + "^.+\\.i18nproject$", + _("i18neditor.action.choose.project.description")); + if (f == null) { + return; + } + loadProject(context, f); + + I18nProject project = context.getProject(); + + if (project == null) { + return; + } + + log.info("open project " + project); + + context.firePropertyChange(I18nEditorContext.PROJECT_PROPERTY, null, project); + + } catch (Exception ex) { + throw new RuntimeException("could not open project for reason " + ex.getMessage(), ex); + } + } + + /** + * Ouvre un projet. + * + * @param context le context applicatif + * @param name le nom du projet a ouvrir + */ + public void openProject(I18nEditorContext context, String name) { + try { + File f = context.getConfig().getProjectStore(name); + loadProject(context, f); + + I18nProject project = context.getProject(); + + if (project == null) { + return; + } + + log.info("open project " + project); + + context.firePropertyChange(I18nEditorContext.PROJECT_PROPERTY, null, project); + + } catch (Exception ex) { + throw new RuntimeException("could not open project for reason " + ex.getMessage(), ex); + } + } + + /** + * Ferme un projet actuellement charge. + * + * @param context le context applicatif + * @param project le projet a fermer + */ + public void closeProject(I18nEditorContext context, I18nProject project) { + + if (project == null) { + return; + } + + log.info("close project " + project); + + I18nEditorContext.PROJECT_DEF.removeContextValue(context); + + context.firePropertyChange(I18nEditorContext.PROJECT_PROPERTY, project, null); + + context.setSelectedKey(null); + } + + /** + * Ferme l'application. + * + * @param context le context applicatif + */ + public void close(I18nEditorContext context) { + log.info("I18nEditor quitting..."); + I18nEditorUI ui = getUI(context); + boolean canContinue = ensureModification(ui); + if (!canContinue) { + return; + } + try { + if (ui != null) { + ui.dispose(); + } + } finally { + System.exit(0); + } + } + + /** + * Méthode pour changer de mode d'affichage. + * <p/> + * Si <code>fullscreen</code> est à <code>true</code> alors on passe en + * mode console (c'est à dire en mode plein écran exclusif), sinon on + * passe en mode fenetré normal. + * + * @param context le context applicatif + * @param fullscreen le nouvel état requis. + */ + public void changeScreen(I18nEditorContext context, boolean fullscreen) { + I18nEditorUI ui = getUI(context); + boolean canContinue = ensureModification(ui); + if (!canContinue) { + return; + } + context.getConfig().setFullscreen(fullscreen); + + // on recharge l'ui + reloadUI(context); + } + + /** + * Methode pour changer la langue utilisee. + * + * Cette action recharge le systeme i18n avec la nouvelle locale + * donnee puis recherge les interfaces graphiques. + * + * @param context applicatif + * @param newLocale la nouvelle locale a utilisee dans l'application. + */ + public void changeLanguage(I18nEditorContext context, Locale newLocale) { + if (newLocale == null) { + // pour eviter du code reentrant due aux binding... + return; + } + I18nEditorUI ui = getUI(context); + + boolean canContinue = ensureModification(ui); + if (!canContinue) { + return; + } + I18nEditorConfig config = context.getConfig(); + Locale oldLocale = config.getLocale(); + if (oldLocale != null && oldLocale.equals(newLocale)) { + return; + } + log.info("new locale to use " + newLocale + " (old: " + oldLocale + ")"); + // sauvegarde de la nouvelle locale + config.setLocale(newLocale); + + // chargement de la nouvelle locale dans le système i18n + I18n.init(newLocale); + + // on recharge l'ui + reloadUI(context); + } + + /** + * Methode pour changer le type de modele de l'arbre de l'arbre des clefs. + * + * @param context le contexte applicatif + * @param newMode le nouveau mode du modele d'arbre + */ + public void changeTreeModelMode(I18nEditorContext context, TreeModelMode newMode) { + //I18nEditorContext context = ui.getContext(); + + TreeModelMode oldMode = context.getTreeModelMode(); + if (oldMode == newMode) { + // on evite le code re-entrant + return; + } + + log.info("new tree model mode : " + newMode); + + // on conserve la clef actuellement selectionnee + context.saveSelectedKey(); + + // on change le type de model d'arbre (cela reconstruira l'arbre) + context.setTreeModelMode(newMode); + } + + public void updateProjectsMenuUI(final I18nEditorContext context) { + I18nEditorUI ui = getUI(context); + if (ui == null) { + return; + } + JMenu menu = ui.getMenuFileOpenProject(); + + Component[] components = menu.getMenuComponents(); + for (Component c : components) { + if (c instanceof JMenuItem && ((JComponent) c).getClientProperty("doNotRemove") == null) { + menu.remove(c); + } + } + Action action = new AbstractAction() { + + private static final long serialVersionUID = 1L; + + @Override + public void actionPerformed(ActionEvent e) { + JMenuItem source = (JMenuItem) e.getSource(); + String name = source.getName(); + openProject(context, name); + } + }; + List<String> projects = new ArrayList<String>(context.getConfig().getProjects()); + Collections.sort(projects); + for (String name : projects) { + JMenuItem item = new JMenuItem(action); + item.setName(name); + item.setText(name); + menu.add(item); + } + ui.getMenuFileDeleteProject().setEnabled(!projects.isEmpty()); + + } + + public void updateSelectedValue(I18nEditorContext context, String packageName, Locale locale, String key, String newValue) { + I18nProject project = context.getProject(); + if (log.isDebugEnabled()) { + log.debug(packageName + " - " + locale + " - " + key + " = " + newValue); + } + if (project != null) { + project.updateValue(packageName, locale, key, newValue); + } + } + + public void deleteSelectedValueForLocale(I18nEditorContext context, BundleValueUI sourceUI, String packageName, Locale locale, String key) { + I18nProject project = context.getProject(); + if (log.isDebugEnabled()) { + log.debug(packageName + " - " + locale + " - " + key); + } + if (project != null) { + project.deleteKey(packageName, locale, key); + } + + final BundleValuesUI ui = sourceUI.getParentContainer(BundleValuesUI.class); + ui.getBundlesContent().remove(sourceUI); + if (ui.getBundlesContent().getComponentCount() == 0) { + Container parent = ui.getParent(); + // plus de bundle pour le paquetage + parent.remove(ui); + getUI(context).getValues().repaint(); + // on doit recharger les clefs + + context.saveSelectedKey(); + + reloadKeys(getUI(context)); + } else { + ui.revalidate(); + } + } + + /** + * Création d'un nouveau bundle utilistateur + * + * @param context + */ + public void createBundle(I18nEditorContext context) { +// // Ouverture de la fenêtre de création +// CreateBundleUI createBundle = new CreateBundleUI(ui); +// createBundle.setVisible(true); +// +// String bundle = createBundle.getBundle(); +// +// if (bundle != null) { +// // Ajout du nouveau bundle à l'écran et dans le menu +// +//// I18nEditorContext context = ui.getContext(); +// //List<String> bundlesI18n = context.getBundlesI18n(); +// createBundleChekBoxMenu(ui, bundle); +// //bundlesI18n.add(bundle); +// reloadValues(ui); +// } + } + + public void createBundle(I18nEditorContext context, String bundle) { +// // Ouverture de la fenêtre de création +// CreateBundleUI createBundle = new CreateBundleUI(ui); +// createBundle.setVisible(true); +// +// String bundle = createBundle.getBundle(); +// +// if (bundle != null) { +// // Ajout du nouveau bundle à l'écran et dans le menu +// +//// I18nEditorContext context = ui.getContext(); +// //List<String> bundlesI18n = context.getBundlesI18n(); +// createBundleChekBoxMenu(ui, bundle); +// //bundlesI18n.add(bundle); +// reloadValues(ui); +// } + } + + /** + * Création d'un nouveau bundle utilistateur + * + * @param context + */ + public void createPackage(I18nEditorContext context) { +// // Ouverture de la fenêtre de création +// CreatePackageUI createBundle = new CreatePackageUI(ui); +// createBundle.setVisible(true); +// +// String bundle = createBundle.getBundle(); +// +// if (bundle != null) { +// // Ajout du nouveau bundle à l'écran et dans le menu +// +//// I18nEditorContext context = ui.getContext(); +//// List<String> bundlesI18n = context.getBundlesI18n(); +// createPackageChekBoxMenu(ui, bundle); +// //bundlesI18n.add(bundle); +// reloadKeys(ui); +// reloadValues(ui); +// } + } + + public void showConfig(I18nEditorContext context) { + I18nEditorUI ui = getUI(context); + + ConfigUIModel model = new ConfigUIModel(context.getConfig()); + model.addCategory( + n_("i18neditor.config.category.directories"), + n_("i18neditor.config.category.directories.description"), + I18nEditorConfig.Option.CONFIG_FILE, + I18nEditorConfig.Option.PROJECTS_DIRECTORY, + I18nEditorConfig.Option.TMP_DIRECTORY); + + model.addCategory( + n_("i18neditor.config.category.ui"), + n_("i18neditor.config.category.ui.description"), + I18nEditorConfig.Option.FULL_SCREEN, + I18nEditorConfig.Option.LOCALE); + + ConfigUI configUI = ConfigUIBuilder.newConfigUI(context, model, "i18neditor.config.category.ui"); + + ConfigUIBuilder.showConfigUI(configUI, ui, false); +// configUI.showInDialog(ui, ui != null); + } + + public void showHelp(JAXXContext context, String helpId) { +// ObserveMainUI mainUI = getUI(context); +// +// ObserveHelpBroker helpBroker = context.getContextValue(ObserveHelpBroker.class); +// +// if (mainUI == null) { +// log.info("no mainUI, open in autonome frame"); +// // ouvrir dans une fenetre dedie +// helpBroker.showHelpSet(); +// return; +// } +// +// JHelp ui = mainUI.getHelp(); +// +// if (helpId == null) { +// helpId = helpBroker.getDefaultID(); +// } +// log.debug("show help " + helpId); +// ui.setCurrentID(helpId); +// +// mainUI.setContextValue(mainUI.getMode(), "oldMode"); +// mainUI.setMode(ObserveUIMode.HELP); +// } +// +// public void closeHelp(JAXXContext context) { +// ObserveMainUI mainUI = getUI(context); +// ObserveUIMode oldMode = mainUI.getContextValue(ObserveUIMode.class, "oldMode"); +// if (oldMode == null) { +// // on regarde si une base est chargee +// ObserveDataContext dataContext = context.getContextValue(ObserveDataContext.class); +// StorageService<?> mainStorage = dataContext.getStorage(); +// +// if (mainStorage == null) { +// oldMode = ObserveUIMode.NO_DB; +// } else { +// oldMode = ObserveUIMode.DB; +// } +// } +// mainUI.setMode(oldMode); + } + + public void gotoSite(I18nEditorContext context) { + + I18nEditorConfig config = context.getConfig(); + + URL siteURL = config.getOptionAsURL("application.site.url"); + + log.info("goto " + siteURL); + if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { + try { + Desktop.getDesktop().browse(siteURL.toURI()); + } catch (Exception ex) { + log.error(ex.getMessage(), ex); + } + } + } + + public void showAbout(I18nEditorContext context) { + + I18nEditorUI ui = getUI(context); + + AboutPanel about = new AboutPanel(ui); + about.setTitle(_("i18neditor.title.about")); + about.setAboutText(_("i18neditor.about.message")); + about.setBottomText(context.getConfig().getCopyrightText()); +// about.setIconPath("/icons/logo-OT_web.png"); + about.setLicenseFile("META-INF/nuiton-i18n-editor-LICENSE.txt"); + about.setThirdpartyFile("META-INF/nuiton-i18n-editor-THIRD-PARTY.txt"); + about.init(); + about.showInDialog(ui, true); + } + + public void showStorageInfo(I18nEditorContext context) { + + I18nEditorUI ui = getUI(context); + + String text = null; + if (context.getProject() == null) { + text = _("i18neditor.message.no.project.loaded"); + } else { + text = context.getProject().toString(); + } + JOptionPane.showMessageDialog( + ui, + text, + _("i18neditor.title.project.info"), + JOptionPane.INFORMATION_MESSAGE); + } + + /** + * Méthode pour lancer l'assistant de creation de projet. + * + * @param rootContext le context applicatif + */ + public void createProjectUI(final JAXXContext rootContext) { + boolean canContinue = ensureModification(rootContext); + if (!canContinue) { + return; + } + + final I18nEditorUI mainUI = getUI(rootContext); + + new WizardUILancher<ProjectStep, ProjectUIModel, ProjectUI>(rootContext, mainUI, ProjectUI.class, ProjectUIModel.class) { + + @Override + protected void init(ProjectUI ui) { + ProjectUIModel model = ui.getModel(); + Set<I18nProjectProvider<?>> providers = I18nProjectFactory.getProviders(); + if (!providers.isEmpty()) { + model.setType(providers.iterator().next()); + } + } + + @Override + protected void doAction(ProjectUI ui) { + log.info(ui.getName()); + ProjectUIModel model = ui.getModel(); + + I18nProject project = null; + I18nProjectProvider<?> type = model.getType(); + project = I18nProjectFactory.newProject(type.getType(), model); + try { + if (project.isStoreProject()) { + // ajout du projet dans la liste des projets connus + rootContext.getContextValue(I18nEditorConfig.class).getProjects().add(project.getName()); + // on enregistre la definition du projet + project.saveDefinition(); + } + project.load(); + I18nEditorContext.PROJECT_DEF.setContextValue(rootContext, project); + } catch (IOException ex) { + log.error(ex.getMessage(), ex); + } + } + + @Override + protected void doCancel(ProjectUI ui) { + super.doCancel(ui); + + } + }.start(); + } + + /** + * Méthode pour lancer l'assistant de mise a jour de projet. + * + * @param context le context applicatif + */ + public void editProject(final I18nEditorContext context) { + boolean canContinue = ensureModification(context); + if (!canContinue) { + return; + } + + final I18nEditorUI mainUI = getUI(context); + + new WizardUILancher<ProjectStep, ProjectUIModel, ProjectUI>(context, mainUI, ProjectUI.class, ProjectUIModel.class) { + + @Override + protected void doAction(ProjectUI ui) { + log.info(ui.getName()); + ProjectUIModel model = ui.getModel(); + I18nProject project = null; + I18nProjectProvider<?> type = model.getType(); + project = I18nProjectFactory.newProject(type.getType(), model); + try { + if (project.isStoreProject()) { + if (!context.getConfig().getProjects().contains(project.getName())) { + // ajout du projet dans la liste des projets connus + context.getConfig().getProjects().add(project.getName()); + } + // on enregistre la definition du projet + project.saveDefinition(); + } + project.load(); + I18nEditorContext.PROJECT_DEF.setContextValue(context, project); + } catch (IOException ex) { + log.error(ex.getMessage(), ex); + } + } + + @Override + protected void doCancel(ProjectUI ui) { + super.doCancel(ui); + + } + }.start(); + } + + public void deleteProject(I18nEditorContext context) { + JComboBox box = new JComboBox(); + List<String> projects = new ArrayList<String>(context.getConfig().getProjects()); + Collections.sort(projects); + box.addItem(""); + for (String p : projects) { + box.addItem(p); + } + JOptionPane.showMessageDialog(getUI(context), box, _("i18neditor.choose.project.to.delete"), JOptionPane.INFORMATION_MESSAGE); + + String selectedProject = (String) box.getSelectedItem(); + if (!selectedProject.isEmpty()) { + File f = context.getConfig().getProjectStore(selectedProject); + f.delete(); + context.getConfig().getProjects().remove(selectedProject); + log.info("project ot delete : " + selectedProject); + context.firePropertyChange("projects", null, context.getConfig().getProjects()); + } + } + + /** + * Charger un projet. + * + * @param context le context applicatif + * @param projectFile le fichier de definition du projet a ouvrir + */ + public void loadProject(I18nEditorContext context, File projectFile) { + FileInputStream stream = null; + try { + I18nProject project = I18nProjectFactory.newProject(projectFile); + + project.setStoreFile(projectFile); + project.load(); + I18nEditorContext.PROJECT_DEF.setContextValue(context, project); + + } catch (Exception ex) { + throw new RuntimeException("could not load project for reason " + ex.getMessage(), ex); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException ex) { + throw new RuntimeException("could not close project for reason " + ex.getMessage(), ex); + } + } + } + } + + protected void openProjectUI(I18nEditorUI ui, I18nProject project) { + if (ui == null) { + return; + } + if (log.isDebugEnabled()) { + log.debug("opening project ui for " + project); + } + + List<Locale> selectedLocales = project.getSelectedBundles(); + List<String> selectedPackages = project.getSelectedPackages(); + JMenu menuPackages = ui.getMenuPackages(); + for (String packageName : project.getPackages()) { + boolean selected = selectedPackages.contains(packageName); + JCheckBoxMenuItem checkBoxMenuItem = new PackageCheckBoxMenuUI(ui, packageName, selected); + menuPackages.add(checkBoxMenuItem); + } + + JMenu menuBundles = ui.getMenuBundles(); + for (Locale l : project.getBundles()) { + boolean selected = selectedLocales.contains(l); + JCheckBoxMenuItem checkBoxMenuItem = new BundleCheckBoxMenuUI(ui, l, selected); + menuBundles.add(checkBoxMenuItem); + } + + // Initialisation des données + reloadKeys(ui); + } + + protected void closeProjectUI(final I18nEditorUI ui, I18nProject project) { + + if (ui == null) { + return; + } + + if (log.isDebugEnabled()) { + log.debug("closing project ui for " + project); + } + JMenu menu = ui.getMenuBundles(); + Component[] components = menu.getMenuComponents(); + for (Component c : components) { + if (c instanceof JCheckBoxMenuItem) { + menu.remove(c); + } + } + menu = ui.getMenuPackages(); + components = menu.getMenuComponents(); + for (Component c : components) { + if (c instanceof JCheckBoxMenuItem) { + menu.remove(c); + } + } + ui.getValues().removeAll(); + ui.getTreeModel().setKeys(new String[0]); + ui.getValues().repaint(); + } + + /** + * Recharge les clés dans l'arbre des propriétés en fonction des paquetages + * @param ui + */ + protected void reloadKeys(I18nEditorUI ui) { + I18nEditorContext context = ui.getContext(); + I18nProject project = context.getProject(); + if (project == null) { + return; + } + + // on supprime la selection (elle sera repositionnee ensuite si necessaire) + ui.getTreeSelectionModel().clearSelection(); + + // construction du nouveau model + String[] keys = project.getKeys(); + PropertiesTreeModel model = ui.getTreeModel(); + log.info("wil use " + keys.length + " keys"); + model.setKeys(keys); + ui.getTree().repaint(); + reSelectSelectedKey(ui); + } + + public void reSelectSelectedKey(I18nEditorUI ui) { + + I18nEditorContext context = ui.getContext(); + // recuperation de l'ancienne clef selectionne + String selectedKey = context.getSelectedKey(); + if (selectedKey == null) { + // on recherche dans une seconde entree du context + // positionne explicitement par le developpeur + // ceci est necessaire car le model est reconstruit a chaque + // nouvelle ui (changement de langue,...) et on perd donc l'information + // sur selectedKey due a un binding... + selectedKey = context.popSelectedKey(); + if (selectedKey != null && !ui.getTreeModel().containsKey(selectedKey)) { + selectedKey = null; + } + context.setSelectedKey(selectedKey); + } + log.info(selectedKey); + } + + /** + * Recharge les valeurs de la clef selectionnee dans l'arbre de navigation. + * + * @param ui + */ + protected void reloadValues(I18nEditorUI ui) { + String key = ui.getContext().getSelectedKey(); + reloadValues(ui, key); + } + + /** + * Recharge les valeurs d'une clef donnee. + * + * @param ui + * @param key la clef de traduction dont on va editer les traductions + */ + protected void reloadValues(I18nEditorUI ui, String key) { + I18nEditorContext context = ui.getContext(); + I18nProject project = context.getProject(); + if (project == null) { + return; + } + + JPanel valuesUI = ui.getValues(); + valuesUI.removeAll(); + + if (log.isDebugEnabled()) { + log.debug("for key : " + key); + } + + if (key != null) { + List<String> packagesI18n = project.getSelectedPackages(); + + for (String p : packagesI18n) { + Map<Locale, String> values = project.getValues(p, key); + if (values != null && !values.isEmpty()) { + BundleValuesUI bundleValuesUI = new BundleValuesUI(context); + bundleValuesUI.setPackageName(p); + bundleValuesUI.setKey(key); + if (log.isDebugEnabled()) { + log.debug("adding package " + p); + } + bundleValuesUI.setBundles(new ArrayList<Locale>(values.keySet())); + for (java.util.Map.Entry<Locale, String> e : values.entrySet()) { + BundleValueUI v = new BundleValueUI(bundleValuesUI); + v.setBundle(e.getKey()); + if (log.isDebugEnabled()) { + log.debug(" - adding locale " + e.getKey()); + } + v.setKey(key); + v.setPackageName(p); + v.setInitialValue(e.getValue()); + bundleValuesUI.getBundlesContent().add(v); + } + valuesUI.add(bundleValuesUI); + } + } + } + + JScrollPane valuesView = ui.getValuesView(); + valuesView.validate(); + valuesView.repaint(); + } + + /** + * Test if there is some modification on screen, + * + * @param rootContext the context + * @return <code>true</code> if no more modification is detected + * @throws IllegalArgumentException if rootContext is null + */ + protected boolean ensureModification(JAXXContext rootContext) throws IllegalArgumentException { + if (rootContext == null) { + throw new IllegalArgumentException("rootContext can not be null"); + } + I18nEditorUI ui = getUI(rootContext); + if (ui == null) { + // no ui, so no modification + return true; + } + return true; + } + + protected I18nEditorUI getUI(JAXXContext context) { + I18nEditorUI ui; + if (context instanceof I18nEditorUI) { + ui = (I18nEditorUI) context; + } else if (context instanceof I18nEditorContext) { + ui = ((I18nEditorContext) context).getMainUI(); + } else { + ui = I18nEditorContext.MAIN_UI_ENTRY_DEF.getContextValue(context); + } + return ui; + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/PackageCheckBoxMenuUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/PackageCheckBoxMenuUI.jaxx new file mode 100644 index 0000000..be91774 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/PackageCheckBoxMenuUI.jaxx @@ -0,0 +1,66 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<JCheckBoxMenuItem id='content' + text='{updateText(getUrl())}' + toolTipText='{_("i18neditor.resource.name", getUrl())}' + onItemStateChanged='updateState(event)'> + + <!-- le nom du bundle --> + <String id='url' javaBean='""'/> + + <script><![CDATA[ +import org.nuiton.i18n.editor.*; +import java.util.Locale; +import jaxx.runtime.JAXXContext; + +public PackageCheckBoxMenuUI(JAXXContext parentContext, String bundle, boolean selected) { + super(null, selected); + setContextValue(parentContext); + setUrl(bundle); +} + +protected String updateText(String name) { + int index = name.lastIndexOf("/"); + if (index > -1) { + name = name.substring(index + 1); + } + return name; +} + +protected void updateState(ItemEvent e) { + I18nEditorContext context = getContextValue(I18nEditorContext.class); + if (context == null) { + // pas encore de context (ui en construction) + return; + } + if (e.getStateChange() == ItemEvent.SELECTED) { + context.addSelectedPackage(url); + } else { + context.removeSelectedPackage(url); + } +} +]]> + </script> + +</JCheckBoxMenuItem> diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/PropertieNode.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/PropertieNode.java new file mode 100644 index 0000000..3e0faef --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/PropertieNode.java @@ -0,0 +1,122 @@ +/* + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* */ +package org.nuiton.i18n.editor.ui; + +import javax.swing.tree.DefaultMutableTreeNode; +import java.io.Serializable; +import javax.swing.tree.MutableTreeNode; + +/** + * Représente un noeud de l'ardre des propriétés affichées. Le noeud contient + * le chemin de la propriétés, par exemple tutu.toto.tata va être représenté avec + * 3 noeuds avec comme chemin tutu, tutu.toto, tutu.toto.tata + * + * @author julien + */ +public class PropertieNode extends DefaultMutableTreeNode implements Comparable<PropertieNode> { + + /** @see Serializable */ + private static final long serialVersionUID = 1L; + + /** + * Constructeur avec l'objet contenu dans le noeud + * + * @param userObject chemin de la propriété + */ + public PropertieNode(Object userObject) { + super(userObject); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof PropertieNode) { + // Comparaison du chemin + PropertieNode node = (PropertieNode) obj; + return getUserObject().equals(node.getUserObject()); + } + return false; + } + + public PropertieNode getChildAt(String path) { + if (!isLeaf()) { + for (Object o : children) { + PropertieNode n = (PropertieNode) o; + if (path.equals(n.getUserObject())) { + return n; + } + } + } + return null; + } + + /** + * Ajoute le noeud fils a la bonne position (on conserve l'ordre alphabetique des path) + * + * Note : si le path existe deja, alors on ne fait rien. + * + * @param newChild le fils a ajouter + */ + @Override + public void add(MutableTreeNode newChild) { + int index = 0; + if (!isLeaf()) { + // on recherche la position ou ajouter la clef + for (Object o : children) { + PropertieNode n = (PropertieNode) o; + int compareTo = n.compareTo((PropertieNode) newChild); + if (compareTo == 0) { + // le noeud existe deja + return; + } + if (compareTo > 0) { + // le noeud courant doit etre apres le noeud a ajouter + break; + } + index++; + } + } + insert(newChild, index); + } + +// @Override +// public String toString() { +// String result = getUserObject().toString(); +// if (isRoot()) { +// // Si c'est la racine +// return result; +// } else { +// // Si c'est un chemin +// int lastSeparator = result.lastIndexOf("."); +// return result.substring(lastSeparator + 1); +// } +// } + + @Override + public int hashCode() { + return getUserObject().hashCode(); + } + + @Override + public int compareTo(PropertieNode node) { + // Compare les chemins + return getUserObject().toString().compareTo(node.getUserObject().toString()); + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/PropertiesTreeModel.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/PropertiesTreeModel.java new file mode 100644 index 0000000..c69286b --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/PropertiesTreeModel.java @@ -0,0 +1,199 @@ +/* + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* */ +package org.nuiton.i18n.editor.ui; + +import javax.swing.tree.DefaultTreeModel; +import java.io.Serializable; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.i18n.editor.I18nEditorContext; +import static org.nuiton.i18n.I18n._; + +/** + * Modèle de l'arbre des propriétés. Le modèle permet de sructurer les propriétés + * (ex: tutu.toto.tata) en un des noeuds de l'arbre. + * + * @author julien + */ +public class PropertiesTreeModel extends DefaultTreeModel { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(PropertiesTreeModel.class); + /** @see Serializable */ + private static final long serialVersionUID = 1L; + protected TreeModelMode mode; + protected String[] keys; + + /** + * Constructeur avec un liste de proprétés + * + * @param list liste de propriétés + */ + public PropertiesTreeModel(String... list) { + this(TreeModelMode.TREE, list); + } + + /** + * Constructeur avec un liste de proprétés + * + * @param mode le mode de modele a construire + * @param list liste de propriétés + */ + public PropertiesTreeModel(TreeModelMode mode, String... list) { + super(null); + this.keys = list; + + // Création de la racine (qui n'est jamais affichee) + PropertieNode r = new PropertieNode(""); +// PropertieNode r = new PropertieNode(list.length == 0 ? _("i18neditor.no.keys") : I18nEditorContext.ROOT_NAME); + setRoot(r); + setMode(mode); + } + + @Override + public PropertieNode getRoot() { + return (PropertieNode) super.getRoot(); + } + + public String[] getKeys() { + return keys; + } + + public void setKeys(String[] keys) { + this.keys = keys; + // on reconstruit le model + TreeModelMode theMode = mode; + mode = null; + setMode(theMode); + } + + public boolean containsKey(String selectedKey) { + if (keys != null) { + switch (mode) { + case TREE: + for (String k : keys) { + if (k.equals(selectedKey) || k.startsWith(selectedKey + ".")) { + return true; + } + } + break; + case FLAT: + + for (String k : keys) { + if (k.equals(selectedKey)) { + return true; + } + } + break; + } + } + return false; + } + + public PropertieNode getNode(String path) { + PropertieNode result = null; + switch (mode) { + case TREE: + String[] names = path.split("\\" + I18nEditorContext.SEPARATOR); + result = getRoot(); + String currentPath = ""; + for (String name : names) { + if (!currentPath.isEmpty()) { + currentPath += I18nEditorContext.SEPARATOR; + } + currentPath += name; + result = result.getChildAt(currentPath); + } + break; + case FLAT: + result = getRoot().getChildAt(path); + break; + } + return result; + } + + public TreeModelMode getMode() { + return mode; + } + + public void setMode(TreeModelMode mode) { + this.mode = mode; + + if (root == null) { + return; + } + PropertieNode r = (PropertieNode) root; + if (!r.isLeaf()) { + // on supprime tous les fils + r.removeAllChildren(); + } + if (keys == null || keys.length == 0) { + // pas de clef a reconstruire + PropertieNode r2 = new PropertieNode(_("i18neditor.no.keys")); + r.add(r2); + // on notifie que le modele a ete reconstruit + nodeStructureChanged(root); + return; + } + + // on reconstruit le modele + + switch (mode) { + case TREE: + buildTreeModel(r, keys); + break; + + case FLAT: + buildFlatModel(r, keys); + break; + } + // on notifie que le modele a ete reconstruit + nodeStructureChanged(root); + } + + private void buildTreeModel(PropertieNode r, String[] list) { + for (String property : list) { + String path = ""; + PropertieNode parent = r; + + String[] names = property.split("\\" + I18nEditorContext.SEPARATOR); + for (String name : names) { + if (!path.isEmpty()) { + + path += I18nEditorContext.SEPARATOR; + } + path += name; + + PropertieNode node = parent.getChildAt(path); + if (node == null) { + node = new PropertieNode(path); + parent.add(node); + } + parent = node; + } + } + } + + private void buildFlatModel(PropertieNode r, String[] list) { + + for (String property : list) { + PropertieNode node = new PropertieNode(property); + r.add(node); + } + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/TreeModelMode.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/TreeModelMode.java new file mode 100644 index 0000000..13495d4 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/TreeModelMode.java @@ -0,0 +1,36 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.ui; + +/** + * Pour caracteriser le mode a utiliser dans le modele de navigation. + * + * @author chemit + */ +public enum TreeModelMode { + + /** + * pour afficher les clefs sous forme d'arbre + */ + TREE, + /** + * pour afficher les clefs a plat + */ + FLAT +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/ProjectStep.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/ProjectStep.java new file mode 100644 index 0000000..c786adf --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/ProjectStep.java @@ -0,0 +1,67 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.ui.project; + +import static org.nuiton.i18n.I18n.n_; + +/** + * Pour caracteriser les étapes lors du wizard de creation de projet + * + * @author tchemit + */ +public enum ProjectStep implements jaxx.runtime.swing.wizard.WizardStep { + + /** + * pour choisir le type de projet a creer (@see ProjectType) + */ + CHOOSE_PROJECT_TYPE(n_("i18neditor.project.step.chooseProjectType"), n_("i18neditor.project.step.chooseProjectType.description")), + /** + * pour configurer un projet + */ + CONFIGURE_PROJECT(n_("i18neditor.project.step.configureProject"), n_("i18neditor.project.step.configureProject.description")), + /** + * pour choisir les bundles parmis ceux trouvés + */ + SELECT_BUNDLES(n_("i18neditor.project.step.selecteBundles"), n_("i18neditor.project.step.selecteBundles.description")), + /** + * pour renseigner si on persiste le projet + */ + PERSIST(n_("i18neditor.project.step.persist"), n_("i18neditor.project.step.persist.description")), + /** + * pour confirmer et charger le projet + */ + RESUME(n_("i18neditor.project.step.resume"), n_("i18neditor.project.step.resume.description")); + private final String label; + private final String description; + + private ProjectStep(String label, String description) { + this.label = label; + this.description = description; + } + + @Override + public String getLabel() { + return label; + } + + @Override + public String getDescription() { + return description; + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/ProjectUI.css b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/ProjectUI.css new file mode 100644 index 0000000..8a24599 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/ProjectUI.css @@ -0,0 +1,59 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +#mainUI { + title:"i18neditor.title.noproject"; + modal:true; + resizable:false; + defaultCloseOperation:"dispose_on_close"; + layout:{new BorderLayout()}; +} + +#tabs { + border:{BorderFactory.createEmptyBorder(6,6,6,6)}; +} + +#cancelAction { + text:"i18neditor.action.cancel"; + toolTipText:"i18neditor.action.cancel.tip"; + actionIcon:"cancel"; +} + +#previousAction { + text:"i18neditor.action.goto.previous.stage"; + toolTipText:"i18neditor.action.goto.previous.stage.tip"; + actionIcon:"previous-step"; + enabled:{getModel().getPreviousStep() != null}; +} + +#nextAction { + text:"i18neditor.action.goto.next.stage"; + toolTipText:"i18neditor.action.goto.next.stage.tip"; + actionIcon:"next-step"; + enabled:{getModel().isValidStep()}; + visible:{getModel().getNextStep() != null}; +} + +#applyAction { + text:"i18neditor.action.apply"; + toolTipText:"i18neditor.action.apply.tip"; + actionIcon:"accept"; + enabled:{getModel().isValidStep()}; + visible:{getModel().getNextStep() == null}; +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/ProjectUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/ProjectUI.jaxx new file mode 100644 index 0000000..fae2fed --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/ProjectUI.jaxx @@ -0,0 +1,299 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<JDialog id="mainUI" + implements='jaxx.runtime.swing.wizard.WizardUI<ProjectStep, ProjectUIModel>' + width='550' height='560' defaultCloseOperation='dispose_on_close'> + + <style source='ProjectUI.css'/> + + <script><![CDATA[ +import javax.swing.table.DefaultTableCellRenderer; + +import jaxx.runtime.JAXXContext; +import jaxx.runtime.SwingUtil; +import jaxx.runtime.swing.MyDefaultCellEditor; +import jaxx.runtime.swing.wizard.WizardOperationState; +import jaxx.runtime.swing.wizard.WizardUtil; +import static jaxx.runtime.JAXXContextEntryDef.newDef; +import static jaxx.runtime.Util.checkJAXXContextEntry; + +import org.nuiton.i18n.editor.I18nEditorContext; +import org.nuiton.i18n.editor.I18nEditorConfig; +import org.nuiton.i18n.editor.ui.I18nEditorUIHandler; +import org.nuiton.i18n.editor.ui.project.ProjectStep; +import org.nuiton.i18n.editor.ui.project.ProjectUIModel; +import org.nuiton.i18n.editor.ui.project.tabs.*; +import static org.nuiton.i18n.I18n.n_; + +protected I18nEditorUIHandler handler = getContextValue(I18nEditorUIHandler.class); +protected I18nEditorConfig config = getContextValue(I18nEditorConfig.class); +protected I18nEditorContext context = getContextValue(I18nEditorContext.class); +protected ProjectUIModel model = getContextValue(ProjectUIModel.class); + + +private boolean contextInitialized; + +public ProjectUI(Window owner, JAXXContext parentContext) { + super(owner); + + // verification du context parent + checkJAXXContextEntry(parentContext, newDef(ProjectUIModel.class)); + checkJAXXContextEntry(parentContext, newDef("apply", Runnable.class)); + checkJAXXContextEntry(parentContext, newDef("cancel", Runnable.class)); + + if (owner != null) { + setContextValue(owner, "parent"); + } + if (parentContext instanceof jaxx.runtime.JAXXInitialContext) { + ((jaxx.runtime.JAXXInitialContext)parentContext).to(this); + } else { + setContextValue(parentContext); + } + contextInitialized = true; +} + +@Override +public ProjectUIModel getModel() { + return model; +} + +@Override +public void start() { + + // on demarre le modele + getModel().start(); + + // centrage sur la frame parent + SwingUtil.center(getContextValue(Window.class, "parent"), this); + + // affichage ui + setVisible(true); +} + +@Override +public ProjectStep getSelectedStep() { + int index = tabs.getSelectedIndex(); + AbstractProjectTabPanelUI c = null; + if (index > -1) { + c = (AbstractProjectTabPanelUI) tabs.getComponentAt(index); + } + ProjectStep result = c == null ? null : c.getStep(); + return result; +} + +@Override +public AbstractProjectTabPanelUI getStepUI(ProjectStep step) { + if (step != null) { + return (AbstractProjectTabPanelUI) getObjectById(step.name()); + } + return null; +} + +@Override +public AbstractProjectTabPanelUI getStepUI(int stepIndex) { + if (stepIndex > tabs.getTabCount()) { + return null; + } + return (AbstractProjectTabPanelUI) tabs.getComponentAt(stepIndex); +} + +@Override +public AbstractProjectTabPanelUI getSelectedStepUI() { + ProjectStep step = getSelectedStep(); + AbstractProjectTabPanelUI ui = getStepUI(step); + return ui; +} + +@Override +public void onWasStarted() { +} + +@Override +public void onModelStateChanged(WizardOperationState newState) { +} + +@Override +public void onOperationStateChanged(ProjectStep step, WizardOperationState newState) { + // mettre a jour l'onglet +} + +@Override +public void onStepChanged(ProjectStep newStep) { + if (newStep == ProjectStep.SELECT_BUNDLES) { + // recalcule des urls disponibles + SELECT_BUNDLES.getBundlesModel().setUrls(model.detectBundles()); + if (!model.isCreate()) { + // on reselectionne les urls du projet + SELECT_BUNDLES.getBundlesModel().setSelectedUrls(model.getProject().getUrls()); + } + return; + } +} + +@Override +public void onStepsChanged(ProjectStep[] steps) { + +} + +public I18nEditorUIHandler getHandler() { + return handler; +} + +public void apply() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + Runnable action = getContextValue(Runnable.class, "apply"); + action.run(); + } catch (Exception e) { + jaxx.runtime.swing.ErrorDialogUI.showError(e); + log.error(e.getMessage(), e); + } finally { + dispose(); + } + } + }); +} + +public void cancel() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + Runnable action = getContextValue(Runnable.class, "cancel"); + action.run(); + } catch (Exception e) { + jaxx.runtime.swing.ErrorDialogUI.showError(e); + log.error(e.getMessage(), e); + } finally { + dispose(); + } + } + }); +} + +void $afterCompleteSetup() { + + // installation du dispatcher de modifications du modele + WizardUtil.installWizardUIListeners(this); + + // ajout de la politique d'affichage des onglets + WizardUtil.addTabsDisplayUntilStepListener(this); + + // tableau de la synchronisation des données des references obsoletes + + final JTable table = SELECT_BUNDLES.getBundles(); + table.setRowHeight(24); + SwingUtil.fixTableColumnWidth(table, 0, 20); + + SwingUtil.setI18nTableHeaderRenderer(table, + n_("i18neditor.createProject.table.bundles.select"), + n_("i18neditor.createProject.table.bundles.select.tip"), + n_("i18neditor.createProject.table.bundles.url"), + n_("i18neditor.createProject.table.bundles.url.tip")); + + DefaultTableCellRenderer renderer = new DefaultTableCellRenderer(); + + DefaultTableCellRenderer renderer2 = new DefaultTableCellRenderer() { + private static final long serialVersionUID = 1L; + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + int modelColumn = table.convertColumnIndexToModel(column); + int modelRow = table.convertRowIndexToModel(row); + SelectBundlesTableModel model = (SelectBundlesTableModel) table.getModel(); + String text = model.getTextValueAt(modelRow, modelColumn); + JComponent c = (JComponent) super.getTableCellRendererComponent(table, text, isSelected, hasFocus, row, column); + return c; + } + }; + + SwingUtil.setTableColumnRenderer(table, 0, SwingUtil.newBooleanTableCellRenderer(renderer)); + SwingUtil.setTableColumnRenderer(table, 1, SwingUtil.newStringTableCellRenderer(renderer2, 100, true)); + SwingUtil.setTableColumnEditor(table, 0, MyDefaultCellEditor.newBooleanEditor(false)); + + // pour tout selectionner - deselectionner dans l'entete du tableau + table.getTableHeader().addMouseListener(new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + + int colIndex = table.getTableHeader().columnAtPoint(e.getPoint()); + colIndex = table.convertColumnIndexToModel(colIndex); + if (colIndex == 0) { + SelectBundlesTableModel model = (SelectBundlesTableModel) table.getModel(); + boolean oldValue = model.isSelectAll(); + // toggle selectAll + model.setSelectAll(!oldValue); + } + } + }); + + // chargement du modèle + getModel().finalizeUIInit(this); +} +]]> + </script> + + <CardLayout> + <!-- les differents contenu d'onglets --> + <ChooseProjectTypePanelUI id='CHOOSE_PROJECT_TYPE' constructorParams='this'/> + <ConfigureProjectPanelUI id='CONFIGURE_PROJECT' constructorParams='this'/> + <SelectBundlesPanelUI id='SELECT_BUNDLES' constructorParams='this'/> + <PersistPanelUI id='PERSIST' constructorParams='this'/> + <ResumePanelUI id='RESUME' constructorParams='this'/> + </CardLayout> + + <!-- les onglets --> + <JTabbedPane id='tabs' + constraints='BorderLayout.CENTER' + onStateChanged='getModel().gotoStep(getSelectedStep())'/> + + <!-- les actions --> + <Table weightx='1' fill='both' constraints='BorderLayout.SOUTH'> + <row> + <cell weightx='0.5' fill="both"> + <!-- pour annuler --> + <JButton id="cancelAction" + onActionPerformed='cancel()'/> + </cell> + <cell weightx='0.5' fill="both"> + <!-- pour aller sur l'onglet précédent --> + <JButton id="previousAction" + onActionPerformed='getModel().gotoPreviousStep()'/> + </cell> + <cell weightx='0.5' fill="both"> + <!-- pour aller sur l'onglet suivant --> + <JButton id="nextAction" + onActionPerformed='getModel().gotoNextStep()'/> + </cell> + <cell weightx='0.5' fill="both"> + <!-- pour apliquer la configuration --> + <JButton id="applyAction" + onActionPerformed='apply()'/> + </cell> + </row> + </Table> + +</JDialog> diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/ProjectUIModel.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/ProjectUIModel.java new file mode 100644 index 0000000..1219894 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/ProjectUIModel.java @@ -0,0 +1,301 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.ui.project; + +import java.awt.Component; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import jaxx.runtime.swing.wizard.WizardModel; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.i18n.editor.I18nEditorConfig; +import org.nuiton.i18n.editor.I18nEditorContext; +import org.nuiton.i18n.editor.project.I18nProject; +import org.nuiton.i18n.editor.project.I18nProjectFactory; +import org.nuiton.i18n.editor.project.I18nProjectProvider; +import org.nuiton.util.FileUtil; + +/** + * Le modele de l'ui pour creer un projet via un assistant + * + * @author chemit + */ +public class ProjectUIModel extends WizardModel<ProjectStep> { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(ProjectUIModel.class); + public static final String TYPE_PROPERTY_NAME = "type"; + public static final String PROJECT_PROPERTY_NAME = "project"; + public static final String VALID_PROPERTY_NAME = "valid"; + /** le dictionnaire des differents projects possible indexes par leur provideur */ + protected Map<I18nProjectProvider<?>, I18nProject> projects; + /** Le provideur du projet en cours d'edition */ + protected I18nProjectProvider<?> type; + /** le projet en cours d'edition */ + protected I18nProject project; + /** la configuration de l'application */ + protected I18nEditorConfig config; + /** un drapeau pour savoir si on est en mode creation ou pas */ + protected boolean create; + + public ProjectUIModel() { + super(ProjectStep.class, + ProjectStep.CHOOSE_PROJECT_TYPE, + ProjectStep.CONFIGURE_PROJECT, + ProjectStep.SELECT_BUNDLES, + ProjectStep.PERSIST, + ProjectStep.RESUME); + this.projects = new HashMap<I18nProjectProvider<?>, I18nProject>(); + // init map of different types of projects + Set<I18nProjectProvider<?>> providers = I18nProjectFactory.getProviders(); + for (I18nProjectProvider<?> p : providers) { + I18nProject newProject = p.newProject(); + this.projects.put(p, newProject); + // the model listens every modification of each project + // and at each time revalidate the model + newProject.addPropertyChangeListener(new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + validate(); + } + }); + } + if (!providers.isEmpty()) { + setType(providers.iterator().next()); + } + } + + /** + * Methode pour finir l'initialisation de l'ui partir du modele. + * + * @param ui l'ui de l'assistant + */ + public void finalizeUIInit(final ProjectUI ui) { + + config = ui.getContextValue(I18nEditorConfig.class); + + I18nEditorContext ctxt = ui.getContextValue(I18nEditorContext.class); + + //TODO instead of seeking an ui model, must seek fro an incoming project... + I18nProject incomingProject = ctxt.getProject(); + + setCreate(incomingProject == null); + + if (incomingProject != null) { + + log.info("from a incoming project " + incomingProject); + if (log.isDebugEnabled()) { + log.debug("from a incoming project " + incomingProject); + } + I18nProjectProvider<?> provider = I18nProjectFactory.getProvider(incomingProject.getClass()); + setType(provider); + incomingProject.copyDefinitionTo(project); + } + } + + @Override + public void start() { + super.start(); + firePropertyChange(TYPE_PROPERTY_NAME, null, type); + firePropertyChange(PROJECT_PROPERTY_NAME, null, project); + if (!create && type != null && project != null) { + // ask to provider to fire every thing on the project ? + //TODO no! the project fire will do it in each specicialized project's ui + project.fireAllProperties(); + } + } + + @Override + public void updateUniverse() { + if (type == null) { + // pas de mode choisi donc l'univers ne change pas + return; + } + List<ProjectStep> universe = new ArrayList<ProjectStep>(); + universe.add(ProjectStep.CHOOSE_PROJECT_TYPE); + universe.add(ProjectStep.CONFIGURE_PROJECT); + + universe.add(ProjectStep.SELECT_BUNDLES); + universe.add(ProjectStep.PERSIST); + universe.add(ProjectStep.RESUME); + if (excludeSteps != null) { + universe.removeAll(excludeSteps); + } + setSteps(universe.toArray(new ProjectStep[universe.size()])); + } + + @Override + public boolean validate(ProjectStep s) { + boolean validate = super.validate(s); + if (validate) { + switch (s) { + case CHOOSE_PROJECT_TYPE: + validate = type != null; + break; + case CONFIGURE_PROJECT: + validate = type.validateUIModel(this); + break; + case SELECT_BUNDLES: + validate = !project.getUrls().isEmpty(); + break; + case PERSIST: + boolean storeProject = project.isStoreProject(); + if (storeProject) { + File storeFile = project.getStoreFile(); + if (create) { + validate = storeFile != null && !storeFile.exists(); + } else { + validate = storeFile != null && storeFile.exists(); + } + } + break; + case RESUME: +// validate = true; + break; + } + } + return validate; + } + + public I18nProjectProvider<?> getType() { + return type; + } + + public I18nProject getProject() { + return project; + } + + public <T extends I18nProject> T getProject(Class<T> projectClass) { + I18nProjectProvider<T> projectType = I18nProjectFactory.getProvider(projectClass); + if (!projects.containsKey(projectType)) { + throw new IllegalArgumentException(projectType + " is not a registred type"); + } + return (T) projects.get(projectType); + } + + public boolean isCreate() { + return create; + } + + public void setCreate(boolean create) { + this.create = create; + } + + public void setType(I18nProjectProvider<?> type) { + I18nProjectProvider<?> oldType = this.type; + this.type = type; + firePropertyChange(TYPE_PROPERTY_NAME, oldType, type); + I18nProject oldProject = this.project; + I18nProject newProject = projects.get(type); + this.project = newProject; + firePropertyChange(PROJECT_PROPERTY_NAME, oldProject, newProject); + validate(); + } + + /** + * Choisir un fichier via un sélecteur graphique de fichiers. + * + * @param parent le component swing appelant le controle + * @param title le titre du dialogue de sélection + * @param buttonLabel le label du boutton d'acceptation + * @param incoming le fichier de base à utilier + * @param filters les filtres + descriptions sur le sélecteur de fichiers + * @return le fichier choisi ou le fichier incoming si l'opération a été annulée + */ + public static File chooseFile(Component parent, String title, String buttonLabel, File incoming, String... filters) { + File oldBasedir = FileUtil.getCurrentDirectory(); + if (incoming != null) { + File basedir; + if (incoming.isFile()) { + basedir = incoming.getParentFile(); + } else { + basedir = incoming; + } + if (basedir.exists()) { + FileUtil.setCurrentDirectory(basedir); + } + } + File file = FileUtil.getFile(title, buttonLabel, parent, filters); + if (log.isDebugEnabled()) { + log.debug(title + " : " + file); + } + FileUtil.setCurrentDirectory(oldBasedir); + File result = file == null ? incoming : file; + return result; + } + + /** + * Choisir un répertoire via un sélecteur graphique de fichiers. + * + * @param parent le component swing appelant le controle + * @param title le titre de la boite de dialogue de sléection + * @param buttonLabel le label de l'action d'acceptation + * @param incoming le fichier de base à utiliser + * @return le répertoire choisi ou le répertoire incoming si l'opération a été annulée + */ + public static File chooseDirectory(Component parent, String title, String buttonLabel, File incoming) { + File oldBasedir = FileUtil.getCurrentDirectory(); + if (incoming != null) { + File basedir; + if (incoming.isFile()) { + basedir = incoming.getParentFile(); + } else { + basedir = incoming; + } + if (basedir.exists()) { + FileUtil.setCurrentDirectory(basedir); + } + } + String file = FileUtil.getDirectory(parent, title, buttonLabel); + if (log.isDebugEnabled()) { + log.debug(title + " : " + file); + } + FileUtil.setCurrentDirectory(oldBasedir); + return file == null ? incoming : new File(file); + } + + public List<URL> detectBundles() { + List<URL> urls; + try { + urls = type.detectBundles(this); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + // suppression du fichier pom.properties... + for (Iterator<URL> it = urls.iterator(); it.hasNext();) { + String path = it.next().toString(); + int index = path.lastIndexOf("/"); + path = path.substring(index + 1); + if (path.equals("pom.properties")) { + it.remove(); + } + } + return urls; + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/SelectBundlesTableModel.java b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/SelectBundlesTableModel.java new file mode 100644 index 0000000..61d3ad2 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/SelectBundlesTableModel.java @@ -0,0 +1,196 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ +package org.nuiton.i18n.editor.ui.project; + +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import javax.swing.table.AbstractTableModel; +import org.nuiton.i18n.I18n; + +/** + * Le modèle pour la tableau dans l'import GPS qui contient les activités et + * les points gps calculés via le fichier gps importé. + * + * @author chemit + */ +public class SelectBundlesTableModel extends AbstractTableModel { + + private static final long serialVersionUID = 1L; + protected static final String[] COLUMN_NAMES = { + I18n.n_("i18neditor.createproject.common.select"), + I18n.n_("i18neditor.createproject.url") + }; + protected static final Class<?>[] COLUMN_CLASSES = { + Boolean.class, + URL.class,}; + protected List<URL> entries; + protected Set<Integer> selected; + protected boolean selectAll; + + public SelectBundlesTableModel() { + super(); + selected = new java.util.HashSet<Integer>(); + } + + @Override + public Class<?> getColumnClass(int columnIndex) { + return COLUMN_CLASSES[columnIndex]; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnIndex == 0; + } + + public void setUrls(List<URL> entries) { + // on nettoye toujours le model lors de l'init d'une entité + this.entries = new java.util.ArrayList<URL>(entries); +// selected.clear(); + // par defaut, on selectionne toutes les references + setSelectAll(true); + //fireTableDataChanged(); + } + + public List<URL> getSelectedUrls() { + List<URL> result = new ArrayList<URL>(); + for (Integer index : selected) { + result.add(entries.get(index)); + } + return result; + } + + public void setSelectedUrls(List<URL> selectedUrls) { + setSelectAll(false); + + for (URL selectedUrl : selectedUrls) { + // trouver l'inder de l'url + String selectedUrlStr = selectedUrl.toString(); + int index = 0; + for (URL u : entries) { + if (selectedUrlStr.equals(u.toString())) { + selected.add(index); + break; + } + index++; + } + } + } + + public int[] getSelected() { + int[] result = new int[selected.size()]; + int i = 0; + for (Integer index : selected) { + result[i++] = index; + } + return result; + } + + public boolean hasSelection() { + return !selected.isEmpty(); + } + + @Override + public int getRowCount() { + return entries == null ? 0 : entries.size(); + } + + @Override + public int getColumnCount() { + return COLUMN_CLASSES.length; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + Object value = null; + switch (columnIndex) { + case 0: + value = selected.contains(rowIndex); + break; + case 1: + value = getURLAt(rowIndex); + break; + default: + throw new IllegalStateException("can not get value for row " + rowIndex + ", col " + columnIndex); + } + return value; + } + + public String getTextValueAt(int rowIndex, int columnIndex) { + Object value = null; + + String text = ""; + URL p; + switch (columnIndex) { + case 0: + break; + case 1: + value = getURLAt(rowIndex); + String path = value.toString(); + int index = path.lastIndexOf("/"); + text = path.substring(index + 1) + "(" + path.substring(0, index) + ")"; + break; + default: + throw new IllegalStateException("can not get value for column " + columnIndex); + } + return text; + } + + public URL getURLAt(int rowIndex) { + return entries.get(rowIndex); + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + if (columnIndex == 0) { + Boolean value = (Boolean) aValue; + if (value) { + selected.add(rowIndex); + if (selected.size() == getRowCount()) { + selectAll = true; + } + } else { + selected.remove(rowIndex); + if (selected.isEmpty()) { + selectAll = false; + } + } + fireTableCellUpdated(rowIndex, columnIndex); + return; + } + + // no edit for others columns + } + + public boolean isSelectAll() { + return selectAll; + } + + public void setSelectAll(boolean selectAll) { + this.selectAll = selectAll; + selected.clear(); + if (selectAll) { + for (int i = 0, max = getRowCount(); i < max; i++) { + selected.add(i); + } + } + fireTableDataChanged(); + } +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/AbstractProjectTabPanelUI.css b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/AbstractProjectTabPanelUI.css new file mode 100644 index 0000000..e1c7770 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/AbstractProjectTabPanelUI.css @@ -0,0 +1,41 @@ +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +#tabPanel { + layout:{new BorderLayout()}; + border:{new LineBorder(Color.BLACK,1,true)}; +} + +#progress { + indeterminate:false; + stringPainted:true; + string:{getProgressString(model.getStepIndex(model.getStep()), model.getSteps().size())}; + value:{1 + model.getStepIndex(model.getStep())}; + maximum:{model.getSteps().size()}; +} + +#descriptionPane { + columnHeaderView:{new JLabel(_("i18neditor.common.descrition"), jaxx.runtime.Util.getUIManagerActionIcon("information"), 10)}; +} + +#description { + rows:3; + editable:false; + focusable:false; +} diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/AbstractProjectTabPanelUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/AbstractProjectTabPanelUI.jaxx new file mode 100644 index 0000000..dbdd06f --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/AbstractProjectTabPanelUI.jaxx @@ -0,0 +1,88 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<JPanel id="tabPanel" + abstract='true' + implements='jaxx.runtime.swing.wizard.WizardStepUI<ProjectStep, ProjectUIModel>'> + + <style source='AbstractProjectTabPanelUI.css'/> + + <script><![CDATA[ +import static org.nuiton.i18n.I18n.n_; +import org.nuiton.i18n.editor.I18nEditorContext; +import org.nuiton.i18n.editor.I18nEditorConfig; +import org.nuiton.i18n.editor.ui.I18nEditorUIHandler; +import org.nuiton.i18n.editor.ui.project.ProjectStep; +import org.nuiton.i18n.editor.ui.project.ProjectUIModel; + +import jaxx.runtime.swing.wizard.WizardOperationState; + +protected I18nEditorUIHandler handler = getContextValue(I18nEditorUIHandler.class); +protected I18nEditorConfig config = getContextValue(I18nEditorConfig.class); +protected I18nEditorContext context = getContextValue(I18nEditorContext.class); +protected ProjectUIModel model = getContextValue(ProjectUIModel.class); + +@Override +public ProjectStep getStep() { + return (ProjectStep) getClientProperty("step"); +} + +public ProjectUIModel getModel() { + return model; +} + +protected void setDescriptionText(String text) { + description.setText(text); +} + +protected String getProgressString(int currentStep, int nbStep) { + ProjectStep step = getStep(); + String txt = ""; + if (step != null) { + txt = n_("i18neditor.project.step.label"); + txt = _(txt, currentStep + 1, nbStep, _(step.getLabel())); + } + return txt; +} +]]></script> + + <!-- layout pour la configuration specifique de chaque type de projet + on expose ici le layout sinon cela ne fonctionne pas (layout cree + apres 'content' : a fixer dans JAXX) --> + <jaxx.runtime.swing.CardLayout2Ext id='contentLayout' + constructorParams='this, "content"'/> + + <!-- titre --> + <JPanel layout='{new BorderLayout()}' constraints='BorderLayout.NORTH'> + <JProgressBar id='progress' constraints='BorderLayout.CENTER'/> + </JPanel> + + <!-- content --> + <JPanel id='content' constraints='BorderLayout.CENTER'/> + + <!-- description --> + <JScrollPane id="descriptionPane" constraints='BorderLayout.SOUTH'> + <JTextArea id='description'/> + </JScrollPane> + +</JPanel> diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/ChooseProjectTypePanelUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/ChooseProjectTypePanelUI.jaxx new file mode 100644 index 0000000..9a011d5 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/ChooseProjectTypePanelUI.jaxx @@ -0,0 +1,72 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> +<!-- ***************************************** --> +<!-- L'écran de sélection de type de connexion --> +<!-- ***************************************** --> +<AbstractProjectTabPanelUI _step='{ProjectStep.CHOOSE_PROJECT_TYPE}'> + + <script><![CDATA[ +import org.nuiton.i18n.editor.*; +import org.nuiton.i18n.editor.project.*; +import org.nuiton.i18n.editor.ui.project.*; + +void $afterCompleteSetup() { + // ajout des types de projets connus a partir des providers connus + int index = 0; + for (I18nProjectProvider<?> p : I18nProjectFactory.getProviders()) { + JRadioButton b = new JRadioButton(); + String name = "$JRadioButton" + index; + $objectMap.put( name, b); + b.setName(name); + b.putClientProperty("$buttonGroup", mode); + mode.add(b); + b.setText(_(p.getLabel())); + b.setToolTipText(_(p.getDescription())); + b.putClientProperty("$value", p); + mode.updateSelectedValue(); + content.add(b, new GridBagConstraints(0, index++, 1, 1, 1.0, 0.0, 10, 1, new Insets(3, 3, 3, 3), 0, 0)); + } + // on ecoute les changement de type de projet + model.addPropertyChangeListener(ProjectUIModel.TYPE_PROPERTY_NAME, new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + I18nProjectProvider<?> newMode = (I18nProjectProvider<?>) evt.getNewValue(); + if (newMode != null) { + log.info("new project type : " + newMode); + AbstractButton c = mode.getButton(newMode); + c.setSelected(true); + setDescriptionText(_(newMode.getDescription())); + } + } + }); +} +]]> + </script> + + <ButtonGroup id='mode' + onStateChanged='model.setType((I18nProjectProvider) mode.getSelectedValue())'/> + + <Table id='content' fill='both' weightx='1' constraints='BorderLayout.CENTER'/> + +</AbstractProjectTabPanelUI> diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/ConfigureProjectPanelUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/ConfigureProjectPanelUI.jaxx new file mode 100644 index 0000000..d83ca23 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/ConfigureProjectPanelUI.jaxx @@ -0,0 +1,70 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<AbstractProjectTabPanelUI _step='{ProjectStep.CONFIGURE_PROJECT}'> + + <script><![CDATA[ + +import java.lang.reflect.Constructor; + +import org.nuiton.i18n.editor.*; +import org.nuiton.i18n.editor.project.I18nProjectProvider; +import org.nuiton.i18n.editor.project.I18nProjectFactory; +import org.nuiton.i18n.editor.project.I18nProjectConfigurePanelUI; +import org.nuiton.i18n.editor.ui.project.*; + +protected String updateContentLayout(I18nProjectProvider<?> projectType) { + if (projectType == null) { + return "null"; + } + return projectType.getType().getName(); +} + +void $afterCompleteSetup() { + if (getStep()!=null) { + setDescriptionText(_(getStep().getDescription())); + } + for (I18nProjectProvider<?> p : I18nProjectFactory.getProviders()) { + try { + Class<? extends I18nProjectConfigurePanelUI> c = p.getUIClass(); + Constructor<? extends I18nProjectConfigurePanelUI> constructor = c.getConstructor(jaxx.runtime.JAXXContext.class); + I18nProjectConfigurePanelUI ui = constructor.newInstance(this); + getContent().add((java.awt.Component) ui, p.getType().getName()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} +]]> + </script> + + <jaxx.runtime.swing.CardLayout2Ext id='contentLayout' + selected='{updateContentLayout(model.getType())}'/> + + <JPanel id='content' layout='{contentLayout}'> + + <JLabel text='i18neditor.createproject.no.type' constraints='"null"'/> + + </JPanel> + +</AbstractProjectTabPanelUI> diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/PersistPanelUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/PersistPanelUI.jaxx new file mode 100644 index 0000000..6b0d536 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/PersistPanelUI.jaxx @@ -0,0 +1,174 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<AbstractProjectTabPanelUI _step='{ProjectStep.PERSIST}'> + + <script><![CDATA[ +import jaxx.runtime.SwingUtil; + +import org.nuiton.i18n.editor.*; +import org.nuiton.i18n.editor.project.I18nProject; +import org.nuiton.i18n.editor.project.AbstractI18nProject; +import org.nuiton.i18n.editor.ui.project.*; + +import java.io.File; + +protected final I18nEditorConfig config = getContextValue(I18nEditorConfig.class); + +protected final PropertyChangeListener storeProjectPropertyChangeListener = new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + Boolean oldValue = (Boolean) evt.getOldValue(); + Boolean newValue = (Boolean) evt.getNewValue(); + if (newValue != null && newValue) { + if (getProject().getStoreFile() == null || getProject().getStoreFile().getParentFile() == null) { + getProject().setStoreFile(new File(config.getProjectsDirectory(), model.getProject().getName() + ".i18nproject")); + } + } + } +}; + +public void chooseProjectDirectory() { + File f = model.chooseDirectory ( + this, + _("i18neditor.title.choose.projectDir"), + _("i18neditor.action.choose.projectDir"), + new File(directoryText.getText())); + changeDirectory(f); +} + +public I18nProject getProject() { + return model.getProject(); +} + +protected void changeDirectory(File f) { + getProject().setStoreFile(new File(f, getProject().getName() + ".i18nproject")); +} + +void $afterCompleteSetup() { + if (getStep()!=null) { + setDescriptionText(_(getStep().getDescription())); + } + model.addPropertyChangeListener(ProjectUIModel.PROJECT_PROPERTY_NAME, new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + I18nProject oldProject = (I18nProject) evt.getOldValue(); + if (oldProject!=null) { + oldProject.removePropertyChangeListener(AbstractI18nProject.STORE_PROJECT_PROPERTY_NAME, storeProjectPropertyChangeListener); + } + I18nProject newProject = (I18nProject) evt.getNewValue(); + if (newProject!=null) { + newProject.addPropertyChangeListener(AbstractI18nProject.STORE_PROJECT_PROPERTY_NAME, storeProjectPropertyChangeListener); + } + if (log.isDebugEnabled()) { + log.debug("update binding for changed project " + newProject); + } + SwingUtil.applyDataBinding(PersistPanelUI.this, + "storeProject.selected", + "storeFilePanel.visible", + "directoryText.text", + "storeFilePath.text"); + } + }); +} + +@Override +public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + for (PropertyChangeListener l : getPropertyChangeListeners(propertyName)) { + if (l == listener) { + // already registred listener + if (log.isDebugEnabled()) { + log.debug("already registred listener for property " + propertyName + " : " + listener); + } + return; + } + } + super.addPropertyChangeListener(propertyName, listener); +} + +protected String getStoreDirectory(File storeFile) { + if (storeFile == null || storeFile.getParentFile() == null) { + return ""; + } + return storeFile.getParentFile().getAbsolutePath(); +} +]]> + </script> + + + <JPanel id='content' constraints='BorderLayout.CENTER' layout='{new BorderLayout()}'> + <JPanel constraints='BorderLayout.NORTH' + layout='{new BorderLayout()}' + border='{BorderFactory.createTitledBorder("")}'> + <JCheckBox id='storeProject' + constraints='BorderLayout.CENTER' + text='i18neditor.createproject.doPersist' + selected='{getProject().isStoreProject()}' + onStateChanged='getProject().setStoreProject(((JCheckBox)event.getSource()).isSelected())'/> + </JPanel> + + <Table id='storeFilePanel' + constraints='BorderLayout.CENTER' + visible='{getProject().isStoreProject()}'> + <row> + <cell weightx='1' fill="both"> + <Table fill='both'> + <row> + <cell columns='2'> + <JLabel text='i18neditor.createproject.storeProject.directory'/> + </cell> + </row> + <row> + <cell weightx='1' fill="horizontal"> + <JTextField id='directoryText' + text='{getStoreDirectory(getProject().getStoreFile())}' + onKeyReleased='changeDirectory(new File(((JTextField)event.getSource()).getText()))'/> + <!--visible='{model.getProject().isStoreProject()}'--> + </cell> + <cell anchor="east"> + <JButton actionIcon='fileChooser' + onActionPerformed="chooseProjectDirectory()"/> + <!--visible='{model.getProject().isStoreProject()}'--> + </cell> + </row> + <row> + <cell columns='2'> + <JLabel text='i18neditor.createproject.storeProject.path'/> + <!--visible='{model.getProject().isStoreProject()}'/>--> + </cell> + </row> + <row> + <cell columns='2'> + <JLabel id='storeFilePath' + text='{getProject().getStoreFile() + ""}'/> + <!--visible='{model.getProject().isStoreProject()}'/>--> + </cell> + </row> + </Table> + </cell> + </row> + </Table> + </JPanel> +</AbstractProjectTabPanelUI> diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/ResumePanelUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/ResumePanelUI.jaxx new file mode 100644 index 0000000..4492d5b --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/ResumePanelUI.jaxx @@ -0,0 +1,57 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<AbstractProjectTabPanelUI _step='{ProjectStep.RESUME}'> + + <script><![CDATA[ + +import org.nuiton.i18n.editor.*; +import org.nuiton.i18n.editor.ui.project.*; + +void $afterCompleteSetup() { + if (getStep()!=null) { + setDescriptionText(_(getStep().getDescription())); + } +} + +String computeReport(ProjectUIModel model, ProjectStep step) { + return "TODO"; +} +]]> + </script> + + <JPanel id='content' + constraints='BorderLayout.CENTER' + layout='{new BorderLayout()}'> + <JScrollPane columnHeaderView='{new JLabel(_("i18neditor.common.resume"))}' + constraints='BorderLayout.CENTER'> + <JTextArea id='resume' + text='{computeReport(model, model.getStep())}' + editable='false' + focusable='false' + rows='10' + /> + </JScrollPane> + </JPanel> + +</AbstractProjectTabPanelUI> diff --git a/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/SelectBundlesPanelUI.jaxx b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/SelectBundlesPanelUI.jaxx new file mode 100644 index 0000000..af3ae05 --- /dev/null +++ b/nuiton-i18n-editor/src/main/java/org/nuiton/i18n/editor/ui/project/tabs/SelectBundlesPanelUI.jaxx @@ -0,0 +1,57 @@ +<!-- + +/** + * *##% Nuiton I18n Editor + * Copyright (C) 2008 - 2009 CodeLutin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. ##%* + */ + +--> + +<AbstractProjectTabPanelUI _step='{ProjectStep.SELECT_BUNDLES}'> + + <script><![CDATA[ +import jaxx.runtime.SwingUtil; + +import org.nuiton.i18n.editor.*; +import org.nuiton.i18n.editor.ui.project.*; + + +void $afterCompleteSetup() { + if (getStep() != null) { + setDescriptionText(_(getStep().getDescription())); + } +} +]]> + </script> + + <SelectBundlesTableModel id='bundlesModel' + onTableChanged='model.getProject().setUrls(bundlesModel.getSelectedUrls())'/> + + <Table id='content' constraints='BorderLayout.CENTER' fill='both' weightx='1' weighty='1'> + <row> + <cell> + <JScrollPane columnHeaderView="{bundles.getTableHeader()}" + verticalScrollBarPolicy="{JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED}"> + + <JTable id='bundles' + model='{bundlesModel}'/> + </JScrollPane> + </cell> + </row> + </Table> + +</AbstractProjectTabPanelUI> diff --git a/nuiton-i18n-editor/src/main/jnlp/jxlayer.jnlp b/nuiton-i18n-editor/src/main/jnlp/jxlayer.jnlp new file mode 100644 index 0000000..9f90ec8 --- /dev/null +++ b/nuiton-i18n-editor/src/main/jnlp/jxlayer.jnlp @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<jnlp spec="1.0+" codebase="@url@" href="jxlayer.jnlp"> + <information> + <title>Swing X</title> + <vendor>Swing X</vendor> + <offline-allowed/> + </information> + <resources> + <jar href="lib/@lib@"/> + </resources> + <component-desc/> +</jnlp> \ No newline at end of file diff --git a/nuiton-i18n-editor/src/main/jnlp/sun.jnlp b/nuiton-i18n-editor/src/main/jnlp/sun.jnlp new file mode 100644 index 0000000..f345d95 --- /dev/null +++ b/nuiton-i18n-editor/src/main/jnlp/sun.jnlp @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<jnlp spec="1.0+" codebase="@url@" href="sun.jnlp"> + <information> + <title>Sun MicroSystems</title> + <vendor>Sun MicroSystems, Inc.</vendor> + <offline-allowed/> + </information> + <resources> + <jar href="lib/@lib@"/> + </resources> + <component-desc/> +</jnlp> \ No newline at end of file diff --git a/nuiton-i18n-editor/src/main/resources/META-INF/services/org.nuiton.i18n.editor.project.I18nProjectProvider b/nuiton-i18n-editor/src/main/resources/META-INF/services/org.nuiton.i18n.editor.project.I18nProjectProvider new file mode 100644 index 0000000..11ba62d --- /dev/null +++ b/nuiton-i18n-editor/src/main/resources/META-INF/services/org.nuiton.i18n.editor.project.I18nProjectProvider @@ -0,0 +1,2 @@ +org.nuiton.i18n.editor.project.impl.JarI18nProjectProvider +org.nuiton.i18n.editor.project.impl.DirectoryI18nProjectProvider diff --git a/nuiton-i18n-editor/src/main/resources/i18n/nuiton-i18n-editor-en_GB.properties b/nuiton-i18n-editor/src/main/resources/i18n/nuiton-i18n-editor-en_GB.properties new file mode 100644 index 0000000..dbd0bbb --- /dev/null +++ b/nuiton-i18n-editor/src/main/resources/i18n/nuiton-i18n-editor-en_GB.properties @@ -0,0 +1,120 @@ +i18neditor.about.message=<h3>Nuiton i18n editor</h3><hr/><p>Project realised by <a href\="http\://codelutin.com">Codelutin</a> in 2009.</p><br/><hr/>For more information, visit the <a href\="http\://maven-site.nuiton.org/i18n/i18neditor">project's site</a>. +i18neditor.action.about=About +i18neditor.action.about.tip=Show about screen +i18neditor.action.apply=Apply +i18neditor.action.apply.tip= +i18neditor.action.cancel=Cancel +i18neditor.action.cancel.tip=Cancel +i18neditor.action.choose.directory.source.description= +i18neditor.action.choose.jar.source= +i18neditor.action.choose.jar.source.description= +i18neditor.action.choose.project= +i18neditor.action.choose.project.description= +i18neditor.action.choose.projectDir= +i18neditor.action.closeProject=Close the project +i18neditor.action.commandline.configure=Configure the application +i18neditor.action.commandline.disable.main.ui=Do not launch main ui +i18neditor.action.commandline.help=Show this help +i18neditor.action.configuration=Preferences +i18neditor.action.configuration.tip=show preferences screen +i18neditor.action.create=Create +i18neditor.action.createProject=Create project +i18neditor.action.delete.key.tip= +i18neditor.action.deleteProject=Delete project +i18neditor.action.editProject=Modify project +i18neditor.action.exit=Exit +i18neditor.action.exit.tip=Quit +i18neditor.action.fullscreen=Full screen +i18neditor.action.fullscreen.tip=Go into full screen mode +i18neditor.action.goto.next.stage=Continue +i18neditor.action.goto.next.stage.tip= +i18neditor.action.goto.previous.stage=Go back +i18neditor.action.goto.previous.stage.tip= +i18neditor.action.help=Show help +i18neditor.action.help.tip=Show help +i18neditor.action.new.bundle=New +i18neditor.action.new.package=New +i18neditor.action.normalscreen=Frame mode +i18neditor.action.normalscreen.tip=Go back in frame mode +i18neditor.action.openOtherProject=Open other project +i18neditor.action.openProject=Open a project +i18neditor.action.reset.value.tip= +i18neditor.action.save.value.tip= +i18neditor.action.showHelp.tip=Show context sensitve help +i18neditor.action.site=Website +i18neditor.action.site.tip=Go to web site of application +i18neditor.bundle.name=Locale \: %1$s +i18neditor.choose.project.to.delete= +i18neditor.common.descrition= +i18neditor.common.resume=Resume +i18neditor.config.category.directories=Directories +i18neditor.config.category.directories.description=Directories used by the application +i18neditor.config.category.ui=Application +i18neditor.config.category.ui.description=Other options used by the application +i18neditor.config.configFileName.description=configuration file +i18neditor.config.defaultProjectsDirectory.description=default directory where to store project definitions (*.i18nproject) +i18neditor.config.defaultTmpDirectory.description=tempory directory used by the application +i18neditor.config.ui.fullscreen=choose initial ui mode (true for full screen, false otherwise) +i18neditor.config.ui.locale=Language used by application (fr_FR, en_GB) +i18neditor.createProject.table.bundles.select= +i18neditor.createProject.table.bundles.select.tip= +i18neditor.createProject.table.bundles.url= +i18neditor.createProject.table.bundles.url.tip= +i18neditor.createbundle.label=Create a new bundle for all packages known +i18neditor.createbundle.newlanguage=NEw language +i18neditor.createbundle.newlocale=New locale +i18neditor.createbundle.title=Create bundle +i18neditor.createpackage.label=Create a new package (for all bundles known) +i18neditor.createpackage.newpackage=NEw language +i18neditor.createpackage.title=Create package +i18neditor.createproject.common.select= +i18neditor.createproject.directory.source.label= +i18neditor.createproject.doPersist= +i18neditor.createproject.jar.source.label= +i18neditor.createproject.name.label= +i18neditor.createproject.no.type= +i18neditor.createproject.storeProject.directory= +i18neditor.createproject.storeProject.path= +i18neditor.createproject.uniqueJarDefinition= +i18neditor.createproject.uniqueJarDefinition.tip= +i18neditor.createproject.url= +i18neditor.init.closed=Application was closed at %1$s +i18neditor.init.context.done=Initialisation of context done in %1$s. +i18neditor.init.ui.done=GUI initialized +i18neditor.main.menu.file=File +i18neditor.menu.bundles=Bundles +i18neditor.menu.help=Help +i18neditor.menu.packages=Packages +i18neditor.menu.storeall=Save all +i18neditor.message.config.loaded=Config of nuiton-i18n-editor v %1$s was loaded. +i18neditor.message.help.usage=Help of nuiton-i18n-editor v %1$s +i18neditor.message.no.project.loaded=< No project loaded > +i18neditor.no.keys=< No defined key > +i18neditor.package.name=Package \: %1$s +i18neditor.project.info.tip=Click here to display project's informations +i18neditor.project.step.chooseProjectType= +i18neditor.project.step.chooseProjectType.description= +i18neditor.project.step.configureProject= +i18neditor.project.step.configureProject.description= +i18neditor.project.step.label= +i18neditor.project.step.persist= +i18neditor.project.step.persist.description= +i18neditor.project.step.resume= +i18neditor.project.step.resume.description= +i18neditor.project.step.selecteBundles= +i18neditor.project.step.selecteBundles.description= +i18neditor.project.type.directory= +i18neditor.project.type.directory.description= +i18neditor.project.type.jar= +i18neditor.project.type.jar.description= +i18neditor.resource.name=Resource \: %1$s +i18neditor.title=Nuiton i18n editor < Project %1$s > +i18neditor.title.about=About Nuiton i18n editor +i18neditor.title.choose.directory.source= +i18neditor.title.choose.jar.source= +i18neditor.title.choose.project= +i18neditor.title.choose.projectDir= +i18neditor.title.noproject=Nuiton i18n editor < no project loaded > +i18neditor.title.project.info=Project's informations +i18neditor.warning.nimbus.landf=Could not find nymbus look and feel, please use at least a 1.6u10 version of sun jre +i18neditor.warning.no.ui=No ui environment detected\! diff --git a/nuiton-i18n-editor/src/main/resources/i18n/nuiton-i18n-editor-fr_FR.properties b/nuiton-i18n-editor/src/main/resources/i18n/nuiton-i18n-editor-fr_FR.properties new file mode 100644 index 0000000..78ed8ee --- /dev/null +++ b/nuiton-i18n-editor/src/main/resources/i18n/nuiton-i18n-editor-fr_FR.properties @@ -0,0 +1,120 @@ +i18neditor.about.message=<h3>Nuiton i18n editor</h3><hr/><p>Projet r\u00E9alis\u00E9 par la soci\u00E9t\u00E9 <a href\="http\://codelutin.com">Codelutin</a> en 2009.</p><br/><hr/>Pour plus d'informations, vous pouvez visiter le <a href\="http\://maven-site.nuiton.org/i18n/i18neditor">site du projet</a>. +i18neditor.action.about=A propos +i18neditor.action.about.tip=Afficher l'a propos +i18neditor.action.apply=Appliquer +i18neditor.action.apply.tip=Appliquer +i18neditor.action.cancel=Annuler +i18neditor.action.cancel.tip=Annuler +i18neditor.action.choose.directory.source.description=R\u00E9pertoire +i18neditor.action.choose.jar.source=Choisir ce jar +i18neditor.action.choose.jar.source.description=Fichier jar (*.jar) +i18neditor.action.choose.project=Choisir ce projet +i18neditor.action.choose.project.description=Fichier de d\u00E9finition de project (*.i18nproject) +i18neditor.action.choose.projectDir=Choisir ce r\u00E9pertoire +i18neditor.action.closeProject=Fermer le projet +i18neditor.action.commandline.configure=Configurer l'application +i18neditor.action.commandline.disable.main.ui=Ne pas lancer l'interface graphique principale +i18neditor.action.commandline.help=Voir l'aide +i18neditor.action.configuration=Pr\u00E9f\u00E9rences +i18neditor.action.configuration.tip=Modifier les pr\u00E9f\u00E9rences +i18neditor.action.create=Cr\u00E9er +i18neditor.action.createProject=Cr\u00E9er un projet +i18neditor.action.delete.key.tip=Supprimer cette traduction +i18neditor.action.deleteProject=Supprimer un projet +i18neditor.action.editProject=Modifier le projet +i18neditor.action.exit=Quitter +i18neditor.action.exit.tip=Quitter l'application +i18neditor.action.fullscreen=Plein \u00E9cran +i18neditor.action.fullscreen.tip=Passer en mode Plein \u00E9cran +i18neditor.action.goto.next.stage=Continuer +i18neditor.action.goto.next.stage.tip=Continuer vers l'\u00E9tape suivante +i18neditor.action.goto.previous.stage=Revenir +i18neditor.action.goto.previous.stage.tip=Revenir \u00E0 l'\u00E9tape pr\u00E9c\u00E9dente +i18neditor.action.help=Aide +i18neditor.action.help.tip=Affichier l'aide +i18neditor.action.new.bundle=Nouveau +i18neditor.action.new.package=Nouveau +i18neditor.action.normalscreen=Mode fen\u00EAtre +i18neditor.action.normalscreen.tip=retour en mode fen\u00EAtre +i18neditor.action.openOtherProject=Ouvrir un projet (autre r\u00E9pertoire) +i18neditor.action.openProject=Ouvrir un projet... +i18neditor.action.reset.value.tip=R\u00E9initialiser +i18neditor.action.save.value.tip=Sauver la traduction modifi\u00E9e +i18neditor.action.showHelp.tip=Voir l'aide contextuelle +i18neditor.action.site=Site +i18neditor.action.site.tip=Acc\u00E9der au site du projet +i18neditor.bundle.name=Localisation \: %1$s +i18neditor.choose.project.to.delete=Choisir le projet \u00E0 supprimer +i18neditor.common.descrition=Description +i18neditor.common.resume=R\u00E9sum\u00E9 +i18neditor.config.category.directories=R\u00E9pertoires +i18neditor.config.category.directories.description=Les r\u00E9pertoires utilis\u00E9es par l'application +i18neditor.config.category.ui=Application +i18neditor.config.category.ui.description=Les autres options de l'application +i18neditor.config.configFileName.description=Le nom du fichier de configuration +i18neditor.config.defaultProjectsDirectory.description=Le r\u00E9pertoire o\u00F9 sont sauvegarder les d\u00E9finitions de projets +i18neditor.config.defaultTmpDirectory.description=Le r\u00E9pertoire temporaire par d\u00E9faut +i18neditor.config.ui.fullscreen=Pour afficher l'aplication en mode pleine \u00E9cran +i18neditor.config.ui.locale=Langue utilis\u00E9e par l'application (fr_FR, en_GB) +i18neditor.createProject.table.bundles.select=... +i18neditor.createProject.table.bundles.select.tip=S\u00E9lectionner - D\u00E9selectionner toutes les urls +i18neditor.createProject.table.bundles.url=Localisation +i18neditor.createProject.table.bundles.url.tip=location du bundle +i18neditor.createbundle.label=Cr\u00E9er un nouveau bundle pour les paquetages donn\u00E9es +i18neditor.createbundle.newlanguage=Langue +i18neditor.createbundle.newlocale=Pays +i18neditor.createbundle.title=Nouveau bundle +i18neditor.createpackage.label=Cr\u00E9er un nouveau paquetage (pour tous les bundles connus) +i18neditor.createpackage.newpackage=Nouveau paquetage +i18neditor.createpackage.title=Cr\u00E9er un nouveau paquetage +i18neditor.createproject.common.select=... +i18neditor.createproject.directory.source.label=R\u00E9pertoire de sauvegarde +i18neditor.createproject.doPersist=Sauver la d\u00E9finition du projet +i18neditor.createproject.jar.source.label=Choisir le jar source +i18neditor.createproject.name.label=Nom du projet +i18neditor.createproject.no.type=< Aucune type de projet s\u00E9lectionn\u00E9 > +i18neditor.createproject.storeProject.directory=R\u00E9pertoire de sauvegarde +i18neditor.createproject.storeProject.path=Fichier de sauvegarde +i18neditor.createproject.uniqueJarDefinition=Utilisation d'un bundle final +i18neditor.createproject.uniqueJarDefinition.tip=Utilisation d'un bundle final (un seul bundle) +i18neditor.createproject.url=Localisation +i18neditor.init.closed=Nuiton-i18n-editor a \u00E9t\u00E9 ferm\u00E9 \u00E0 %1$s +i18neditor.init.context.done=Initialisation du contexte termin\u00E9e en %1$s. +i18neditor.init.ui.done=Initialisation de l'interface graphique termin\u00E9e. +i18neditor.main.menu.file=Fichier +i18neditor.menu.bundles=Bundles +i18neditor.menu.help=Aide +i18neditor.menu.packages=Paquetages +i18neditor.menu.storeall=Sauvegarder +i18neditor.message.config.loaded=Configuration de nuiton-i18n-editor v. %1$s charg\u00E9e. +i18neditor.message.help.usage=Aide de nuiton-i18n-editor v %1$s +i18neditor.message.no.project.loaded=< Aucun projet charg\u00E9 > +i18neditor.no.keys=< Aucune clef definie > +i18neditor.package.name=Paquetage \: %1$s +i18neditor.project.info.tip=Cliquer ici pour obtenir des informations sur le projet charg\u00E9 +i18neditor.project.step.chooseProjectType=Type de projet +i18neditor.project.step.chooseProjectType.description=Choisir le type de projet \u00E0 ouvrir +i18neditor.project.step.configureProject=Configuration +i18neditor.project.step.configureProject.description=Configurer le projet +i18neditor.project.step.label=Etape %1$d/%2$d \: %3$s +i18neditor.project.step.persist=Sauvegarde +i18neditor.project.step.persist.description=Permet de sauvegarder la d\u00E9finition du projet +i18neditor.project.step.resume=Resume +i18neditor.project.step.resume.description=Voir le r\u00E9sum\u00E9 du projet \u00E0 ouvrir +i18neditor.project.step.selecteBundles=Bundles +i18neditor.project.step.selecteBundles.description=Choisir les bundles du projet parmi ceux d\u00E9tect\u00E9s +i18neditor.project.type.directory=R\u00E9pertoire +i18neditor.project.type.directory.description=Ouvrir un projet \u00E0 partir d'un r\u00E9pertoire +i18neditor.project.type.jar=Jar (ou zip) +i18neditor.project.type.jar.description=Ouvrir un projet \u00E0 partir d'un jar +i18neditor.resource.name=Resource \: %1$s +i18neditor.title=Nuiton i18n editor < Projet %1$s > +i18neditor.title.about=A propos de nuiton-i18n-editor... +i18neditor.title.choose.directory.source=Choisir le r\u00E9pertoire +i18neditor.title.choose.jar.source=Choisir un fichier de type 'jar' +i18neditor.title.choose.project=Choisir le fichier de d\u00E9finition d'un projet +i18neditor.title.choose.projectDir=Choisir une d\u00E9finition de projet +i18neditor.title.noproject=Nuiton i18n editor < aucun projet charg\u00E9 > +i18neditor.title.project.info=Informations sur le projet +i18neditor.warning.nimbus.landf=Le look and Feel Nimbus n'a pas \u00E9t\u00E9 trouv\u00E9, il faut au moins la version 1.6u10 de java. +i18neditor.warning.no.ui=Aucun environnement graphique d\u00E9tect\u00E9 diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-about.png b/nuiton-i18n-editor/src/main/resources/icons/action-about.png new file mode 100644 index 0000000..0d826bb Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-about.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-accept.png b/nuiton-i18n-editor/src/main/resources/icons/action-accept.png new file mode 100644 index 0000000..89c8129 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-accept.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-add.png b/nuiton-i18n-editor/src/main/resources/icons/action-add.png new file mode 100644 index 0000000..6332fef Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-add.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-calculator.png b/nuiton-i18n-editor/src/main/resources/icons/action-calculator.png new file mode 100644 index 0000000..701a60a Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-calculator.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-cancel.png b/nuiton-i18n-editor/src/main/resources/icons/action-cancel.png new file mode 100644 index 0000000..c149c2b Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-cancel.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-close.png b/nuiton-i18n-editor/src/main/resources/icons/action-close.png new file mode 100644 index 0000000..2541d2b Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-close.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-closeTab.png b/nuiton-i18n-editor/src/main/resources/icons/action-closeTab.png new file mode 100644 index 0000000..93edaf0 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-closeTab.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-collapseAll.png b/nuiton-i18n-editor/src/main/resources/icons/action-collapseAll.png new file mode 100644 index 0000000..f88a24a Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-collapseAll.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-combobox-reset.png b/nuiton-i18n-editor/src/main/resources/icons/action-combobox-reset.png new file mode 100644 index 0000000..0fb00f9 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-combobox-reset.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-combobox-sort.png b/nuiton-i18n-editor/src/main/resources/icons/action-combobox-sort.png new file mode 100644 index 0000000..188e1c1 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-combobox-sort.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-config.png b/nuiton-i18n-editor/src/main/resources/icons/action-config.png new file mode 100644 index 0000000..9460dfc Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-config.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-connect_creating.png b/nuiton-i18n-editor/src/main/resources/icons/action-connect_creating.png new file mode 100644 index 0000000..258b65b Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-connect_creating.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-connect_no.png b/nuiton-i18n-editor/src/main/resources/icons/action-connect_no.png new file mode 100644 index 0000000..3c832d4 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-connect_no.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-connect_ok.png b/nuiton-i18n-editor/src/main/resources/icons/action-connect_ok.png new file mode 100644 index 0000000..2bd16cc Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-connect_ok.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-connect_untested.png b/nuiton-i18n-editor/src/main/resources/icons/action-connect_untested.png new file mode 100644 index 0000000..61a8556 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-connect_untested.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-connected.png b/nuiton-i18n-editor/src/main/resources/icons/action-connected.png new file mode 100644 index 0000000..024138e Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-connected.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-db-change.png b/nuiton-i18n-editor/src/main/resources/icons/action-db-change.png new file mode 100644 index 0000000..3a11197 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-db-change.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-db-local.png b/nuiton-i18n-editor/src/main/resources/icons/action-db-local.png new file mode 100644 index 0000000..fed6221 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-db-local.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-db-none.png b/nuiton-i18n-editor/src/main/resources/icons/action-db-none.png new file mode 100644 index 0000000..cce652e Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-db-none.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-db-remote.png b/nuiton-i18n-editor/src/main/resources/icons/action-db-remote.png new file mode 100644 index 0000000..49b2691 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-db-remote.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-delete.png b/nuiton-i18n-editor/src/main/resources/icons/action-delete.png new file mode 100644 index 0000000..184f762 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-delete.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-edit.png b/nuiton-i18n-editor/src/main/resources/icons/action-edit.png new file mode 100644 index 0000000..188e1c1 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-edit.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-exit.png b/nuiton-i18n-editor/src/main/resources/icons/action-exit.png new file mode 100644 index 0000000..a77152b Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-exit.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-expandAll.png b/nuiton-i18n-editor/src/main/resources/icons/action-expandAll.png new file mode 100644 index 0000000..3c19e48 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-expandAll.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-fileChooser.png b/nuiton-i18n-editor/src/main/resources/icons/action-fileChooser.png new file mode 100644 index 0000000..523a651 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-fileChooser.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-fullscreen.png b/nuiton-i18n-editor/src/main/resources/icons/action-fullscreen.png new file mode 100644 index 0000000..6845e04 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-fullscreen.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-go-back.png b/nuiton-i18n-editor/src/main/resources/icons/action-go-back.png new file mode 100644 index 0000000..5dc6967 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-go-back.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-go-detail.png b/nuiton-i18n-editor/src/main/resources/icons/action-go-detail.png new file mode 100644 index 0000000..aba044b Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-go-detail.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-go-down.png b/nuiton-i18n-editor/src/main/resources/icons/action-go-down.png new file mode 100644 index 0000000..2c4e279 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-go-down.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-go-jump.png b/nuiton-i18n-editor/src/main/resources/icons/action-go-jump.png new file mode 100644 index 0000000..1d218c3 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-go-jump.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-go-up.png b/nuiton-i18n-editor/src/main/resources/icons/action-go-up.png new file mode 100644 index 0000000..1ebb193 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-go-up.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-help.png b/nuiton-i18n-editor/src/main/resources/icons/action-help.png new file mode 100644 index 0000000..4ed65a9 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-help.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-i18n-es.png b/nuiton-i18n-editor/src/main/resources/icons/action-i18n-es.png new file mode 100644 index 0000000..c2de2d7 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-i18n-es.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-i18n-fr.png b/nuiton-i18n-editor/src/main/resources/icons/action-i18n-fr.png new file mode 100644 index 0000000..8332c4e Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-i18n-fr.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-i18n-gb.png b/nuiton-i18n-editor/src/main/resources/icons/action-i18n-gb.png new file mode 100644 index 0000000..ff701e1 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-i18n-gb.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-import-gps.png b/nuiton-i18n-editor/src/main/resources/icons/action-import-gps.png new file mode 100644 index 0000000..68f21d3 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-import-gps.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-information.png b/nuiton-i18n-editor/src/main/resources/icons/action-information.png new file mode 100644 index 0000000..12cd1ae Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-information.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-leave-fullscreen.png b/nuiton-i18n-editor/src/main/resources/icons/action-leave-fullscreen.png new file mode 100644 index 0000000..fc6638e Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-leave-fullscreen.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-local-export.png b/nuiton-i18n-editor/src/main/resources/icons/action-local-export.png new file mode 100644 index 0000000..91e3b24 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-local-export.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-local-import.png b/nuiton-i18n-editor/src/main/resources/icons/action-local-import.png new file mode 100644 index 0000000..cafac61 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-local-import.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-mode-create.png b/nuiton-i18n-editor/src/main/resources/icons/action-mode-create.png new file mode 100644 index 0000000..e2f0847 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-mode-create.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-mode-read.png b/nuiton-i18n-editor/src/main/resources/icons/action-mode-read.png new file mode 100644 index 0000000..d8e23ec Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-mode-read.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-mode-update.png b/nuiton-i18n-editor/src/main/resources/icons/action-mode-update.png new file mode 100644 index 0000000..6e756cc Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-mode-update.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-next-step.png b/nuiton-i18n-editor/src/main/resources/icons/action-next-step.png new file mode 100644 index 0000000..6ef8de7 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-next-step.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-open.png b/nuiton-i18n-editor/src/main/resources/icons/action-open.png new file mode 100644 index 0000000..41676a0 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-open.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-previous-step.png b/nuiton-i18n-editor/src/main/resources/icons/action-previous-step.png new file mode 100644 index 0000000..659cd90 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-previous-step.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-remote-export.png b/nuiton-i18n-editor/src/main/resources/icons/action-remote-export.png new file mode 100644 index 0000000..44c06dd Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-remote-export.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-remote-import.png b/nuiton-i18n-editor/src/main/resources/icons/action-remote-import.png new file mode 100644 index 0000000..ff803be Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-remote-import.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-revert.png b/nuiton-i18n-editor/src/main/resources/icons/action-revert.png new file mode 100644 index 0000000..197b8a7 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-revert.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-save.png b/nuiton-i18n-editor/src/main/resources/icons/action-save.png new file mode 100644 index 0000000..41b3f43 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-save.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-select-ssl-cert.png b/nuiton-i18n-editor/src/main/resources/icons/action-select-ssl-cert.png new file mode 100644 index 0000000..ca93f0d Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-select-ssl-cert.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-show-help.png b/nuiton-i18n-editor/src/main/resources/icons/action-show-help.png new file mode 100644 index 0000000..f6bc721 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-show-help.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-site.png b/nuiton-i18n-editor/src/main/resources/icons/action-site.png new file mode 100644 index 0000000..ac5957a Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-site.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-synch.png b/nuiton-i18n-editor/src/main/resources/icons/action-synch.png new file mode 100644 index 0000000..3fd71d6 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-synch.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-synchro-pause.png b/nuiton-i18n-editor/src/main/resources/icons/action-synchro-pause.png new file mode 100644 index 0000000..2d9ce9c Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-synchro-pause.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-synchro-start.png b/nuiton-i18n-editor/src/main/resources/icons/action-synchro-start.png new file mode 100644 index 0000000..0846555 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-synchro-start.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-synchro-stop.png b/nuiton-i18n-editor/src/main/resources/icons/action-synchro-stop.png new file mode 100644 index 0000000..893bb60 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-synchro-stop.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-translate.png b/nuiton-i18n-editor/src/main/resources/icons/action-translate.png new file mode 100644 index 0000000..63ce64d Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-translate.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-unconnected.png b/nuiton-i18n-editor/src/main/resources/icons/action-unconnected.png new file mode 100644 index 0000000..b335cb1 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-unconnected.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/action-validate.png b/nuiton-i18n-editor/src/main/resources/icons/action-validate.png new file mode 100644 index 0000000..a9925a0 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/action-validate.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/logo OT_rvb.png b/nuiton-i18n-editor/src/main/resources/icons/logo OT_rvb.png new file mode 100644 index 0000000..1c35a25 Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/logo OT_rvb.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/logo-OT_web.png b/nuiton-i18n-editor/src/main/resources/icons/logo-OT_web.png new file mode 100644 index 0000000..e6b87bd Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/logo-OT_web.png differ diff --git a/nuiton-i18n-editor/src/main/resources/icons/logo_ird.png b/nuiton-i18n-editor/src/main/resources/icons/logo_ird.png new file mode 100644 index 0000000..87405cc Binary files /dev/null and b/nuiton-i18n-editor/src/main/resources/icons/logo_ird.png differ diff --git a/nuiton-i18n-editor/src/main/resources/log4j.properties b/nuiton-i18n-editor/src/main/resources/log4j.properties new file mode 100644 index 0000000..ee9f182 --- /dev/null +++ b/nuiton-i18n-editor/src/main/resources/log4j.properties @@ -0,0 +1,14 @@ +# Global logging configuration +log4j.rootLogger=ERROR, stdout +# Console output... +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) %M - %m%n +#log4j.appender.stdout.layout.ConversionPattern=%%c=%c %%C=%C %%d=%d %%F=%F %%l=%l %%L=%L %%m=%m %%M=%M %%p=%p %%r=%r %%t=%t %%x=%x %%X=%X +# package level +log4j.logger.org.nuiton=WARN +log4j.logger.org.nuiton.i18n.editor=INFO +#log4j.logger.org.nuiton.util.Resource=DEBUG +#log4j.logger.org.nuiton.i18n.editor.I18nEditorConfig=DEBUG +log4j.logger.jaxx.runtime.swing.editor.config=DEBUG +log4j.logger.jaxx.runtime.swing.editor=DEBUG diff --git a/nuiton-i18n-editor/src/site/apt/index.apt b/nuiton-i18n-editor/src/site/apt/index.apt new file mode 100644 index 0000000..fc25dc0 --- /dev/null +++ b/nuiton-i18n-editor/src/site/apt/index.apt @@ -0,0 +1,25 @@ +---- +Nuiton-i18n-editor +---- +---- +2009-08-22 +---- + +Présentation + + Application swing pour éditer des bundles i18n. + +Set it in action from Web + +~~[images/webstart.gif] webstart + + To run this application in + {{{http://java.sun.com/products/javawebstart/} Java Web Start}}, + click the {{{launch-nuiton-i18n-editor.jnlp}following link}}. + + Actually does not work very well, prefer use the zip version... + +Set it in action from Zip + + You can download at the section download the zip file, extract it and then + launch <go.sh> or <go.bat>. diff --git a/nuiton-i18n-editor/src/site/site.xml b/nuiton-i18n-editor/src/site/site.xml new file mode 100644 index 0000000..65b8a30 --- /dev/null +++ b/nuiton-i18n-editor/src/site/site.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="${project.name}"> + + <skin> + <groupId>org.nuiton</groupId> + <artifactId>maven-nuiton-skin</artifactId> + <version>1.0.0</version> + </skin> + + <bannerLeft> + <name>${project.name}</name> + <href>index.html</href> + </bannerLeft> + + <bannerRight> + <src>http://www.codelutin.com/images/lutinorange-codelutin.png</src> + <href>${project.organization.url}</href> + </bannerRight> + + <poweredBy> + <logo href="http://maven-site.nuiton.org/jaxx" name="JAXX" img="images/jaxx-logo.png"/> + <logo href="http://jrst.labs.libre-entreprise.org/jrst" name="JRst" + img="images/jrst-logo.png"/> + + <logo href="http://docutils.sourceforge.net/rst.html" name="ReStructuredText" + img="images/restructuredtext-logo.png"/> + </poweredBy> + + <body> + + <breadcrumbs> + <item name="${project.name}" href="${project.url}" /> + </breadcrumbs> + + <menu name="Utilisateur"> + <item name="Accueil" href="index.html"/> + <item href="launch-${project.artifactId}.jnlp" + src="images/webstart.gif" + name="Démarrer la dernière version"/> + <item href="${project.build.finalName}-bin.zip" + name="Télécharger la dernière version"/> + </menu> + + <menu name="Développeur"> + <item name="A faire" href="Todo.html"/> + </menu> + + <menu ref="reports"/> + + </body> +</project> diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..0d74e8e --- /dev/null +++ b/pom.xml @@ -0,0 +1,147 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <!-- ************************************************************* --> + <!-- *** POM Relationships *************************************** --> + <!-- ************************************************************* --> + <parent> + <groupId>org.nuiton</groupId> + <artifactId>mavenpom</artifactId> + <version>1.0.0</version> + </parent> + + <artifactId>i18n</artifactId> + <version>1.0.0</version> + + <modules> + <module>nuiton-i18n-api</module> + <module>maven-i18n-plugin</module> + <!--module>nuiton-i18n-editor</module--> + </modules> + + <dependencyManagement> + <dependencies> + + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.1.1</version> + </dependency> + + <dependency> + <groupId>commons-beanutils</groupId> + <artifactId>commons-beanutils</artifactId> + <version>1.8.0</version> + </dependency> + + <dependency> + <groupId>org.nuiton.processor</groupId> + <artifactId>nuiton-processor</artifactId> + <version>${processor.version}</version> + </dependency> + + <dependency> + <groupId>org.nuiton</groupId> + <artifactId>maven-helper-plugin</artifactId> + <version>${helper.version}</version> + <type>maven-plugin</type> + </dependency> + + <dependency> + <groupId>xalan</groupId> + <artifactId>xalan</artifactId> + <version>2.7.1</version> + </dependency> + + <dependency> + <groupId>commons-collections</groupId> + <artifactId>commons-collections</artifactId> + <version>3.1</version> + </dependency> + + <!-- tests dependencies --> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.6</version> + <scope>test</scope> + </dependency> + + <!--dependency> + <groupId>org.nuiton</groupId> + <artifactId>maven-helper-plugin</artifactId> + <version>${helper.version}</version> + <scope>test</scope> + <classifier>tests</classifier> + </dependency--> + + <!-- provided dependencies --> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-project</artifactId> + <version>${maven.version}</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-plugin-api</artifactId> + <version>${maven.version}</version> + <scope>provided</scope> + </dependency> + + <!-- FIXME si on ne le rajoute pas, on se retrouve avec la version 1.1 qui ne convient pas --> + <dependency> + <groupId>org.codehaus.plexus</groupId> + <artifactId>plexus-utils</artifactId> + <version>1.5.15</version> + <scope>compile</scope> + </dependency> + + </dependencies> + </dependencyManagement> + + <!-- ************************************************************* --> + <!-- *** Project Information ************************************* --> + <!-- ************************************************************* --> + <name>nuiton-i18n - pom</name> + <description>Nuiton i18n tools</description> + <inceptionYear>2008</inceptionYear> + <url>http://maven-site.nuiton.org/i18n</url> + + <!-- ************************************************************* --> + <!-- *** Build Settings ****************************************** --> + <!-- ************************************************************* --> + + <packaging>pom</packaging> + + <properties> + <!-- pour un muli module on doit fixer le projectId --> + <projectId>i18n</projectId> + + <processor.version>1.0.0</processor.version> + + </properties> + + <build> + + <defaultGoal>install</defaultGoal> + + </build> + + <!-- ************************************************************* --> + <!-- *** Build Environment ************************************** --> + <!-- ************************************************************* --> + + <!-- Source control management. --> + <scm> + <connection>scm:svn:http://svn.nuiton.org/svn/i18n/tags/i18n-1.0.0</connection> + <developerConnection>scm:svn:http://svn.nuiton.org/svn/i18n/tags/i18n-1.0.0</developerConnection> + <url>http://www.nuiton.org/repositories/browse/i18n/tags/i18n-1.0.0</url> + </scm> + +</project> + diff --git a/src/site/site.xml b/src/site/site.xml new file mode 100644 index 0000000..644dfdc --- /dev/null +++ b/src/site/site.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="${project.name}"> + + <publishDate format="dd/MM/yyyy"/> + + <skin> + <groupId>org.nuiton</groupId> + <artifactId>maven-nuiton-skin</artifactId> + <version>1.0.0</version> + </skin> + + <bannerLeft> + <name>${project.name}</name> + <href>index.html</href> + </bannerLeft> + + <bannerRight> + <src>http://www.codelutin.com/images/lutinorange-codelutin.png</src> + <href>${project.organization.url}</href> + </bannerRight> + + <poweredBy> + <logo href="http://maven.apache.org" name="Maven" img="${project.url}/images/logos/maven-feather.png"/> + </poweredBy> + + <body> + + <breadcrumbs> + <item name="${project.name}" href="${project.url}" /> + </breadcrumbs> + + <menu ref="modules"/> + + <menu ref="reports"/> + </body> +</project> -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.
participants (1)
-
nuiton.org scm