Added localization system

This commit is contained in:
RaphiMC 2023-09-17 12:46:36 +02:00
parent 9f4fbe0031
commit 1c18ce4699
No known key found for this signature in database
GPG Key ID: 0F6BB0657A03AC94
15 changed files with 583 additions and 131 deletions

View File

@ -95,6 +95,16 @@ Documentation and examples:
- [ViaProxyMultiLaunch](https://github.com/Lenni0451/ViaProxyMultiLaunch)
- [ViaProxyGeyserPlugin](https://github.com/RaphiMC/ViaProxyGeyserPlugin)
## Contributing
Contributions in the form of pull requests are always welcome.
Please make sure to keep your code style consistent with the rest of the project and that your code is easily maintainable.
If you plan to make a large scale changes, please open an issue first or join my discord to discuss it.
### Translations
If you want to help translating ViaProxy you can do so by creating a pull request with your language file.
The language files are located in the [language folder](/src/main/resources/assets/language).
You can find the guidelines for creating a language file in the [en_US](/src/main/resources/assets/language/en_US.properties) language file.
## Contact
If you encounter any issues, please report them on the
[issue tracker](https://github.com/ViaVersion/ViaProxy/issues).

View File

@ -130,12 +130,19 @@ public class ViaProxy {
PluginManager.loadPlugins();
PluginManager.EVENT_MANAGER.register(EventListener.class);
Thread loaderThread = new Thread(new LoaderTask(), "ViaLoader");
Thread updateCheckThread = new Thread(new UpdateCheckTask(hasUI), "UpdateCheck");
final Thread loaderThread = new Thread(new LoaderTask(), "ViaLoader");
final Thread updateCheckThread = new Thread(new UpdateCheckTask(hasUI), "UpdateCheck");
if (hasUI) {
loaderThread.start();
SwingUtilities.invokeLater(() -> ui = new ViaProxyUI());
SwingUtilities.invokeLater(() -> {
try {
ui = new ViaProxyUI();
} catch (Throwable e) {
Logger.LOGGER.fatal("Failed to initialize UI", e);
System.exit(1);
}
});
if (System.getProperty("skipUpdateCheck") == null) {
updateCheckThread.start();
}

View File

@ -23,6 +23,7 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.vdurmont.semver4j.Semver;
import net.raphimc.viaproxy.ViaProxy;
import net.raphimc.viaproxy.ui.I18n;
import net.raphimc.viaproxy.ui.popups.DownloadPopup;
import net.raphimc.viaproxy.util.logging.Logger;
@ -94,15 +95,15 @@ public class UpdateCheckTask implements Runnable {
}
private void showUpdateWarning(final String latestVersion) {
JOptionPane.showMessageDialog(ViaProxy.ui, "You are running an outdated version of ViaProxy!\nCurrent version: " + VERSION + "\nLatest version: " + latestVersion, "ViaProxy", JOptionPane.WARNING_MESSAGE);
JOptionPane.showMessageDialog(ViaProxy.ui, I18n.get("popup.update.info", VERSION, latestVersion), "ViaProxy", JOptionPane.WARNING_MESSAGE);
}
private void showUpdateQuestion(final String name, final String downloadUrl, final String latestVersion) {
int chosen = JOptionPane.showConfirmDialog(ViaProxy.ui, "You are running an outdated version of ViaProxy!\nCurrent version: " + VERSION + "\nLatest version: " + latestVersion + "\n\nDo you want to update?", "ViaProxy", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
int chosen = JOptionPane.showConfirmDialog(ViaProxy.ui, I18n.get("popup.update.info", VERSION, latestVersion) + "\n\n" + I18n.get("popup.update.question"), "ViaProxy", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (chosen == JOptionPane.YES_OPTION) {
File f = new File(name);
new DownloadPopup(ViaProxy.ui, downloadUrl, f, () -> SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(ViaProxy.ui, "Downloaded the latest version of ViaProxy!\nPress OK to restart.", "ViaProxy", JOptionPane.INFORMATION_MESSAGE);
JOptionPane.showMessageDialog(ViaProxy.ui, I18n.get("popup.update.success"), "ViaProxy", JOptionPane.INFORMATION_MESSAGE);
try {
Runtime.getRuntime().exec(new String[]{System.getProperty("java.home") + "/bin/java", "-jar", f.getAbsolutePath()});
System.exit(0);

View File

@ -27,7 +27,7 @@ public abstract class AUITab {
public AUITab(final ViaProxyUI frame, final String name) {
this.frame = frame;
this.name = name;
this.name = I18n.get("tab." + name + ".name");
this.contentPane = new JPanel();
this.contentPane.setLayout(null);

View File

@ -0,0 +1,114 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* 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/>.
*/
package net.raphimc.viaproxy.ui;
import net.raphimc.viaproxy.ViaProxy;
import net.raphimc.viaproxy.util.FileSystemUtil;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.*;
public class I18n {
private static final String DEFAULT_LOCALE = "en_US";
private static final Map<String, Properties> LOCALES = new HashMap<>();
private static String currentLocale;
static {
if (ViaProxy.saveManager == null) {
throw new IllegalStateException("ViaProxy is not yet initialized");
}
try {
for (Map.Entry<Path, byte[]> entry : FileSystemUtil.getFilesInDirectory("assets/language").entrySet()) {
final Properties properties = new Properties();
properties.load(new InputStreamReader(new ByteArrayInputStream(entry.getValue()), StandardCharsets.UTF_8));
LOCALES.put(entry.getKey().getFileName().toString().replace(".properties", ""), properties);
}
} catch (Throwable e) {
throw new RuntimeException("Failed to load translations", e);
}
currentLocale = ViaProxy.saveManager.uiSave.get("locale");
if (currentLocale == null || !LOCALES.containsKey(currentLocale)) {
final String systemLocale = Locale.getDefault().getLanguage() + '_' + Locale.getDefault().getCountry();
if (LOCALES.containsKey(systemLocale)) {
currentLocale = systemLocale;
} else {
for (Map.Entry<String, Properties> entry : LOCALES.entrySet()) {
if (entry.getKey().startsWith(Locale.getDefault().getLanguage() + '_')) {
currentLocale = entry.getKey();
break;
}
}
}
}
final int totalTranslation = LOCALES.get(DEFAULT_LOCALE).size();
for (Properties properties : LOCALES.values()) {
final int translated = properties.size();
final float percentage = (float) translated / totalTranslation * 100;
properties.put("language.completion", (int) Math.floor(percentage) + "%");
}
}
public static String get(final String key) {
return getSpecific(currentLocale, key);
}
public static String get(final String key, String... args) {
return String.format(getSpecific(currentLocale, key), (Object[]) args);
}
public static String getSpecific(final String locale, final String key) {
Properties properties = LOCALES.get(locale);
if (properties == null) {
properties = LOCALES.get(DEFAULT_LOCALE);
}
String value = properties.getProperty(key);
if (value == null) {
value = LOCALES.get(DEFAULT_LOCALE).getProperty(key);
}
if (value == null) {
return "Missing translation for key: " + key;
}
return value;
}
public static String getCurrentLocale() {
return currentLocale;
}
public static void setLocale(final String locale) {
if (ViaProxy.saveManager == null) {
throw new IllegalStateException("ViaProxy is not yet initialized");
}
currentLocale = locale;
ViaProxy.saveManager.uiSave.put("locale", locale);
ViaProxy.saveManager.save();
}
public static Collection<String> getAvailableLocales() {
return LOCALES.keySet();
}
}

View File

@ -29,6 +29,7 @@ import net.raphimc.viaproxy.ui.events.UIInitEvent;
import net.raphimc.viaproxy.ui.impl.AccountsTab;
import net.raphimc.viaproxy.ui.impl.AdvancedTab;
import net.raphimc.viaproxy.ui.impl.GeneralTab;
import net.raphimc.viaproxy.ui.impl.UISettingsTab;
import net.raphimc.viaproxy.util.logging.Logger;
import javax.swing.*;
@ -52,11 +53,13 @@ public class ViaProxyUI extends JFrame {
public final GeneralTab generalTab = new GeneralTab(this);
public final AdvancedTab advancedTab = new AdvancedTab(this);
public final AccountsTab accountsTab = new AccountsTab(this);
public final UISettingsTab uiSettingsTab = new UISettingsTab(this);
private ImageIcon icon;
public ViaProxyUI() {
Thread.setDefaultUncaughtExceptionHandler((t, e) -> this.showException(e));
EVENT_MANAGER.register(this);
this.setLookAndFeel();
this.loadIcons();
@ -67,8 +70,6 @@ public class ViaProxyUI extends JFrame {
ToolTipManager.sharedInstance().setDismissDelay(10_000);
SwingUtilities.updateComponentTreeUI(this);
this.setVisible(true);
EVENT_MANAGER.register(this);
}
private void setLookAndFeel() {
@ -128,7 +129,7 @@ public class ViaProxyUI extends JFrame {
try {
Desktop.getDesktop().browse(new URI(url));
} catch (Throwable t) {
this.showInfo("Couldn't open the link :(\nHere it is for you: " + url);
this.showInfo(I18n.get("generic.could_not_open_url", url));
}
}

View File

@ -27,6 +27,7 @@ import net.raphimc.viaproxy.saves.impl.accounts.Account;
import net.raphimc.viaproxy.saves.impl.accounts.BedrockAccount;
import net.raphimc.viaproxy.saves.impl.accounts.MicrosoftAccount;
import net.raphimc.viaproxy.ui.AUITab;
import net.raphimc.viaproxy.ui.I18n;
import net.raphimc.viaproxy.ui.ViaProxyUI;
import net.raphimc.viaproxy.ui.events.UIInitEvent;
import net.raphimc.viaproxy.ui.popups.AddAccountPopup;
@ -56,7 +57,7 @@ public class AccountsTab extends AUITab {
private Thread addThread;
public AccountsTab(final ViaProxyUI frame) {
super(frame, "Accounts");
super(frame, "accounts");
}
@Override
@ -66,14 +67,7 @@ public class AccountsTab extends AUITab {
int gridy = 0;
{
JLabel infoLabel = new JLabel("""
<html>
<p>To join online mode servers you have to add minecraft accounts for ViaProxy to use.</p>
<p>You can select the account by right clicking it. By default the first one will be used.</p>
<br>
<p>If you change your account frequently, you can install OpenAuthMod on your client.</p>
<p>This allows ViaProxy to use the account you are logged in with on the client.</p>
</html>""");
JLabel infoLabel = new JLabel("<html><p>" + I18n.get("tab.accounts.description.line1") + "</p><br><p>" + I18n.get("tab.accounts.description.line2") + "</p></html>");
GBC.create(body).grid(0, gridy++).weightx(1).insets(BORDER_PADDING, BORDER_PADDING, 0, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(infoLabel);
}
{
@ -121,7 +115,7 @@ public class AccountsTab extends AUITab {
scrollPane.setViewportView(this.accountsList);
JPopupMenu contextMenu = new JPopupMenu();
{
JMenuItem selectItem = new JMenuItem("Select account");
JMenuItem selectItem = new JMenuItem(I18n.get("tab.accounts.list.context_menu.select"));
selectItem.addActionListener(event -> {
int index = this.accountsList.getSelectedIndex();
if (index != -1) this.markSelected(index);
@ -129,7 +123,7 @@ public class AccountsTab extends AUITab {
contextMenu.add(selectItem);
}
{
JMenuItem removeItem = new JMenuItem("Remove");
JMenuItem removeItem = new JMenuItem(I18n.get("tab.accounts.list.context_menu.remove"));
removeItem.addActionListener(event -> {
int index = this.accountsList.getSelectedIndex();
if (index != -1) {
@ -147,7 +141,7 @@ public class AccountsTab extends AUITab {
contextMenu.add(removeItem);
}
{
JMenuItem moveUp = new JMenuItem("Move up ↑");
JMenuItem moveUp = new JMenuItem(I18n.get("tab.accounts.list.context_menu.move_up"));
moveUp.addActionListener(event -> {
int index = this.accountsList.getSelectedIndex();
if (index != -1) this.moveUp(index);
@ -155,7 +149,7 @@ public class AccountsTab extends AUITab {
contextMenu.add(moveUp);
}
{
JMenuItem moveDown = new JMenuItem("Move down ↓");
JMenuItem moveDown = new JMenuItem(I18n.get("tab.accounts.list.context_menu.move_down"));
moveDown.addActionListener(event -> {
int index = this.accountsList.getSelectedIndex();
if (index != -1) this.moveDown(index);
@ -170,9 +164,9 @@ public class AccountsTab extends AUITab {
addButtons.setLayout(new GridLayout(1, 3, BORDER_PADDING, 0));
contentPane.add(addButtons);
{
JButton addOfflineAccountButton = new JButton("Offline Account");
JButton addOfflineAccountButton = new JButton(I18n.get("tab.accounts.add_offline.label"));
addOfflineAccountButton.addActionListener(event -> {
String username = JOptionPane.showInputDialog(this.frame, "Enter your offline mode Username:", "Add Offline Account", JOptionPane.PLAIN_MESSAGE);
String username = JOptionPane.showInputDialog(this.frame, I18n.get("tab.accounts.add_offline.enter_username"), I18n.get("tab.accounts.add.title"), JOptionPane.PLAIN_MESSAGE);
if (username != null && !username.trim().isEmpty()) {
Account account = ViaProxy.saveManager.accountsSave.addAccount(username);
ViaProxy.saveManager.save();
@ -182,7 +176,7 @@ public class AccountsTab extends AUITab {
addButtons.add(addOfflineAccountButton);
}
{
this.addMicrosoftAccountButton = new JButton("Microsoft Account");
this.addMicrosoftAccountButton = new JButton(I18n.get("tab.accounts.add_microsoft.label"));
this.addMicrosoftAccountButton.addActionListener(event -> {
this.addMicrosoftAccountButton.setEnabled(false);
this.handleLogin(msaDeviceCodeConsumer -> {
@ -194,7 +188,7 @@ public class AccountsTab extends AUITab {
addButtons.add(this.addMicrosoftAccountButton);
}
{
this.addBedrockAccountButton = new JButton("Bedrock Account");
this.addBedrockAccountButton = new JButton(I18n.get("tab.accounts.add_bedrock.label"));
this.addBedrockAccountButton.addActionListener(event -> {
this.addBedrockAccountButton.setEnabled(false);
this.handleLogin(msaDeviceCodeConsumer -> {
@ -208,7 +202,7 @@ public class AccountsTab extends AUITab {
JPanel border = new JPanel();
border.setLayout(new GridBagLayout());
border.setBorder(BorderFactory.createTitledBorder("Add Account"));
border.setBorder(BorderFactory.createTitledBorder(I18n.get("tab.accounts.add.title")));
GBC.create(border).grid(0, 0).weightx(1).insets(2, 4, 4, 4).fill(GridBagConstraints.HORIZONTAL).add(addButtons);
GBC.create(body).grid(0, gridy++).weightx(1).insets(BODY_BLOCK_PADDING, BORDER_PADDING, BORDER_PADDING, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(border);
@ -280,26 +274,22 @@ public class AccountsTab extends AUITab {
private void handleLogin(final TFunction<Consumer<StepMsaDeviceCode.MsaDeviceCode>, Account> requestHandler) {
this.addThread = new Thread(() -> {
try {
final Account account = requestHandler.apply(msaDeviceCode -> {
SwingUtilities.invokeLater(() -> {
new AddAccountPopup(this.frame, msaDeviceCode, popup -> this.addAccountPopup = popup, () -> {
this.closePopup();
this.addThread.interrupt();
});
});
});
final Account account = requestHandler.apply(msaDeviceCode -> SwingUtilities.invokeLater(() -> new AddAccountPopup(this.frame, msaDeviceCode, popup -> this.addAccountPopup = popup, () -> {
this.closePopup();
this.addThread.interrupt();
})));
SwingUtilities.invokeLater(() -> {
this.closePopup();
ViaProxy.saveManager.accountsSave.addAccount(account);
ViaProxy.saveManager.save();
this.addAccount(account);
this.frame.showInfo("The account " + account.getName() + " was added successfully.");
this.frame.showInfo(I18n.get("tab.accounts.add.success", account.getName()));
});
} catch (InterruptedException ignored) {
} catch (TimeoutException e) {
SwingUtilities.invokeLater(() -> {
this.closePopup();
this.frame.showError("The login request timed out.\nPlease login within 60 seconds.");
this.frame.showError(I18n.get("tab.accounts.add.timeout", "60"));
});
} catch (Throwable t) {
SwingUtilities.invokeLater(() -> {

View File

@ -24,6 +24,7 @@ import net.lenni0451.lambdaevents.EventHandler;
import net.raphimc.viaproxy.ViaProxy;
import net.raphimc.viaproxy.saves.impl.UISave;
import net.raphimc.viaproxy.ui.AUITab;
import net.raphimc.viaproxy.ui.I18n;
import net.raphimc.viaproxy.ui.ViaProxyUI;
import net.raphimc.viaproxy.ui.events.UICloseEvent;
import net.raphimc.viaproxy.ui.events.UIInitEvent;
@ -54,7 +55,7 @@ public class AdvancedTab extends AUITab {
JButton uploadLogsButton;
public AdvancedTab(final ViaProxyUI frame) {
super(frame, "Advanced");
super(frame, "advanced");
}
@Override
@ -79,59 +80,47 @@ public class AdvancedTab extends AUITab {
int gridy = 0;
{
String toolTipText = "The port the proxy should bind to.";
JLabel bindPortLabel = new JLabel("Bind Port:");
bindPortLabel.setToolTipText(toolTipText);
JLabel bindPortLabel = new JLabel(I18n.get("tab.advanced.bind_port.label"));
bindPortLabel.setToolTipText(I18n.get("tab.advanced.bind_port.tooltip"));
GBC.create(body).grid(0, gridy++).insets(BORDER_PADDING, BORDER_PADDING, 0, 0).anchor(GridBagConstraints.NORTHWEST).add(bindPortLabel);
this.bindPort = new JSpinner(new SpinnerNumberModel(25568, 1, 65535, 1));
this.bindPort.setToolTipText(toolTipText);
this.bindPort.setToolTipText(I18n.get("tab.advanced.bind_port.tooltip"));
ViaProxy.saveManager.uiSave.loadSpinner("bind_port", this.bindPort);
GBC.create(body).grid(0, gridy++).weightx(1).insets(0, BORDER_PADDING, 0, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(this.bindPort);
}
{
String toolTipText = """
URL of a SOCKS(4/5)/HTTP(S) proxy which will be used for TCP connections.
Supported formats:
- type://address:port
- type://username:password@address:port""";
JLabel proxyLabel = new JLabel("Proxy URL:");
proxyLabel.setToolTipText(toolTipText);
JLabel proxyLabel = new JLabel(I18n.get("tab.advanced.proxy_url.label"));
proxyLabel.setToolTipText(I18n.get("tab.advanced.proxy_url.tooltip"));
GBC.create(body).grid(0, gridy++).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, 0).anchor(GridBagConstraints.NORTHWEST).add(proxyLabel);
this.proxy = new JTextField();
this.proxy.setToolTipText(toolTipText);
this.proxy.setToolTipText(I18n.get("tab.advanced.proxy_url.tooltip"));
ViaProxy.saveManager.uiSave.loadTextField("proxy", this.proxy);
GBC.create(body).grid(0, gridy++).insets(0, BORDER_PADDING, 0, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(this.proxy);
}
{
this.proxyOnlineMode = new JCheckBox("Proxy Online Mode");
this.proxyOnlineMode.setToolTipText("""
Enabling Proxy Online Mode requires your client to have a valid account.
Proxy Online Mode allows your client to see skins on online mode servers and use the signed chat features.""");
this.proxyOnlineMode = new JCheckBox(I18n.get("tab.advanced.proxy_online_mode.label"));
this.proxyOnlineMode.setToolTipText(I18n.get("tab.advanced.proxy_online_mode.tooltip"));
ViaProxy.saveManager.uiSave.loadCheckBox("proxy_online_mode", this.proxyOnlineMode);
GBC.create(body).grid(0, gridy++).weightx(1).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, 0).anchor(GridBagConstraints.NORTHWEST).add(this.proxyOnlineMode);
}
{
this.legacySkinLoading = new JCheckBox("Legacy Skin Loading");
this.legacySkinLoading.setToolTipText("Enabling Legacy Skin Loading allows you to see skins on <= 1.6.4 servers.");
this.legacySkinLoading = new JCheckBox(I18n.get("tab.advanced.legacy_skin_loading.label"));
this.legacySkinLoading.setToolTipText(I18n.get("tab.advanced.legacy_skin_loading.tooltip"));
ViaProxy.saveManager.uiSave.loadCheckBox("legacy_skin_loading", this.legacySkinLoading);
GBC.create(body).grid(0, gridy++).weightx(1).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, 0).fill(GridBagConstraints.HORIZONTAL).add(this.legacySkinLoading);
}
{
this.chatSigning = new JCheckBox("Chat signing");
this.chatSigning.setToolTipText("Enables sending signed chat messages on >= 1.19 servers.");
this.chatSigning = new JCheckBox(I18n.get("tab.advanced.chat_signing.label"));
this.chatSigning.setToolTipText(I18n.get("tab.advanced.chat_signing.tooltip"));
this.chatSigning.setSelected(true);
ViaProxy.saveManager.uiSave.loadCheckBox("chat_signing", this.chatSigning);
GBC.create(body).grid(0, gridy++).weightx(1).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, 0).anchor(GridBagConstraints.NORTHWEST).add(this.chatSigning);
}
{
this.ignorePacketTranslationErrors = new JCheckBox("Ignore packet translation errors");
this.ignorePacketTranslationErrors.setToolTipText("""
Enabling this will prevent getting disconnected from the server when a packet translation error occurs and instead only print the error in the console.
This may cause issues depending on the type of packet which failed to translate.""");
this.ignorePacketTranslationErrors = new JCheckBox(I18n.get("tab.advanced.ignore_packet_translation_errors.label"));
this.ignorePacketTranslationErrors.setToolTipText(I18n.get("tab.advanced.ignore_packet_translation_errors.tooltip"));
this.ignorePacketTranslationErrors.setSelected(false);
ViaProxy.saveManager.uiSave.loadCheckBox("ignore_packet_translation_errors", this.ignorePacketTranslationErrors);
GBC.create(body).grid(0, gridy++).weightx(1).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, 0).fill(GridBagConstraints.HORIZONTAL).add(this.ignorePacketTranslationErrors);
@ -145,7 +134,7 @@ public class AdvancedTab extends AUITab {
footer.setLayout(new GridLayout(1, 2, BORDER_PADDING, 0));
{
this.viaVersionDumpButton = new JButton("Create ViaVersion dump");
this.viaVersionDumpButton = new JButton(I18n.get("tab.advanced.create_viaversion_dump.label"));
this.viaVersionDumpButton.addActionListener(event -> {
this.viaVersionDumpButton.setEnabled(false);
DumpUtil.postDump(null).whenComplete((url, e) -> {
@ -156,7 +145,7 @@ public class AdvancedTab extends AUITab {
ViaProxy.ui.openURL(url);
final StringSelection stringSelection = new StringSelection(url);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, stringSelection);
SwingUtilities.invokeLater(() -> ViaProxy.ui.showInfo("Copied ViaVersion dump link to clipboard."));
SwingUtilities.invokeLater(() -> ViaProxy.ui.showInfo(I18n.get("tab.advanced.create_viaversion_dump.success")));
}
SwingUtilities.invokeLater(() -> this.viaVersionDumpButton.setEnabled(true));
});
@ -165,7 +154,7 @@ public class AdvancedTab extends AUITab {
footer.add(this.viaVersionDumpButton);
}
{
this.uploadLogsButton = new JButton("Upload latest.log");
this.uploadLogsButton = new JButton(I18n.get("tab.advanced.upload_latest_log.label"));
this.uploadLogsButton.addActionListener(event -> {
final org.apache.logging.log4j.core.Logger logger = (org.apache.logging.log4j.core.Logger) LogManager.getRootLogger();
final RollingRandomAccessFileAppender fileAppender = (RollingRandomAccessFileAppender) logger.getAppenders().get("LatestFile");
@ -180,15 +169,15 @@ public class AdvancedTab extends AUITab {
ViaProxy.ui.openURL(apiResponse.getUrl());
final StringSelection selection = new StringSelection(apiResponse.getUrl());
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection);
ViaProxy.ui.showInfo("<html>Uploaded log file to <a href=\"\">" + apiResponse.getUrl() + "</a> (copied to clipboard)</html>");
ViaProxy.ui.showInfo("<html>" + I18n.get("tab.advanced.upload_latest_log.success", "<a href=\"\">" + apiResponse.getUrl() + "</a>") + "</html>");
} else {
ViaProxy.ui.showError("The log file could not be uploaded: " + apiResponse.getError());
ViaProxy.ui.showError(I18n.get("tab.advanced.upload_latest_log.error_generic", apiResponse.getError()));
}
} catch (FileNotFoundException e) {
ViaProxy.ui.showError("The log file could not be found.");
ViaProxy.ui.showError(I18n.get("tab.advanced.upload_latest_log.error_not_found"));
} catch (Throwable e) {
Logger.LOGGER.error("Failed to upload log file", e);
ViaProxy.ui.showError("The log file could not be uploaded.");
ViaProxy.ui.showError(I18n.get("tab.advanced.upload_latest_log.error_generic", e.getMessage()));
} finally {
this.uploadLogsButton.setEnabled(true);
}

View File

@ -27,6 +27,7 @@ import net.raphimc.viaproxy.plugins.events.GetDefaultPortEvent;
import net.raphimc.viaproxy.saves.impl.UISave;
import net.raphimc.viaproxy.saves.impl.accounts.OfflineAccount;
import net.raphimc.viaproxy.ui.AUITab;
import net.raphimc.viaproxy.ui.I18n;
import net.raphimc.viaproxy.ui.ViaProxyUI;
import net.raphimc.viaproxy.ui.events.UICloseEvent;
import net.raphimc.viaproxy.ui.events.UIInitEvent;
@ -52,11 +53,11 @@ public class GeneralTab extends AUITab {
private JComboBox<VersionEnum> serverVersion;
private JComboBox<String> authMethod;
private JCheckBox betaCraftAuth;
private JLabel stateLabelLabel;
private JLabel stateLabel;
private JButton stateButton;
public GeneralTab(final ViaProxyUI frame) {
super(frame, "General");
super(frame, "general");
}
@Override
@ -106,37 +107,33 @@ public class GeneralTab extends AUITab {
int gridy = 0;
{
String toolTipText = """
Supported formats:
- address
- address:port
- ClassiCube Direct URL""";
JLabel serverAddressLabel = new JLabel("Server Address:");
serverAddressLabel.setToolTipText(toolTipText);
JLabel serverAddressLabel = new JLabel(I18n.get("tab.general.server_address.label"));
serverAddressLabel.setToolTipText(I18n.get("tab.general.server_address.tooltip"));
GBC.create(body).grid(0, gridy++).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, 0).anchor(GridBagConstraints.NORTHWEST).add(serverAddressLabel);
this.serverAddress = new JTextField();
this.serverAddress.setToolTipText(toolTipText);
this.serverAddress.setToolTipText(I18n.get("tab.general.server_address.tooltip"));
ViaProxy.saveManager.uiSave.loadTextField("server_address", this.serverAddress);
GBC.create(body).grid(0, gridy++).weightx(1).insets(0, BORDER_PADDING, 0, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(this.serverAddress);
}
{
JLabel serverVersionLabel = new JLabel("Server Version:");
JLabel serverVersionLabel = new JLabel(I18n.get("tab.general.server_version.label"));
GBC.create(body).grid(0, gridy++).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, 0).anchor(GridBagConstraints.NORTHWEST).add(serverVersionLabel);
this.serverVersion = new JComboBox<>(VersionEnum.SORTED_VERSIONS.toArray(new VersionEnum[0]));
this.serverVersion.setRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
if (value instanceof VersionEnum version) value = version.getName();
if (value instanceof VersionEnum version) {
value = version.getName();
}
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
});
this.serverVersion.addActionListener(event -> {
if (this.betaCraftAuth == null) return; // This is called when the JComboBox is created (before betaCraftAuth is set)
if (!(this.serverVersion.getSelectedItem() instanceof VersionEnum)) return;
if (((VersionEnum) this.serverVersion.getSelectedItem()).isOlderThanOrEqualTo(VersionEnum.c0_28toc0_30)) {
if (!(this.serverVersion.getSelectedItem() instanceof VersionEnum selectedVersion)) return;
if (selectedVersion.isOlderThanOrEqualTo(VersionEnum.c0_28toc0_30)) {
this.betaCraftAuth.setEnabled(true);
} else {
this.betaCraftAuth.setEnabled(false);
@ -147,16 +144,16 @@ public class GeneralTab extends AUITab {
GBC.create(body).grid(0, gridy++).weightx(1).insets(0, BORDER_PADDING, 0, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(this.serverVersion);
}
{
JLabel minecraftAccountLabel = new JLabel("Minecraft Account:");
JLabel minecraftAccountLabel = new JLabel(I18n.get("tab.general.minecraft_account.label"));
GBC.create(body).grid(0, gridy++).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, 0).anchor(GridBagConstraints.NORTHWEST).add(minecraftAccountLabel);
this.authMethod = new JComboBox(new String[]{"Use no account", "Use selected account", "Use OpenAuthMod"});
this.authMethod = new JComboBox<>(new String[]{I18n.get("tab.general.minecraft_account.option_no_account"), I18n.get("tab.general.minecraft_account.option_select_account"), I18n.get("tab.general.minecraft_account.option_openauthmod")});
ViaProxy.saveManager.uiSave.loadComboBox("auth_method", this.authMethod);
GBC.create(body).grid(0, gridy++).weightx(1).insets(0, BORDER_PADDING, 0, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(this.authMethod);
}
{
this.betaCraftAuth = new JCheckBox("BetaCraft Auth (Classic)");
this.betaCraftAuth.setToolTipText("Enabling BetaCraft Auth allows you to join Classic servers which have online mode enabled.");
this.betaCraftAuth = new JCheckBox(I18n.get("tab.general.betacraft_auth.label"));
this.betaCraftAuth.setToolTipText(I18n.get("tab.general.betacraft_auth.tooltip"));
ViaProxy.saveManager.uiSave.loadCheckBox("betacraft_auth", this.betaCraftAuth);
GBC.create(body).grid(0, gridy++).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, 0).anchor(GridBagConstraints.NORTHWEST).add(this.betaCraftAuth);
// Simulate user action on serverVersion to update betaCraftAuth
@ -173,14 +170,14 @@ public class GeneralTab extends AUITab {
JPanel footer = new JPanel();
footer.setLayout(new GridBagLayout());
this.stateLabelLabel = new JLabel("State: Not Connected");
this.stateLabelLabel.setVisible(false);
GBC.create(footer).grid(0, 0).weightx(1).insets(0, BORDER_PADDING, 0, BORDER_PADDING).anchor(GridBagConstraints.WEST).fill(GridBagConstraints.HORIZONTAL).add(this.stateLabelLabel);
this.stateLabel = new JLabel("");
this.stateLabel.setVisible(false);
GBC.create(footer).grid(0, 0).weightx(1).insets(0, BORDER_PADDING, 0, BORDER_PADDING).anchor(GridBagConstraints.WEST).fill(GridBagConstraints.HORIZONTAL).add(this.stateLabel);
this.stateButton = new JButton("Loading ViaProxy...");
this.stateButton = new JButton(I18n.get("tab.general.state.loading"));
this.stateButton.addActionListener(event -> {
if (this.stateButton.getText().equalsIgnoreCase("Start")) this.start();
else if (this.stateButton.getText().equalsIgnoreCase("Stop")) this.stop();
if (this.stateButton.getText().equalsIgnoreCase(I18n.get("tab.general.state.start"))) this.start();
else if (this.stateButton.getText().equalsIgnoreCase(I18n.get("tab.general.state.stop"))) this.stop();
});
this.stateButton.setEnabled(false);
GBC.create(footer).grid(0, 1).weightx(1).insets(0, BORDER_PADDING, BORDER_PADDING, BORDER_PADDING).anchor(GridBagConstraints.WEST).fill(GridBagConstraints.HORIZONTAL).add(this.stateButton);
@ -191,7 +188,7 @@ public class GeneralTab extends AUITab {
@EventHandler
private void setReady(final UIInitEvent event) {
SwingUtilities.invokeLater(() -> {
this.stateButton.setText("Start");
this.stateButton.setText(I18n.get("tab.general.state.start"));
this.stateButton.setEnabled(true);
});
}
@ -221,32 +218,32 @@ public class GeneralTab extends AUITab {
}
private void updateStateLabel() {
this.stateLabelLabel.setText("ViaProxy is running! Connect with Minecraft 1.7+ to 127.0.0.1:" + ViaProxy.ui.advancedTab.bindPort.getValue());
this.stateLabelLabel.setVisible(true);
this.stateLabel.setText(I18n.get("tab.general.state.running", ViaProxy.ui.advancedTab.bindPort.getValue().toString()));
this.stateLabel.setVisible(true);
}
private void start() {
Object selectedItem = this.serverVersion.getSelectedItem();
final Object selectedItem = this.serverVersion.getSelectedItem();
if (!(selectedItem instanceof VersionEnum)) {
this.frame.showError("Please select a server version!");
this.frame.showError(I18n.get("tab.general.error.no_server_version_selected"));
return;
}
if (ViaProxy.saveManager.uiSave.get("notice.ban_warning") == null) {
ViaProxy.saveManager.uiSave.put("notice.ban_warning", "true");
ViaProxy.saveManager.save();
this.frame.showWarning("<html><div style='text-align: center;'>ViaProxy may trigger anti-cheats, due to block, item, movement and other differences between versions.<br><b>USE AT YOUR OWN RISK!</b></div></html>");
this.frame.showWarning("<html><div style='text-align: center;'>" + I18n.get("tab.general.warning.ban_warning.line1") + "<br><b>" + I18n.get("tab.general.warning.risk") + "</b></div></html>");
}
if (VersionEnum.bedrockLatest.equals(selectedItem) && ViaProxy.saveManager.uiSave.get("notice.bedrock_warning") == null) {
ViaProxy.saveManager.uiSave.put("notice.bedrock_warning", "true");
ViaProxy.saveManager.save();
this.frame.showWarning("<html><div style='text-align: center;'>ViaBedrock is currently in very early development and not ready for general use.<br><b>CONTINUE AT YOUR OWN RISK!</b></div></html>");
this.frame.showWarning("<html><div style='text-align: center;'>" + I18n.get("tab.general.warning.bedrock_warning.line1") + "<br><b>" + I18n.get("tab.general.warning.risk") + "</b></div></html>");
}
this.setComponentsEnabled(false);
this.stateButton.setEnabled(false);
this.stateButton.setText("Starting...");
this.stateButton.setText(I18n.get("tab.general.state.starting"));
new Thread(() -> {
String serverAddress = this.serverAddress.getText().trim();
@ -268,7 +265,7 @@ public class GeneralTab extends AUITab {
final String[] path = uri.getPath().substring(1).split("/");
if (path.length < 2) {
throw new IllegalArgumentException("Invalid ClassiCube Direct URL!");
throw new IllegalArgumentException(I18n.get("tab.general.error.invalid_classicube_url"));
}
Options.MC_ACCOUNT = new OfflineAccount(path[0]);
@ -287,7 +284,7 @@ public class GeneralTab extends AUITab {
Options.CONNECT_ADDRESS = hostAndPort.getHost();
Options.CONNECT_PORT = hostAndPort.getPortOrDefault(PluginManager.EVENT_MANAGER.call(new GetDefaultPortEvent(serverVersion, 25565)).getDefaultPort());
} catch (Throwable t) {
throw new IllegalArgumentException("Invalid server address!");
throw new IllegalArgumentException(I18n.get("tab.general.error.invalid_server_address"));
}
Options.BIND_PORT = bindPort;
@ -303,39 +300,35 @@ public class GeneralTab extends AUITab {
try {
Options.PROXY_URL = new URI(proxyUrl);
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Invalid proxy URL!");
throw new IllegalArgumentException(I18n.get("tab.general.error.invalid_proxy_url"));
}
} else {
Options.PROXY_URL = null;
}
} catch (Throwable t) {
SwingUtilities.invokeLater(() -> {
this.frame.showError(t.getMessage());
});
SwingUtilities.invokeLater(() -> this.frame.showError(t.getMessage()));
throw t;
}
try {
ViaProxy.startProxy();
} catch (Throwable e) {
SwingUtilities.invokeLater(() -> {
this.frame.showError("Failed to start ViaProxy! Ensure that the local port is not already in use and try again.");
});
SwingUtilities.invokeLater(() -> this.frame.showError(I18n.get("tab.general.error.failed_to_start")));
throw e;
}
SwingUtilities.invokeLater(() -> {
this.updateStateLabel();
this.stateButton.setEnabled(true);
this.stateButton.setText("Stop");
this.stateButton.setText(I18n.get("tab.general.state.stop"));
});
} catch (Throwable e) {
Logger.LOGGER.error("Error while starting ViaProxy", e);
SwingUtilities.invokeLater(() -> {
this.setComponentsEnabled(true);
this.stateButton.setEnabled(true);
this.stateButton.setText("Start");
this.stateLabelLabel.setVisible(false);
this.stateButton.setText(I18n.get("tab.general.state.start"));
this.stateLabel.setVisible(false);
});
}
}).start();
@ -344,8 +337,8 @@ public class GeneralTab extends AUITab {
private void stop() {
ViaProxy.stopProxy();
this.stateLabelLabel.setVisible(false);
this.stateButton.setText("Start");
this.stateLabel.setVisible(false);
this.stateButton.setText(I18n.get("tab.general.state.start"));
this.setComponentsEnabled(true);
}

View File

@ -0,0 +1,84 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* 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/>.
*/
package net.raphimc.viaproxy.ui.impl;
import net.raphimc.viaproxy.ViaProxy;
import net.raphimc.viaproxy.ui.AUITab;
import net.raphimc.viaproxy.ui.I18n;
import net.raphimc.viaproxy.ui.ViaProxyUI;
import net.raphimc.viaproxy.util.GBC;
import net.raphimc.viaproxy.util.logging.Logger;
import org.jdesktop.swingx.VerticalLayout;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import static net.raphimc.viaproxy.ui.ViaProxyUI.BORDER_PADDING;
public class UISettingsTab extends AUITab {
public UISettingsTab(final ViaProxyUI frame) {
super(frame, "ui_settings");
}
@Override
protected void init(JPanel contentPane) {
JPanel body = new JPanel();
body.setLayout(new GridBagLayout());
int gridy = 0;
{
JLabel languageLabel = new JLabel(I18n.get("tab.ui_settings.language.label"));
GBC.create(body).grid(0, gridy++).insets(BORDER_PADDING, BORDER_PADDING, 0, BORDER_PADDING).anchor(GridBagConstraints.NORTHWEST).add(languageLabel);
JComboBox<String> language = new JComboBox<>(I18n.getAvailableLocales().toArray(new String[0]));
language.setRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
if (value instanceof String locale) {
value = "<html><b>" + I18n.getSpecific(locale, "language.name") + "</b> (" + I18n.get("tab.ui_settings.language.completion", I18n.getSpecific(locale, "language.completion")) + ") " + I18n.get("tab.ui_settings.language.author", I18n.getSpecific(locale, "language.author")) + "</html>";
}
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
});
language.setSelectedItem(I18n.getCurrentLocale());
language.addActionListener(event -> {
if (!(language.getSelectedItem() instanceof String locale)) return;
I18n.setLocale(locale);
ViaProxy.ui.showInfo(I18n.get("tab.ui_settings.language.success", I18n.get("language.name"), locale));
try {
final File f = new File(ViaProxy.class.getProtectionDomain().getCodeSource().getLocation().toURI());
Runtime.getRuntime().exec(new String[]{System.getProperty("java.home") + "/bin/java", "-jar", f.getAbsolutePath()});
System.exit(0);
} catch (URISyntaxException | IOException e) {
Logger.LOGGER.error("Could not start the ViaProxy jar", e);
ViaProxy.ui.showException(e);
System.exit(1);
}
});
GBC.create(body).grid(0, gridy++).weightx(1).insets(0, BORDER_PADDING, 0, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(language);
}
contentPane.setLayout(new VerticalLayout());
contentPane.add(body);
}
}

View File

@ -18,6 +18,7 @@
package net.raphimc.viaproxy.ui.popups;
import net.raphimc.mcauth.step.msa.StepMsaDeviceCode;
import net.raphimc.viaproxy.ui.I18n;
import net.raphimc.viaproxy.ui.ViaProxyUI;
import net.raphimc.viaproxy.util.GBC;
@ -58,7 +59,7 @@ public class AddAccountPopup extends JDialog {
if (!AddAccountPopup.this.externalClose) closeListener.run();
}
});
this.setTitle("Add Account");
this.setTitle(I18n.get("popup.login_account.title"));
this.setSize(400, 200);
this.setResizable(false);
this.setLocationRelativeTo(this.parent);
@ -68,8 +69,8 @@ public class AddAccountPopup extends JDialog {
JPanel contentPane = new JPanel();
contentPane.setLayout(new GridBagLayout());
{
JLabel browserLabel = new JLabel("Please open the following URL in your browser:");
GBC.create(contentPane).grid(0, 0).insets(BORDER_PADDING, BORDER_PADDING, 0, 0).anchor(GridBagConstraints.NORTHWEST).add(browserLabel);
JLabel browserLabel = new JLabel("<html><p>" + I18n.get("popup.login_account.instructions.browser") + "</p></html>");
GBC.create(contentPane).grid(0, 0).weightx(1).insets(BORDER_PADDING, BORDER_PADDING, 0, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(browserLabel);
JLabel urlLabel = new JLabel("<html><a href=\"\">" + this.deviceCode.verificationUri() + "</a></html>");
urlLabel.addMouseListener(new MouseAdapter() {
@ -78,19 +79,19 @@ public class AddAccountPopup extends JDialog {
AddAccountPopup.this.parent.openURL(AddAccountPopup.this.deviceCode.verificationUri());
}
});
GBC.create(contentPane).grid(0, 1).insets(0, BORDER_PADDING, 0, 0).anchor(GridBagConstraints.NORTHWEST).add(urlLabel);
GBC.create(contentPane).grid(0, 1).weightx(1).insets(0, BORDER_PADDING, 0, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(urlLabel);
JLabel enterCodeLabel = new JLabel("Enter the following code:");
GBC.create(contentPane).grid(0, 2).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, 0).anchor(GridBagConstraints.NORTHWEST).add(enterCodeLabel);
JLabel enterCodeLabel = new JLabel("<html><p>" + I18n.get("popup.login_account.instructions.code") + "</p></html>");
GBC.create(contentPane).grid(0, 2).weightx(1).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(enterCodeLabel);
JLabel codeLabel = new JLabel(this.deviceCode.userCode());
GBC.create(contentPane).grid(0, 3).insets(0, BORDER_PADDING, 0, 0).anchor(GridBagConstraints.NORTHWEST).add(codeLabel);
GBC.create(contentPane).grid(0, 3).weightx(1).insets(0, BORDER_PADDING, 0, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(codeLabel);
JLabel closeInfo = new JLabel("The popup will close automatically after you have been logged in.");
GBC.create(contentPane).grid(0, 4).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, 0).anchor(GridBagConstraints.NORTHWEST).add(closeInfo);
JLabel closeInfo = new JLabel("<html><p>" + I18n.get("popup.login_account.instructions.close") + "</p></html>");
GBC.create(contentPane).grid(0, 4).weightx(1).insets(BODY_BLOCK_PADDING, BORDER_PADDING, 0, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(closeInfo);
}
{
JButton copyCodeButton = new JButton("Copy Code");
JButton copyCodeButton = new JButton(I18n.get("popup.login_account.instructions.copy_code.label"));
copyCodeButton.addActionListener(event -> {
StringSelection selection = new StringSelection(this.deviceCode.userCode());
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection);

View File

@ -18,6 +18,7 @@
package net.raphimc.viaproxy.ui.popups;
import net.raphimc.viaproxy.ViaProxy;
import net.raphimc.viaproxy.ui.I18n;
import net.raphimc.viaproxy.ui.ViaProxyUI;
import net.raphimc.viaproxy.util.GBC;
@ -68,7 +69,7 @@ public class DownloadPopup extends JDialog {
DownloadPopup.this.close(false);
}
});
this.setTitle("Downloading...");
this.setTitle(I18n.get("popup.download.title"));
this.setSize(400, 110);
this.setResizable(false);
this.setLocationRelativeTo(this.parent);
@ -83,7 +84,7 @@ public class DownloadPopup extends JDialog {
GBC.create(contentPane).grid(0, 0).weightx(1).insets(BORDER_PADDING, BORDER_PADDING, 0, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(this.progressBar);
}
{
JButton cancelButton = new JButton("Cancel");
JButton cancelButton = new JButton(I18n.get("generic.cancel"));
cancelButton.addActionListener(event -> this.close(false));
GBC.create(contentPane).grid(0, 1).weightx(1).insets(BORDER_PADDING, BORDER_PADDING, BORDER_PADDING, BORDER_PADDING).fill(GridBagConstraints.HORIZONTAL).add(cancelButton);
}

View File

@ -0,0 +1,73 @@
/*
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
* Copyright (C) 2023 RK_01/RaphiMC and contributors
*
* 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/>.
*/
package net.raphimc.viaproxy.util;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.*;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class FileSystemUtil {
public static Map<Path, byte[]> getFilesInDirectory(final String assetPath) throws IOException, URISyntaxException {
final URI uri = FileSystemUtil.class.getClassLoader().getResource(assetPath).toURI();
if (uri.getScheme().equals("file")) {
return getFilesInPath(Paths.get(uri));
} else if (uri.getScheme().equals("jar")) {
try (FileSystem fileSystem = getOrCreateFileSystem(uri)) {
return getFilesInPath(fileSystem.getPath(assetPath));
}
} else {
throw new IllegalArgumentException("Unsupported URI scheme: " + uri.getScheme());
}
}
private static Map<Path, byte[]> getFilesInPath(final Path path) throws IOException {
try (Stream<Path> stream = Files.walk(path)) {
return stream
.filter(Files::isRegularFile)
.sorted(Comparator.comparing(Path::toString))
.collect(Collectors.toMap(f -> f, f -> {
try {
return Files.readAllBytes(f);
} catch (IOException e) {
throw new RuntimeException(e);
}
}, (u, v) -> {
throw new IllegalStateException("Duplicate key");
}, LinkedHashMap::new));
}
}
private static FileSystem getOrCreateFileSystem(final URI uri) throws IOException {
FileSystem fileSystem;
try {
fileSystem = FileSystems.getFileSystem(uri);
} catch (FileSystemNotFoundException e) {
fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap());
}
return fileSystem;
}
}

View File

@ -0,0 +1,94 @@
# ViaProxy language file
#
# Language contribution guidelines:
# - Please use the same file content structure as in the en_US language file.
# - Use the en_US language file as a reference/template for your language file.
# - Keep the translations understandable and precise.
# - Do not use or rely on machine translation (Google Translate, DeepL, etc.) exclusively.
# - Do not copy an english translation into your language file. The en_US translation will be used as a fallback automatically.
# - Include this header (untranslated) in your language file.
# The display name of the language
language.name=Deutsch
# The name of the author of the language file (Your name)
language.author=RK_01
generic.cancel=Abbrechen
generic.could_not_open_url=Der Link konnte nicht geöffnet werden: %s
tab.general.name=Standard
tab.general.server_address.label=Server Adresse:
tab.general.server_address.tooltip=Unterstützte Formate:\n- Adresse\n- Adress:Port\n- ClassiCube Direct URL
tab.general.server_version.label=Server Version:
tab.general.minecraft_account.label=Minecraft Account:
tab.general.minecraft_account.option_no_account=Keinen Account verwenden
tab.general.minecraft_account.option_select_account=Ausgewählten Account verwenden
tab.general.minecraft_account.option_openauthmod=OpenAuthMod verwenden
tab.general.betacraft_auth.label=BetaCraft Authentifizierung (Classic)
tab.general.betacraft_auth.tooltip=Wenn du die BetaCraft Authentifizierung aktivierst, kannst du auf Classic Server, die Online Mode aktiviert haben joinen.
tab.general.state.loading=Lade ViaProxy...
tab.general.state.start=Start
tab.general.state.starting=Starte...
tab.general.state.stop=Stop
tab.general.state.running=ViaProxy läuft! Verbinde dich mit Minecraft 1.7+ zu 127.0.0.1:%s
tab.general.warning.ban_warning.line1=ViaProxy könnte Anti-Cheats flaggen aufgrund der Block-, Item- und Bewegungsunterschieden zwischen Versionen.
tab.general.warning.bedrock_warning.line1=ViaBedrock ist aktuell noch sehr früh in der Entwicklung und ist nicht für normale Verwendung gedacht.
tab.general.warning.risk=Verwendung auf eigene Gefahr!
tab.general.error.no_server_version_selected=Bitte wähle eine Server Version aus!
tab.general.error.invalid_classicube_url=Ungültige ClassiCube Direct URL!
tab.general.error.invalid_server_address=Ungültige Server Adresse!
tab.general.error.invalid_proxy_url=Ungültige proxy URL!
tab.general.error.failed_to_start=ViaProxy konnte nicht starten! Sorg dafür, dass der lokale Port nicht bereits belegt ist und versuchs nochmal.
tab.advanced.name=Erweitert
tab.advanced.bind_port.label=Lokaler Port:
tab.advanced.bind_port.tooltip=Der lokale Port, auf dem ViaProxy Verbindungen entgegen nehmen soll.
tab.advanced.proxy_url.label=Proxy URL:
tab.advanced.proxy_url.tooltip=URL von einem SOCKS(4/5)/HTTP(S) Proxy der für TCP Verbindungen verwendet werden soll.\nUnterstützte Formate:\n- Typ://Adresse:Port\n- Typ://Benutzername:Passwort@Adresse:Port
tab.advanced.proxy_online_mode.label=Proxy Online Mode
tab.advanced.proxy_online_mode.tooltip=Wenn du Proxy Online Mode aktivierst, muss dein Client in ein gültiges Minecraft Konto eingeloggt sein.\nProxy Online Mode erlaubt es dir Skins auf Online Mode Servern zu sehen und signierten Chat zu verwenden.
tab.advanced.legacy_skin_loading.label=Alte Skins laden
tab.advanced.legacy_skin_loading.tooltip=Wenn du diese Option aktivierst, kannst du Skins auf <= 1.6.4 Servern sehen.
tab.advanced.chat_signing.label=Chat Signatur
tab.advanced.chat_signing.tooltip=Aktiviert das Senden von signierten Chat Nachrichten auf >= 1.19 Servern.
tab.advanced.ignore_packet_translation_errors.label=Datenpaket Übersetzungsfehler ignorieren
tab.advanced.ignore_packet_translation_errors.tooltip=Wenn du diese Option aktivierst, wirst du nicht mehr vom Server gekickt, wenn es einen Datenpaket Übersetzungsfehler gibt, sondern der Fehler wird nur in der Konsole angezeigt.\nDiese Option könnte abhängig vom Datenpaket, welches nicht übersetzt werden konnte, Folgeprobleme verursachen.
tab.advanced.create_viaversion_dump.label=ViaVersion Dump erstellen
tab.advanced.create_viaversion_dump.success=Der ViaVersion Dump Link wurde in die Zwischenablage kopiert.
tab.advanced.upload_latest_log.label=Neueste Log-Datei hochladen
tab.advanced.upload_latest_log.success=Log-Datei wurde hochgeladen: %s (In die Zwischenablage kopiert)
tab.advanced.upload_latest_log.error_generic=Die Log-Datei konnte nicht hochgeladen werden: %s
tab.advanced.upload_latest_log.error_not_found=Die Log-Datei konnte nicht gefunden werden.
tab.accounts.name=Konten
tab.accounts.description.line1=Um auf Online Mode Server zu joinen musst du ein Minecraft Konto im ViaProxy hinzufügen. Du kannst ein Konto auswählen indem du es rechtsklickst. Standardmäßig wird das Erste verwendet.
tab.accounts.description.line2=Wenn du dein Konto oft änderst, kannst du stattdessen OpenAuthMod auf deinem Client installieren. Das erlaubt ViaProxy das aktuell eingeloggte Konto von deinem Client zu verwenden.
tab.accounts.list.context_menu.select=Konto auswählen
tab.accounts.list.context_menu.remove=Löschen
tab.accounts.list.context_menu.move_up=Nach oben schieben ↑
tab.accounts.list.context_menu.move_down=Nach unten schieben ↓
tab.accounts.add.title=Konto hinzufügen
tab.accounts.add_offline.label=Offline Konto
tab.accounts.add_offline.enter_username=Gib deinen gewünschten Benutzername ein:
tab.accounts.add_microsoft.label=Microsoft Konto
tab.accounts.add_bedrock.label=Bedrock Konto
tab.accounts.add.success=Das Konto %s wurde erfolgreich hinzugefügt.
tab.accounts.add.timeout=Der Login Prozess ist abgelaufen.\nBitte logge dich innerhalb von %s Sekunden ein.
tab.ui_settings.name=Benutzeroberflächeneinstellungen
tab.ui_settings.language.label=Sprache:
tab.ui_settings.language.completion=%s übersetzt
tab.ui_settings.language.author=von %s
tab.ui_settings.language.success=Die Sprache wurde zu %s (%s) geändert. ViaProxy startet jetzt neu!
popup.login_account.title=Konto hinzufügen
popup.login_account.instructions.browser=Bitte öffne folgende URL in deinem Browser:
popup.login_account.instructions.code=Gib den folgenden Code ein:
popup.login_account.instructions.close=Das Popup schließt sich automatisch, nachdem du angemeldet wurdest.
popup.login_account.instructions.copy_code.label=Code kopieren
popup.download.title=Lade herunter...
popup.update.info=Du verwendest eine alte Version von ViaProxy!\nAktuelle Version: %s\nNeueste Version: %s
popup.update.question=Möchtest du aktualisieren?
popup.update.success=Die neueste Version wurde heruntergeladen. ViaProxy startet jetzt neu!

View File

@ -0,0 +1,94 @@
# ViaProxy language file
#
# Language contribution guidelines:
# - Please use the same file content structure as in the en_US language file.
# - Use the en_US language file as a reference/template for your language file.
# - Keep the translations understandable and precise.
# - Do not use or rely on machine translation (Google Translate, DeepL, etc.) exclusively.
# - Do not copy an english translation into your language file. The en_US translation will be used as a fallback automatically.
# - Include this header (untranslated) in your language file.
# The display name of the language
language.name=English (US)
# The name of the author of the language file (Your name)
language.author=RK_01
generic.cancel=Cancel
generic.could_not_open_url=Couldn't open the link: %s
tab.general.name=General
tab.general.server_address.label=Server Address:
tab.general.server_address.tooltip=Supported formats:\n- address\n- address:port\n- ClassiCube Direct URL
tab.general.server_version.label=Server Version:
tab.general.minecraft_account.label=Minecraft Account:
tab.general.minecraft_account.option_no_account=Use no account
tab.general.minecraft_account.option_select_account=Use selected account
tab.general.minecraft_account.option_openauthmod=Use OpenAuthMod
tab.general.betacraft_auth.label=BetaCraft Auth (Classic)
tab.general.betacraft_auth.tooltip=Enabling BetaCraft Auth allows you to join Classic servers which have online mode enabled.
tab.general.state.loading=Loading ViaProxy...
tab.general.state.start=Start
tab.general.state.starting=Starting...
tab.general.state.stop=Stop
tab.general.state.running=ViaProxy is running! Connect with Minecraft 1.7+ to 127.0.0.1:%s
tab.general.warning.ban_warning.line1=ViaProxy may trigger anti-cheats, due to block, item, movement and other differences between versions.
tab.general.warning.bedrock_warning.line1=ViaBedrock is currently in very early development and not ready for general use.
tab.general.warning.risk=Use at your own risk!
tab.general.error.no_server_version_selected=Please select a server version!
tab.general.error.invalid_classicube_url=Invalid ClassiCube Direct URL!
tab.general.error.invalid_server_address=Invalid server address!
tab.general.error.invalid_proxy_url=Invalid proxy URL!
tab.general.error.failed_to_start=Failed to start ViaProxy! Ensure that the local port is not already in use and try again.
tab.advanced.name=Advanced
tab.advanced.bind_port.label=Bind Port:
tab.advanced.bind_port.tooltip=The port ViaProxy should bind to.
tab.advanced.proxy_url.label=Proxy URL:
tab.advanced.proxy_url.tooltip=URL of a SOCKS(4/5)/HTTP(S) proxy which will be used for TCP connections.\nSupported formats:\n- type://address:port\n- type://username:password@address:port
tab.advanced.proxy_online_mode.label=Proxy Online Mode
tab.advanced.proxy_online_mode.tooltip=Enabling Proxy Online Mode requires your client to have a valid minecraft account.\nProxy Online Mode allows you to see skins on online mode servers and use the signed chat features.
tab.advanced.legacy_skin_loading.label=Legacy Skin Loading
tab.advanced.legacy_skin_loading.tooltip=Enabling Legacy Skin Loading allows you to see skins on <= 1.6.4 servers.
tab.advanced.chat_signing.label=Chat signing
tab.advanced.chat_signing.tooltip=Enables sending signed chat messages on >= 1.19 servers.
tab.advanced.ignore_packet_translation_errors.label=Ignore packet translation errors
tab.advanced.ignore_packet_translation_errors.tooltip=Enabling this will prevent getting disconnected from the server when a packet translation error occurs and instead only print the error in the console.\nThis may cause issues depending on the type of packet which failed to translate.
tab.advanced.create_viaversion_dump.label=Create ViaVersion dump
tab.advanced.create_viaversion_dump.success=Copied ViaVersion dump link to clipboard.
tab.advanced.upload_latest_log.label=Upload latest log file
tab.advanced.upload_latest_log.success=Uploaded log file to %s (copied to clipboard)
tab.advanced.upload_latest_log.error_generic=The log file could not be uploaded: %s
tab.advanced.upload_latest_log.error_not_found=The log file could not be found.
tab.accounts.name=Accounts
tab.accounts.description.line1=To join online mode servers you have to add a minecraft account for ViaProxy to use. You can select an account by right clicking it. By default the first one will be used.
tab.accounts.description.line2=If you change your account frequently, you can install OpenAuthMod on your client. This allows ViaProxy to use the account you are logged in with on the client.
tab.accounts.list.context_menu.select=Select Account
tab.accounts.list.context_menu.remove=Remove
tab.accounts.list.context_menu.move_up=Move up ↑
tab.accounts.list.context_menu.move_down=Move down ↓
tab.accounts.add.title=Add Account
tab.accounts.add_offline.label=Offline Account
tab.accounts.add_offline.enter_username=Enter your offline mode username:
tab.accounts.add_microsoft.label=Microsoft Account
tab.accounts.add_bedrock.label=Bedrock Account
tab.accounts.add.success=The account %s was added successfully.
tab.accounts.add.timeout=The login request timed out.\nPlease login within %s seconds.
tab.ui_settings.name=UI Settings
tab.ui_settings.language.label=Language:
tab.ui_settings.language.completion=%s translated
tab.ui_settings.language.author=by %s
tab.ui_settings.language.success=Language changed to %s (%s). ViaProxy will now restart!
popup.login_account.title=Add Account
popup.login_account.instructions.browser=Please open the following URL in your browser:
popup.login_account.instructions.code=Enter the following code:
popup.login_account.instructions.close=The popup will close automatically after you have been logged in.
popup.login_account.instructions.copy_code.label=Copy code
popup.download.title=Downloading...
popup.update.info=You are running an outdated version of ViaProxy!\nCurrent version: %s\nLatest version: %s
popup.update.question=Do you want to update?
popup.update.success=Downloaded the latest version of ViaProxy. ViaProxy will now restart!