diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index dca774ce..32ae04dc 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -23,13 +23,13 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v3 with: - java-version: '11' + java-version: '21' distribution: 'temurin' - name: Build with Gradle uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 with: - gradle-version: 7.5 + gradle-version: 8.7 arguments: build diff --git a/README.md b/README.md index 3b059804..da70d72f 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Usage Java 8 or later is recommended to run JPass. You can run the application from the command line by typing (the password file is optional): - java -jar jpass-1.0.6-SNAPSHOT.jar [password_file] + java -jar jpass-1.0.7-SNAPSHOT.jar [password_file] For convenience, batch/shell scripts are also available for launching JPass for various platforms (i.e. `jpass.bat` for Windows, `jpass.sh` for Linux, `jpass.command` for macOS). Please make sure `PATH`, or `JAVA_HOME` environment variables point to a valid Java installation. @@ -56,14 +56,14 @@ Configuration Default configurations can be overridden in `jpass.properties` file: | Configuration key | Value type | Default value | -| ---------------------------------- | ---------- | ---------------- | +| ---------------------------------- | ---------- |------------------| | ui.theme.dark.mode.enabled | boolean | `false` | | clear.clipboard.on.exit.enabled | boolean | `false` | | default.password.generation.length | integer | `14` | | date.format | string | `yyyy-MM-dd` | | entry.details | list | `TITLE,MODIFIED` | | file.chooser.directory | string | `./` | -| language.languageSetting | string | en-US | +| language.languageSetting | string | `en-US` | Regarding `language.languageSetting` please check [languages](https://github.com/gaborbata/jpass/tree/master/src/main/resources/resources/languages) @@ -71,5 +71,5 @@ resources folder for possible configuration values. Each configuration property can be overridden by system properties, with the `jpass.` key prefix, e.g. - java -Djpass.entry.details=TITLE -jar jpass-1.0.6-SNAPSHOT.jar + java -Djpass.entry.details=TITLE -jar jpass-1.0.7-SNAPSHOT.jar diff --git a/build.gradle b/build.gradle index 1a419c3d..aed42ebd 100644 --- a/build.gradle +++ b/build.gradle @@ -11,15 +11,15 @@ plugins { compileJava.options.encoding = 'UTF-8' -version = '1.0.6-SNAPSHOT' +version = '1.0.7-SNAPSHOT' repositories { mavenCentral() } dependencies { - implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: '2.16.1' - implementation group: 'com.formdev', name: 'flatlaf', version: '3.4' + implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: '2.16.2' + implementation group: 'com.formdev', name: 'flatlaf', version: '3.4.1' implementation group: 'com.formdev', name: 'svgSalamander', version: '1.1.4' } diff --git a/jpass.json b/jpass.json index af56f2f3..5a6e1310 100644 --- a/jpass.json +++ b/jpass.json @@ -1,5 +1,5 @@ { - "version": "1.0.2", + "version": "1.0.6", "description": "Password manager application with strong encryption (AES-256)", "homepage": "https://github.com/gaborbata/jpass", "license": { @@ -17,8 +17,8 @@ "java/openjdk11" ] }, - "url": "https://github.com/gaborbata/jpass/releases/download/v1.0.5/jpass-1.0.5-RELEASE.zip", - "hash": "0c6fc348b55c21e69c2c34d042316fa023773ef42fb8b8ec478e59ed0658be51", + "url": "https://github.com/gaborbata/jpass/releases/download/v1.0.6/jpass-1.0.6-RELEASE.zip", + "hash": "ba390f0cc63aa88c5b667c3fe6d2c69d15aad2afa5f196beca110a331309173b", "bin": "jpass.bat", "shortcuts": [ [ diff --git a/pom.xml b/pom.xml index 72debf49..d1d88cd4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ jpass jpass jar - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT JPass UTF-8 @@ -13,12 +13,12 @@ com.fasterxml.jackson.dataformat jackson-dataformat-xml - 2.16.1 + 2.16.2 com.formdev flatlaf - 3.4 + 3.4.1 com.formdev diff --git a/src/main/config/jpass.properties b/src/main/config/jpass.properties index 702c7dbd..5df42fb7 100644 --- a/src/main/config/jpass.properties +++ b/src/main/config/jpass.properties @@ -44,4 +44,4 @@ date.format=yyyy-MM-dd file.chooser.directory=./ # Locale ID to set the program language -language.languageSetting=en-US \ No newline at end of file +language.languageSetting=en-US diff --git a/src/main/distribution/install.sh b/src/main/distribution/install.sh index 56184f43..f1e439f3 100644 --- a/src/main/distribution/install.sh +++ b/src/main/distribution/install.sh @@ -2,21 +2,6 @@ # JPass installation script for Linux -# check if java executable exists -if [ -d "$JAVA_HOME" -a -x "$JAVA_HOME/bin/java" ]; then - JAVACMD="$JAVA_HOME/bin/java" -else - JAVACMD=java -fi - -$JAVACMD -version >/dev/null 2>&1 -if [ "$?" != "0" ]; then - echo "Install Java (JDK or JRE) if you do not already have. JPass will not work without it." - echo "Please make sure PATH, or JAVA_HOME environment variables point to a valid Java installation." - echo "Could not execute JPass (exit: $?)" - exit -fi - # detect the absolute path of jpass JPASS_HOME=`dirname "$0"` diff --git a/src/main/distribution/jpass.bat b/src/main/distribution/jpass.bat index 35ddf235..1ab5e448 100644 --- a/src/main/distribution/jpass.bat +++ b/src/main/distribution/jpass.bat @@ -27,7 +27,7 @@ pause goto end :launch -start "JPass" /B "%JAVA_EXE%" -jar "%JPASS_HOME%\jpass-1.0.6-SNAPSHOT.jar" %* +start "JPass" /B "%JAVA_EXE%" -jar "%JPASS_HOME%\jpass-1.0.7-SNAPSHOT.jar" %* goto end :end diff --git a/src/main/distribution/jpass.command b/src/main/distribution/jpass.command index 1931113d..cc2d44ca 100644 --- a/src/main/distribution/jpass.command +++ b/src/main/distribution/jpass.command @@ -33,4 +33,4 @@ else fi # execute jpass -exec "$JAVACMD" "$LAF_OPTS" -jar "$JPASS_HOME/jpass-1.0.6-SNAPSHOT.jar" "$@" +exec "$JAVACMD" "$LAF_OPTS" -jar "$JPASS_HOME/jpass-1.0.7-SNAPSHOT.jar" "$@" diff --git a/src/main/distribution/jpass.desktop b/src/main/distribution/jpass.desktop index 199c90f5..27489c6e 100644 --- a/src/main/distribution/jpass.desktop +++ b/src/main/distribution/jpass.desktop @@ -6,4 +6,4 @@ Comment=Password manager with strong encryption Exec=/opt/jpass/jpass.sh Icon=/opt/jpass/jpass.png Terminal=false - +StartupWMClass=jpass-JPass diff --git a/src/main/distribution/jpass.sh b/src/main/distribution/jpass.sh index f5058126..4a914869 100644 --- a/src/main/distribution/jpass.sh +++ b/src/main/distribution/jpass.sh @@ -33,4 +33,4 @@ else fi # execute jpass -exec "$JAVACMD" -jar "$JPASS_PATH/jpass-1.0.6-SNAPSHOT.jar" "$@" +exec "$JAVACMD" -jar "$JPASS_PATH/jpass-1.0.7-SNAPSHOT.jar" "$@" diff --git a/src/main/distribution/readme.txt b/src/main/distribution/readme.txt index f40bf139..6c217a94 100644 --- a/src/main/distribution/readme.txt +++ b/src/main/distribution/readme.txt @@ -1,4 +1,4 @@ -# JPass - Password Manager 1.0.6-SNAPSHOT +# JPass - Password Manager 1.0.7-SNAPSHOT Overview -------- @@ -21,7 +21,7 @@ Java 8 or later is recommended to run JPass. You can run the application from the command line by typing (the password file is optional): - java -jar jpass-1.0.6-SNAPSHOT.jar [password_file] + java -jar jpass-1.0.7-SNAPSHOT.jar [password_file] For convenience, batch/shell scripts are also available for launching JPass for various platforms (i.e. `jpass.bat` for Windows, `jpass.sh` for Linux, @@ -42,6 +42,11 @@ Default configurations can be overridden in `jpass.properties` file: | file.chooser.directory | string | ./ | | language.languageSetting | string | en-US | +Each configuration property can be overridden by system properties, +with the `jpass.` key prefix, e.g. + + java -Djpass.entry.details=TITLE -jar jpass-1.0.7-SNAPSHOT.jar + License ------- Copyright (c) 2009-2024 Gabor Bata diff --git a/src/main/java/jpass/ui/EntryDetailsTable.java b/src/main/java/jpass/ui/EntryDetailsTable.java index 388cc650..b01cb124 100644 --- a/src/main/java/jpass/ui/EntryDetailsTable.java +++ b/src/main/java/jpass/ui/EntryDetailsTable.java @@ -60,12 +60,12 @@ public class EntryDetailsTable extends JTable { private static final DateTimeFormatter FORMATTER = DateUtils.createFormatter(Configuration.getInstance().get("date.format", "yyyy-MM-dd")); - private enum DetailType { - TITLE(getLocalizedMessages().getString(VIEW_WINDOW_TITLE), Entry::getTitle), - URL(getLocalizedMessages().getString(VIEW_WINDOW_URL), Entry::getUrl), - USER(getLocalizedMessages().getString(VIEW_WINDOW_USER), Entry::getUser), - MODIFIED(getLocalizedMessages().getString(VIEW_WINDOW_MODIFIED), entry -> DateUtils.formatIsoDateTime(entry.getLastModification(), FORMATTER)), - CREATED(getLocalizedMessages().getString(VIEW_WINDOW_CREATED), entry -> DateUtils.formatIsoDateTime(entry.getCreationDate(), FORMATTER)); + public enum DetailType { + TITLE(VIEW_WINDOW_TITLE, Entry::getTitle), + URL(VIEW_WINDOW_URL, Entry::getUrl), + USER(VIEW_WINDOW_USER, Entry::getUser), + MODIFIED(VIEW_WINDOW_MODIFIED, entry -> DateUtils.formatIsoDateTime(entry.getLastModification(), FORMATTER)), + CREATED(VIEW_WINDOW_CREATED, entry -> DateUtils.formatIsoDateTime(entry.getCreationDate(), FORMATTER)); private final String description; private final Function valueMapper; @@ -111,7 +111,7 @@ public EntryDetailsTable() { } tableModel = new DefaultTableModel(); - detailsToDisplay.forEach(detail -> tableModel.addColumn(detail.getDescription())); + detailsToDisplay.forEach(detail -> tableModel.addColumn(getLocalizedMessages().getString(detail.getDescription()))); setModel(tableModel); getTableHeader().setReorderingAllowed(false); addMouseListener(new TableListener()); @@ -135,6 +135,10 @@ public Component prepareRenderer(TableCellRenderer renderer, int row, int column return component; } + public List getDetailsToDisplay() { + return detailsToDisplay; + } + public void clear() { tableModel.setRowCount(0); } @@ -144,8 +148,4 @@ public void addRow(Entry entry) { .map(detail -> detail.getValue(entry)) .toArray(Object[]::new)); } - - public int rowCount() { - return tableModel.getRowCount(); - } } diff --git a/src/main/java/jpass/ui/JPassFrame.java b/src/main/java/jpass/ui/JPassFrame.java index 300f1366..1e1d32ed 100644 --- a/src/main/java/jpass/ui/JPassFrame.java +++ b/src/main/java/jpass/ui/JPassFrame.java @@ -37,20 +37,26 @@ import jpass.xml.bind.Entry; import java.awt.BorderLayout; +import java.awt.Component; import java.awt.Dimension; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.Objects; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.swing.JButton; import javax.swing.JFrame; +import javax.swing.JMenuItem; import javax.swing.JTable; import javax.swing.JMenu; import javax.swing.JMenuBar; @@ -58,7 +64,9 @@ import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JToolBar; +import javax.swing.UIManager; import javax.swing.WindowConstants; +import javax.swing.table.TableColumn; import static jpass.ui.MessageDialog.NO_OPTION; import static jpass.ui.MessageDialog.YES_NO_CANCEL_OPTION; @@ -67,10 +75,21 @@ import static jpass.ui.MessageDialog.showQuestionMessage; import static jpass.util.Constants.BOTTOM_MENU_ENTRIES_COUNT; import static jpass.util.Constants.BOTTOM_MENU_ENTRIES_FOUND; +import static jpass.util.Constants.BUTTON_MESSAGE_CANCEL; import static jpass.util.Constants.EDIT_MENU; +import static jpass.util.Constants.FILE_CHOOSER_CANCEL_BUTTON_TEXT; import static jpass.util.Constants.FILE_MENU; import static jpass.util.Constants.HELP_MENU; +import static jpass.util.Constants.LANGUAGE_EN_US; +import static jpass.util.Constants.LANGUAGE_ES_MX; +import static jpass.util.Constants.LANGUAGE_HU_HU; +import static jpass.util.Constants.LANGUAGE_IT_IT; +import static jpass.util.Constants.LANGUAGE_LANGUAGE_CHANGED; +import static jpass.util.Constants.LANGUAGE_LANGUAGE_SETTING; +import static jpass.util.Constants.PANEL_FIND; import static jpass.util.Constants.PANEL_SAVE_MODIFIED_QUESTION_MESSAGE; +import static jpass.util.Constants.SETTINGS_MENU; +import static jpass.util.Constants.SETTINGS_MENU_LANGUAGE; import static jpass.util.Constants.TOOLS_MENU; /** @@ -81,13 +100,14 @@ */ public final class JPassFrame extends JFrame { - private static ResourceBundle localizedMessages; private static final Logger LOG = Logger.getLogger(JPassFrame.class.getName()); private static JPassFrame instance; + private static ResourceBundle localizedMessages; + private static final Map SUPPORTED_LANGUAGES = new HashMap<>(); public static final String PROGRAM_NAME = "JPass Password Manager"; - public static final String PROGRAM_VERSION = "1.0.6-SNAPSHOT"; + public static final String PROGRAM_VERSION = "1.0.7-SNAPSHOT"; private final JPopupMenu popup; private final JPanel topContainerPanel; @@ -96,6 +116,7 @@ public final class JPassFrame extends JFrame { private final JMenu fileMenu; private final JMenu editMenu; private final JMenu toolsMenu; + private final JMenu settingsMenu; private final JMenu helpMenu; private final JToolBar toolBar; private final JScrollPane scrollPane; @@ -103,9 +124,10 @@ public final class JPassFrame extends JFrame { private final EntryDetailsTable entryDetailsTable; private final DataModel model = DataModel.getInstance(); private final StatusPanel statusPanel; + private static String currentLanguage; private volatile boolean processing = false; - private JPassFrame(String fileName, Locale locale) { + private JPassFrame(String fileName) { try { setIconImages(Stream.of(16, 20, 32, 40, 64, 80, 128, 160) .map(size -> getIcon("jpass", size, size).getImage()) @@ -114,7 +136,9 @@ private JPassFrame(String fileName, Locale locale) { LOG.log(Level.CONFIG, "Could not set application icon.", e); } - localizedMessages = ResourceBundle.getBundle("resources.languages.languages", locale); + setSupportedLanguages(); + setLocalizedMessages(Locale.forLanguageTag(getCurrentLanguage())); + UIManager.put(FILE_CHOOSER_CANCEL_BUTTON_TEXT, localizedMessages.getString(BUTTON_MESSAGE_CANCEL)); this.toolBar = new JToolBar(); this.toolBar.setFloatable(false); @@ -182,6 +206,25 @@ private JPassFrame(String fileName, Locale locale) { this.toolsMenu.add(MenuActionType.CLEAR_CLIPBOARD.getAction()); this.jpassMenuBar.add(this.toolsMenu); + this.settingsMenu = new JMenu(localizedMessages.getString(SETTINGS_MENU)); + this.settingsMenu.setMnemonic(KeyEvent.VK_S); + + JMenu languageMenu = new JMenu(localizedMessages.getString(SETTINGS_MENU_LANGUAGE)); + languageMenu.setActionCommand(SETTINGS_MENU_LANGUAGE); + languageMenu.setIcon(getIcon("language")); + + SUPPORTED_LANGUAGES.forEach((key, value) -> { + JMenuItem language = new JMenuItem(localizedMessages.getString(key)); + if (Objects.equals(getCurrentLanguage(), value)) { + language.setIcon(getIcon("selection_checked")); + } + language.setActionCommand(key); + language.addActionListener(e -> refreshComponentsWithLanguageSelected(e.getActionCommand())); + languageMenu.add(language); + }); + settingsMenu.add(languageMenu); + this.jpassMenuBar.add(this.settingsMenu); + this.helpMenu = new JMenu(localizedMessages.getString(HELP_MENU)); this.helpMenu.setMnemonic(KeyEvent.VK_H); this.helpMenu.add(MenuActionType.LICENSE.getAction()); @@ -215,7 +258,7 @@ private JPassFrame(String fileName, Locale locale) { setJMenuBar(this.jpassMenuBar); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - setSize(450, 400); + setSize(490, 400); setMinimumSize(new Dimension(420, 200)); addWindowListener(new CloseListener()); setLocationRelativeTo(null); @@ -232,8 +275,10 @@ public static JPassFrame getInstance() { public static synchronized JPassFrame getInstance(String fileName) { if (instance == null) { - String languageTag = Configuration.getInstance().get("language.languageSetting", "en-US"); - instance = new JPassFrame(fileName, Locale.forLanguageTag(languageTag)); + String languageTag = Configuration.getInstance().get(LANGUAGE_LANGUAGE_SETTING, "en-US"); + Configuration.getInstance().set(LANGUAGE_LANGUAGE_SETTING, languageTag); + setCurrentLanguage(languageTag); + instance = new JPassFrame(fileName); } return instance; } @@ -313,6 +358,109 @@ public void refreshAll() { refreshEntryTitleList(null); } + /** + * Refresh UI components with new translated strings from language selected + * + * @param actionCommand key to differentiate a component + */ + private void refreshComponentsWithLanguageSelected(String actionCommand) { + String newLanguage = getSupportedLanguages().get(actionCommand); + if (Objects.equals(getCurrentLanguage(), newLanguage)) { + return; + } + setCurrentLanguage(newLanguage); + setLocalizedMessages(Locale.forLanguageTag(newLanguage)); + + UIManager.put(FILE_CHOOSER_CANCEL_BUTTON_TEXT, localizedMessages.getString(BUTTON_MESSAGE_CANCEL)); + + fileMenu.setText(localizedMessages.getString(FILE_MENU)); + editMenu.setText(localizedMessages.getString(EDIT_MENU)); + toolsMenu.setText(localizedMessages.getString(TOOLS_MENU)); + settingsMenu.setText(localizedMessages.getString(SETTINGS_MENU)); + helpMenu.setText(localizedMessages.getString(HELP_MENU)); + + updateMenuComponents(fileMenu); + updateMenuComponents(editMenu); + updateMenuComponents(toolsMenu); + updateMenuComponents(settingsMenu); + updateMenuComponents(helpMenu); + updateToolbarComponents(toolBar); + + updateJPopupMenu(popup); + getSearchPanel().setLabelText(String.format("%s: ", getLocalizedMessages().getString(PANEL_FIND))); + + updateTable(); + + Configuration.getInstance().set(LANGUAGE_LANGUAGE_SETTING, newLanguage); + MessageDialog.showInformationMessage(this, getLocalizedMessages().getString(LANGUAGE_LANGUAGE_CHANGED)); + } + + /** + * Updates JMenu components and its children with new translated strings + * + * @param menu to update + */ + private void updateMenuComponents(JMenu menu) { + for (int i = 0; i < menu.getItemCount(); i++) { + JMenuItem item = menu.getItem(i); + if (null != item) { + String actionCommand = item.getActionCommand(); + if (null != actionCommand) { + item.setText(localizedMessages.getString(actionCommand)); + + if (getSupportedLanguages().containsKey(actionCommand)) { + item.setIcon(null); + if (Objects.equals(getSupportedLanguages().get(actionCommand), getCurrentLanguage())) { + item.setIcon(getIcon("selection_checked")); + } + } + } + + if (item instanceof JMenu) { + updateMenuComponents((JMenu) item); + } + } + } + } + + /** + * Updates JPopupMenu components with new translated strings + * @param jPopupMenu + */ + private void updateJPopupMenu(JPopupMenu jPopupMenu) { + for (Component comp : jPopupMenu.getComponents()) { + if (comp instanceof JMenuItem) { + JMenuItem item = (JMenuItem) comp; + item.setText(localizedMessages.getString(item.getActionCommand())); + } + } + } + + /** + * Updates JToolBar components with new translated strings + * @param toolBar + */ + private void updateToolbarComponents(JToolBar toolBar) { + for (Component comp : toolBar.getComponents()) { + if (comp instanceof JButton) { + JButton jButton = (JButton) comp; + jButton.setToolTipText(localizedMessages.getString(jButton.getActionCommand())); + } + } + } + + /** + * Updates main JTable columns headers with new translated strings + */ + private void updateTable() { + for (int i = 0; i < getEntryTitleTable().getColumnModel().getColumnCount(); i++) { + TableColumn column = getEntryTitleTable().getColumnModel().getColumn(i); + column.setHeaderValue(getLocalizedMessages().getString(entryDetailsTable.getDetailsToDisplay().get(i).getDescription())); + } + getEntryTitleTable().getTableHeader().repaint(); + refreshEntryTitleList(null); + } + /** * Exits the application. */ @@ -354,6 +502,24 @@ public void setProcessing(boolean processing) { this.statusPanel.setProcessing(processing); } + /** + * Sets the resource bundle for localization + * + * @param locale locale for the resources bundle + */ + public static void setLocalizedMessages(Locale locale) { + JPassFrame.localizedMessages = ResourceBundle.getBundle("resources.languages.languages", locale); + } + + /** + * Sets the current language for the program + * + * @param newLanguage + */ + private static void setCurrentLanguage(String newLanguage) { + currentLanguage = newLanguage; + } + /** * Gets the processing state of this frame. * @@ -364,7 +530,7 @@ public boolean isProcessing() { } /** - * Get search panel. + * Gets search panel. * * @return the search panel */ @@ -374,9 +540,39 @@ public SearchPanel getSearchPanel() { /** * Gets the resource bundle for localization + * * @return resource bundle */ public static ResourceBundle getLocalizedMessages() { return localizedMessages; } + + /** + * Gets current language selected + * + * @return currentLanguage + */ + private static String getCurrentLanguage() { + return currentLanguage; + } + + /** + * Set supported languages currently + * + */ + private static void setSupportedLanguages() { + SUPPORTED_LANGUAGES.put(LANGUAGE_EN_US, "en-US"); + SUPPORTED_LANGUAGES.put(LANGUAGE_ES_MX, "es-MX"); + SUPPORTED_LANGUAGES.put(LANGUAGE_HU_HU, "hu-HU"); + SUPPORTED_LANGUAGES.put(LANGUAGE_IT_IT, "it-IT"); + } + + /** + * Gets supported languages + * + * @return Map of supported languages + */ + private static Map getSupportedLanguages() { + return SUPPORTED_LANGUAGES; + } } diff --git a/src/main/java/jpass/ui/SearchPanel.java b/src/main/java/jpass/ui/SearchPanel.java index 711c434c..8ca8aef1 100644 --- a/src/main/java/jpass/ui/SearchPanel.java +++ b/src/main/java/jpass/ui/SearchPanel.java @@ -144,6 +144,14 @@ public void actionPerformed(ActionEvent e) { } } + /** + * Sets text for label + * @param text of the label + */ + public void setLabelText(String text) { + this.label.setText(text); + } + /** * Get search criteria. * diff --git a/src/main/java/jpass/ui/action/AbstractMenuAction.java b/src/main/java/jpass/ui/action/AbstractMenuAction.java index 8e61d602..56ea1ad4 100644 --- a/src/main/java/jpass/ui/action/AbstractMenuAction.java +++ b/src/main/java/jpass/ui/action/AbstractMenuAction.java @@ -43,12 +43,14 @@ public abstract class AbstractMenuAction extends AbstractAction { /** * Creates a new menu action. * - * @param text title of the action that appears on UI - * @param icon icon of action - * @param accelerator accelerator key + * @param text title of the action that appears on UI + * @param actionCommandKey + * @param icon icon of action + * @param accelerator accelerator key */ - public AbstractMenuAction(String text, Icon icon, KeyStroke accelerator) { + public AbstractMenuAction(String text, String actionCommandKey, Icon icon, KeyStroke accelerator) { super(text, icon); + putValue(ACTION_COMMAND_KEY, actionCommandKey); putValue(SHORT_DESCRIPTION, text); if (accelerator != null) { putValue(ACCELERATOR_KEY, accelerator); diff --git a/src/main/java/jpass/ui/action/MenuActionType.java b/src/main/java/jpass/ui/action/MenuActionType.java index 58714f13..250908a1 100644 --- a/src/main/java/jpass/ui/action/MenuActionType.java +++ b/src/main/java/jpass/ui/action/MenuActionType.java @@ -41,7 +41,6 @@ import jpass.ui.JPassFrame; import jpass.ui.MessageDialog; import jpass.ui.helper.EntryHelper; -import jpass.util.Constants; import jpass.xml.bind.Entry; import static javax.swing.KeyStroke.getKeyStroke; @@ -56,8 +55,6 @@ import static java.awt.event.InputEvent.CTRL_DOWN_MASK; import static java.awt.event.InputEvent.ALT_DOWN_MASK; -import static jpass.util.Constants.PASSWORD_PASSWORD_NOT_MODIFIED; -import static jpass.util.Constants.PASSWORD_SUCCESSFULLY_MODIFIED; import static jpass.util.Constants.EDIT_MENU_ADD_ENTRY; import static jpass.util.Constants.EDIT_MENU_CLEAR_CLIPBOARD; import static jpass.util.Constants.EDIT_MENU_COPY_PASSWORD; @@ -71,11 +68,14 @@ import static jpass.util.Constants.FILE_MENU_EXIT; import static jpass.util.Constants.FILE_MENU_EXPORT_TO_XML; import static jpass.util.Constants.FILE_MENU_IMPORT_FROM_XML; +import static jpass.util.Constants.FILE_MENU_OPEN_FILE; import static jpass.util.Constants.FILE_MENU_NEW; import static jpass.util.Constants.FILE_MENU_SAVE; import static jpass.util.Constants.FILE_MENU_SAVE_AS; import static jpass.util.Constants.HELP_MENU_ABOUT_JPASS; import static jpass.util.Constants.HELP_MENU_LICENSE; +import static jpass.util.Constants.PASSWORD_PASSWORD_NOT_MODIFIED; +import static jpass.util.Constants.PASSWORD_SUCCESSFULLY_MODIFIED; import static jpass.util.Constants.TOOLS_MENU_GENERATE_PASSWORD; /** @@ -85,43 +85,43 @@ * */ public enum MenuActionType { - NEW_FILE(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_NEW), getIcon("new"), getKeyStroke(KeyEvent.VK_N, CTRL_DOWN_MASK)) { + NEW_FILE(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_NEW), FILE_MENU_NEW, getIcon("new"), getKeyStroke(KeyEvent.VK_N, CTRL_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { createNew(JPassFrame.getInstance()); } }), - OPEN_FILE(new AbstractMenuAction(getLocalizedMessages().getString(Constants.FILE_MENU_OPEN_FILE), getIcon("open"), getKeyStroke(KeyEvent.VK_O, CTRL_DOWN_MASK)) { + OPEN_FILE(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_OPEN_FILE), FILE_MENU_OPEN_FILE, getIcon("open"), getKeyStroke(KeyEvent.VK_O, CTRL_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { openFile(JPassFrame.getInstance()); } }), - SAVE_FILE(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_SAVE), getIcon("save"), getKeyStroke(KeyEvent.VK_S, CTRL_DOWN_MASK)) { + SAVE_FILE(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_SAVE), FILE_MENU_SAVE, getIcon("save"), getKeyStroke(KeyEvent.VK_S, CTRL_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { saveFile(JPassFrame.getInstance(), false); } }), - SAVE_AS_FILE(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_SAVE_AS), getIcon("save_as"), null) { + SAVE_AS_FILE(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_SAVE_AS), FILE_MENU_SAVE_AS, getIcon("save_as"), null) { @Override public void actionPerformed(ActionEvent ev) { saveFile(JPassFrame.getInstance(), true); } }), - EXPORT_XML(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_EXPORT_TO_XML), getIcon("export"), null) { + EXPORT_XML(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_EXPORT_TO_XML), FILE_MENU_EXPORT_TO_XML, getIcon("export"), null) { @Override public void actionPerformed(ActionEvent ev) { exportFile(JPassFrame.getInstance()); } }), - IMPORT_XML(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_IMPORT_FROM_XML), getIcon("import"), null) { + IMPORT_XML(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_IMPORT_FROM_XML), FILE_MENU_IMPORT_FROM_XML, getIcon("import"), null) { @Override public void actionPerformed(ActionEvent ev) { importFile(JPassFrame.getInstance()); } }), - CHANGE_PASSWORD(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_CHANGE_PASSWORD), getIcon("lock"), null) { + CHANGE_PASSWORD(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_CHANGE_PASSWORD), FILE_MENU_CHANGE_PASSWORD, getIcon("lock"), null) { @Override public void actionPerformed(ActionEvent ev) { JPassFrame parent = JPassFrame.getInstance(); @@ -137,19 +137,19 @@ public void actionPerformed(ActionEvent ev) { } } }), - GENERATE_PASSWORD(new AbstractMenuAction(getLocalizedMessages().getString(TOOLS_MENU_GENERATE_PASSWORD), getIcon("generate"), getKeyStroke(KeyEvent.VK_Z, CTRL_DOWN_MASK)) { + GENERATE_PASSWORD(new AbstractMenuAction(getLocalizedMessages().getString(TOOLS_MENU_GENERATE_PASSWORD), TOOLS_MENU_GENERATE_PASSWORD, getIcon("generate"), getKeyStroke(KeyEvent.VK_Z, CTRL_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { new GeneratePasswordDialog(JPassFrame.getInstance()); } }), - EXIT(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_EXIT), getIcon("exit"), getKeyStroke(KeyEvent.VK_F4, ALT_DOWN_MASK)) { + EXIT(new AbstractMenuAction(getLocalizedMessages().getString(FILE_MENU_EXIT), FILE_MENU_EXIT, getIcon("exit"), getKeyStroke(KeyEvent.VK_F4, ALT_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { JPassFrame.getInstance().exitFrame(); } }), - ABOUT(new AbstractMenuAction(getLocalizedMessages().getString(HELP_MENU_ABOUT_JPASS), getIcon("info"), getKeyStroke(KeyEvent.VK_F1, 0)) { + ABOUT(new AbstractMenuAction(getLocalizedMessages().getString(HELP_MENU_ABOUT_JPASS), HELP_MENU_ABOUT_JPASS, getIcon("info"), getKeyStroke(KeyEvent.VK_F1, 0)) { @Override public void actionPerformed(ActionEvent ev) { StringBuilder sb = new StringBuilder(); @@ -162,37 +162,37 @@ public void actionPerformed(ActionEvent ev) { MessageDialog.showInformationMessage(JPassFrame.getInstance(), sb.toString()); } }), - LICENSE(new AbstractMenuAction(getLocalizedMessages().getString(HELP_MENU_LICENSE), getIcon("license"), null) { + LICENSE(new AbstractMenuAction(getLocalizedMessages().getString(HELP_MENU_LICENSE), HELP_MENU_LICENSE, getIcon("license"), null) { @Override public void actionPerformed(ActionEvent ev) { MessageDialog.showTextFile(JPassFrame.getInstance(), getLocalizedMessages().getString(HELP_MENU_LICENSE), "license.txt"); } }), - ADD_ENTRY(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_ADD_ENTRY), getIcon("entry_new"), getKeyStroke(KeyEvent.VK_Y, CTRL_DOWN_MASK)) { + ADD_ENTRY(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_ADD_ENTRY), EDIT_MENU_ADD_ENTRY, getIcon("entry_new"), getKeyStroke(KeyEvent.VK_Y, CTRL_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { EntryHelper.addEntry(JPassFrame.getInstance()); } }), - EDIT_ENTRY(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_EDIT_ENTRY), getIcon("entry_edit"), getKeyStroke(KeyEvent.VK_E, CTRL_DOWN_MASK)) { + EDIT_ENTRY(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_EDIT_ENTRY), EDIT_MENU_EDIT_ENTRY, getIcon("entry_edit"), getKeyStroke(KeyEvent.VK_E, CTRL_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { EntryHelper.editEntry(JPassFrame.getInstance()); } }), - DUPLICATE_ENTRY(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_DUPLICATE_ENTRY), getIcon("entry_duplicate"), getKeyStroke(KeyEvent.VK_K, CTRL_DOWN_MASK)) { + DUPLICATE_ENTRY(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_DUPLICATE_ENTRY), EDIT_MENU_DUPLICATE_ENTRY, getIcon("entry_duplicate"), getKeyStroke(KeyEvent.VK_K, CTRL_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { EntryHelper.duplicateEntry(JPassFrame.getInstance()); } }), - DELETE_ENTRY(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_DELETE_ENTRY), getIcon("entry_delete"), getKeyStroke(KeyEvent.VK_D, CTRL_DOWN_MASK)) { + DELETE_ENTRY(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_DELETE_ENTRY), EDIT_MENU_DELETE_ENTRY, getIcon("entry_delete"), getKeyStroke(KeyEvent.VK_D, CTRL_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { EntryHelper.deleteEntry(JPassFrame.getInstance()); } }), - COPY_URL(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_COPY_URL), getIcon("url"), getKeyStroke(KeyEvent.VK_U, CTRL_DOWN_MASK)) { + COPY_URL(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_COPY_URL), EDIT_MENU_COPY_URL, getIcon("url"), getKeyStroke(KeyEvent.VK_U, CTRL_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { JPassFrame parent = JPassFrame.getInstance(); @@ -202,7 +202,7 @@ public void actionPerformed(ActionEvent ev) { } } }), - COPY_USER(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_COPY_USERNAME), getIcon("user"), getKeyStroke(KeyEvent.VK_B, CTRL_DOWN_MASK)) { + COPY_USER(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_COPY_USERNAME), EDIT_MENU_COPY_USERNAME, getIcon("user"), getKeyStroke(KeyEvent.VK_B, CTRL_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { JPassFrame parent = JPassFrame.getInstance(); @@ -212,7 +212,7 @@ public void actionPerformed(ActionEvent ev) { } } }), - COPY_PASSWORD(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_COPY_PASSWORD), getIcon("keyring"), getKeyStroke(KeyEvent.VK_C, CTRL_DOWN_MASK)) { + COPY_PASSWORD(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_COPY_PASSWORD), EDIT_MENU_COPY_PASSWORD, getIcon("keyring"), getKeyStroke(KeyEvent.VK_C, CTRL_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { JPassFrame parent = JPassFrame.getInstance(); @@ -222,13 +222,13 @@ public void actionPerformed(ActionEvent ev) { } } }), - CLEAR_CLIPBOARD(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_CLEAR_CLIPBOARD), getIcon("clear"), getKeyStroke(KeyEvent.VK_X, CTRL_DOWN_MASK)) { + CLEAR_CLIPBOARD(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_CLEAR_CLIPBOARD), EDIT_MENU_CLEAR_CLIPBOARD, getIcon("clear"), getKeyStroke(KeyEvent.VK_X, CTRL_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { EntryHelper.copyEntryField(JPassFrame.getInstance(), null); } }), - FIND_ENTRY(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_FIND_ENTRY), getIcon("find"), getKeyStroke(KeyEvent.VK_F, CTRL_DOWN_MASK)) { + FIND_ENTRY(new AbstractMenuAction(getLocalizedMessages().getString(EDIT_MENU_FIND_ENTRY), EDIT_MENU_FIND_ENTRY, getIcon("find"), getKeyStroke(KeyEvent.VK_F, CTRL_DOWN_MASK)) { @Override public void actionPerformed(ActionEvent ev) { JPassFrame.getInstance().getSearchPanel().setVisible(true); diff --git a/src/main/java/jpass/util/Configuration.java b/src/main/java/jpass/util/Configuration.java index 7f86f94f..d88bde64 100644 --- a/src/main/java/jpass/util/Configuration.java +++ b/src/main/java/jpass/util/Configuration.java @@ -30,11 +30,14 @@ import java.io.File; import java.io.FileInputStream; +import java.io.IOException; import java.io.InputStream; -import java.util.Optional; -import java.util.Properties; +import java.io.OutputStream; +import java.nio.file.Files; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.Optional; +import java.util.Properties; /** * Class for loading configurations from {@code jpass.properties} or system properties. @@ -50,7 +53,7 @@ public final class Configuration { private static final Logger LOG = Logger.getLogger(Configuration.class.getName()); private static Configuration instance; - private Properties properties = new Properties(); + private final Properties properties = new Properties(); private Configuration() { try { @@ -110,6 +113,20 @@ public String get(String key, String defaultValue) { return prop != null ? prop : defaultValue; } + public void set(String key, String value) { + properties.setProperty(key, value); + saveProperties(); + } + + private void saveProperties() { + File filePath = new File(getConfigurationFolderPath(), "jpass.properties"); + try (OutputStream os = Files.newOutputStream(filePath.toPath())) { + properties.store(os, "Configuration properties"); + } catch (IOException e) { + LOG.log(Level.WARNING, "Could not save configuration to file.", e); + } + } + public String[] getArray(String key, String[] defaultValue) { String prop = getProperty(key); if (prop != null) { diff --git a/src/main/java/jpass/util/Constants.java b/src/main/java/jpass/util/Constants.java index a150f6bb..10503d91 100644 --- a/src/main/java/jpass/util/Constants.java +++ b/src/main/java/jpass/util/Constants.java @@ -5,9 +5,12 @@ private Constants() { // not intended to be instantiated } + public static final String FILE_CHOOSER_CANCEL_BUTTON_TEXT = "FileChooser.cancelButtonText"; + public static final String FILE_MENU = "menuBar.fileMenu"; public static final String EDIT_MENU = "menuBar.editMenu"; public static final String TOOLS_MENU = "menuBar.toolsMenu"; + public static final String SETTINGS_MENU = "menuBar.settingsMenu"; public static final String HELP_MENU = "menuBar.helpMenu"; public static final String FILE_MENU_NEW = "fileMenu.new"; @@ -41,6 +44,8 @@ private Constants() { public static final String TOOLS_MENU_GENERATE_PASSWORD = "toolsMenu.generatePassword"; + public static final String SETTINGS_MENU_LANGUAGE = "settingsMenu.language"; + public static final String HELP_MENU_LICENSE = "helpMenu.license"; public static final String HELP_MENU_ABOUT_JPASS = "helpMenu.aboutJpass"; @@ -93,4 +98,11 @@ private Constants() { public static final String PANEL_OPEN = "panel.open"; public static final String PANEL_SAVE_MODIFIED_QUESTION_MESSAGE = "panel.saveModifiedQuestionMessage"; public static final String PANEL_UNENCRYPTED_DATA_WARNING_MESSAGE = "panel.unencryptedDataWarningMessage"; + + public static final String LANGUAGE_LANGUAGE_SETTING = "language.languageSetting"; + public static final String LANGUAGE_LANGUAGE_CHANGED = "language.languageChanged"; + public static final String LANGUAGE_EN_US = "language.en.us"; + public static final String LANGUAGE_ES_MX = "language.es.mx"; + public static final String LANGUAGE_HU_HU = "language.hu.hu"; + public static final String LANGUAGE_IT_IT = "language.it.it"; } diff --git a/src/main/resources/resources/images/language.svg b/src/main/resources/resources/images/language.svg new file mode 100644 index 00000000..a705061c --- /dev/null +++ b/src/main/resources/resources/images/language.svg @@ -0,0 +1,50 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/main/resources/resources/images/language_dark.svg b/src/main/resources/resources/images/language_dark.svg new file mode 100644 index 00000000..a705061c --- /dev/null +++ b/src/main/resources/resources/images/language_dark.svg @@ -0,0 +1,50 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/main/resources/resources/images/selection_checked.svg b/src/main/resources/resources/images/selection_checked.svg new file mode 100644 index 00000000..5ed423bb --- /dev/null +++ b/src/main/resources/resources/images/selection_checked.svg @@ -0,0 +1,5 @@ + + + + diff --git a/src/main/resources/resources/images/selection_checked_dark.svg b/src/main/resources/resources/images/selection_checked_dark.svg new file mode 100644 index 00000000..5ed423bb --- /dev/null +++ b/src/main/resources/resources/images/selection_checked_dark.svg @@ -0,0 +1,5 @@ + + + + diff --git a/src/main/resources/resources/languages/languages_en_US.properties b/src/main/resources/resources/languages/languages_en_US.properties index 9dd7bca7..5c588dac 100644 --- a/src/main/resources/resources/languages/languages_en_US.properties +++ b/src/main/resources/resources/languages/languages_en_US.properties @@ -2,6 +2,7 @@ menuBar.fileMenu=File menuBar.editMenu=Edit menuBar.toolsMenu=Tools +menuBar.settingsMenu=Settings menuBar.helpMenu=Help fileMenu.new=New @@ -35,6 +36,8 @@ editMenu.findEntry=Find Entry toolsMenu.generatePassword=Generate Password... +settingsMenu.language=Language + helpMenu.license=License helpMenu.aboutJpass=About JPass... @@ -87,3 +90,9 @@ panel.save=Save panel.open=Open panel.saveModifiedQuestionMessage=The current file has been modified.\nDo you want to save the changes before closing? panel.unencryptedDataWarningMessage=Please note that all data will be stored unencrypted.\nMake sure you keep the exported file in a secure location. + +language.languageChanged=Language has changed successfully. +language.en.us=English +language.es.mx=Spanish +language.hu.hu=Hungarian +language.it.it=Italian diff --git a/src/main/resources/resources/languages/languages_es_MX.properties b/src/main/resources/resources/languages/languages_es_MX.properties index c2efa1ad..c09546bc 100644 --- a/src/main/resources/resources/languages/languages_es_MX.properties +++ b/src/main/resources/resources/languages/languages_es_MX.properties @@ -2,6 +2,7 @@ menuBar.fileMenu=Archivo menuBar.editMenu=Editar menuBar.toolsMenu=Herramientas +menuBar.settingsMenu=Ajustes menuBar.helpMenu=Ayuda fileMenu.new=Nuevo @@ -14,6 +15,7 @@ fileMenu.changePassword=Cambiar Contrase fileMenu.exitMenu=Salir password.enterPasswordRequest=Por favor, introduce una contraseńa. +password.generatePasswordRequest=Por favor, genere una contraseńa. password.passwordNotModified=La contraseńa no ha sido modificada. password.successfullyModified=La contraseńa ha sido modificada exitosamente.\n\nGuarda el archivo ahora para asegurarse que la nueva contraseńa fue aplicada. password.passwordsNotIdentical=La contraseńa y contraseńa de confirmación no son identicas. @@ -34,6 +36,8 @@ editMenu.findEntry=Buscar Entrada toolsMenu.generatePassword=Generar Contraseńa... +settingsMenu.language=Idioma + helpMenu.license=Licencia helpMenu.aboutJpass=Acerca de JPass... @@ -67,7 +71,7 @@ buttonMessage.close=Cerrar entryDialog.showEntry=Mostrar entryDialog.generateEntry=Generar entryDialog.copyEntry=Copiar -entryDialog.fillTitleField=Please fill the title field. +entryDialog.fillTitleField=Por favor, complete el campo de título. entryDialog.titleAlreadyExists=El título ya existe,\nPor favor introduzca un título diferente. entryDialog.pleaseSelectEntry=Por favor, selecciona una entrada. entryDialog.wantDeleteEntry=żRealmente quieres eliminar esta entrada? @@ -86,3 +90,9 @@ panel.save=Guardar panel.open=Abrir panel.saveModifiedQuestionMessage=El archivo actual ha sido modificado.\nżDeseas guardar los cambios antes de cerrar el programa? panel.unencryptedDataWarningMessage=Note que toda la data se almancenará sin cifrar.\nAsegúrese de guardar el archivo exportado en un lugar seguro. + +language.languageChanged=El idioma ha cambiado correctamente. +language.en.us=Inglés +language.es.mx=Espańol +language.hu.hu=Húngaro +language.it.it=Italiano diff --git a/src/main/resources/resources/languages/languages_hu_HU.properties b/src/main/resources/resources/languages/languages_hu_HU.properties index ac609949..e89032cc 100644 --- a/src/main/resources/resources/languages/languages_hu_HU.properties +++ b/src/main/resources/resources/languages/languages_hu_HU.properties @@ -1,6 +1,7 @@ menuBar.fileMenu=Fájl menuBar.editMenu=SzerkesztĂ©s menuBar.toolsMenu=Eszközök +menuBar.settingsMenu=BeállĂ­tások menuBar.helpMenu=SĂşgĂł fileMenu.new=Ăšj @@ -34,6 +35,8 @@ editMenu.findEntry=BejegyzĂ©s keresĂ©se toolsMenu.generatePassword=JelszĂł generálás... +settingsMenu.language=Nyelv + helpMenu.license=Licenc helpMenu.aboutJpass=JPass nĂ©vjegy... @@ -87,3 +90,8 @@ panel.open=Megnyitás panel.saveModifiedQuestionMessage=A jelenlegi fájl mĂłdosĂ­tva lett.\nMenteni szeretnĂ© a változtatásokat bezárás elĹ‘tt? panel.unencryptedDataWarningMessage=FelhĂ­vjuk figyelmĂ©t, hogy az adatok titkosĂ­tás nĂ©lkĂĽl lesznek tárolva.\nBizonyosodjon meg rĂłla, hogy az exportált fájlt biztonságos helyre menti. +language.languageChanged=A nyelv sikeresen megváltozott. +language.en.us=Angol +language.es.mx=Spanyol +language.hu.hu=Magyar +language.it.it=Olasz diff --git a/src/main/resources/resources/languages/languages_it_IT.properties b/src/main/resources/resources/languages/languages_it_IT.properties index 5a3f1d79..e7d6408c 100644 --- a/src/main/resources/resources/languages/languages_it_IT.properties +++ b/src/main/resources/resources/languages/languages_it_IT.properties @@ -2,6 +2,7 @@ menuBar.fileMenu=File menuBar.editMenu=Modifica menuBar.toolsMenu=Strumenti +menuBar.settingsMenu=Impostazioni menuBar.helpMenu=Aiuto fileMenu.new=Nuovo @@ -35,6 +36,8 @@ editMenu.findEntry=Trova elemento toolsMenu.generatePassword=Genera password... +settingsMenu.language=Lingua + helpMenu.license=Licenza helpMenu.aboutJpass=Info su JPass... @@ -87,3 +90,9 @@ panel.save=Salva panel.open=Apri panel.saveModifiedQuestionMessage=Il file attuale è stato modificato.\nVuoi salvare le modifiche prima della chiusura? panel.unencryptedDataWarningMessage=Nota che tutti i dati verranno archiviati non crittografati.\nAssicurati di conservare il file esportato in un luogo sicuro. + +language.languageChanged=Impostazione lingua completata. +language.en.us=Inglese +language.es.mx=Spagnolo +language.hu.hu=Ungherese +language.it.it=Italiano diff --git a/src/test/java/jpass/util/ConfigurationTest.java b/src/test/java/jpass/util/ConfigurationTest.java index ded9b60b..f4de4e3c 100644 --- a/src/test/java/jpass/util/ConfigurationTest.java +++ b/src/test/java/jpass/util/ConfigurationTest.java @@ -44,38 +44,57 @@ public void setup() { } @Test - public void configurationIsDarkModeEnabledTest() { + void configurationIsDarkModeEnabledTest() { Boolean result = configuration.is("ui.theme.dark.mode.enabled", false); assertFalse(result); } @Test - public void configurationGetIntegerClearClipboardOnExitWrongConfigTest() { + void configurationGetIntegerClearClipboardOnExitWrongConfigTest() { int result = configuration.getInteger("clear.clipboard.on.exit.enabled", 0); assertEquals(0, result); } @Test - public void configurationIsDefaultPasswordGenerationNullConfigTest() { + void configurationIsDefaultPasswordGenerationNullConfigTest() { Boolean result = configuration.is("default.password.generation.size", false); assertFalse(result); } @Test - public void configurationGetDateFormatTest() { + void configurationGetDateFormatTest() { String result = configuration.get("date.format", "yyyy-MM-dd"); assertEquals("yyyy-MM-dd", result); } @Test - public void configurationGetArrayEntryDetailsTest() { + void configurationGetLanguageTestSupportedLanguages() { + configuration.set("language.languageSetting", "en-US"); + String result = configuration.get("language.languageSetting", null); + assertEquals("en-US", result); + + configuration.set("language.languageSetting", "es-MX"); + result = configuration.get("language.languageSetting", null); + assertEquals("es-MX", result); + + configuration.set("language.languageSetting", "hu-HU"); + result = configuration.get("language.languageSetting", null); + assertEquals("hu-HU", result); + + configuration.set("language.languageSetting", "it-IT"); + result = configuration.get("language.languageSetting", null); + assertEquals("it-IT", result); + } + + @Test + void configurationGetArrayEntryDetailsTest() { String[] defaultValue = new String[]{"TITLE", "MODIFIED"}; String[] result = configuration.getArray("entry.details", defaultValue); assertArrayEquals(defaultValue, result); } @Test - public void configurationGetArrayEntryDetailsWrongKeyTest() { + void configurationGetArrayEntryDetailsWrongKeyTest() { String[] defaultValue = new String[]{"TITLE", "MODIFIED"}; String[] result = configuration.getArray("entry.detail", defaultValue); assertArrayEquals(defaultValue, result);