更新 FeedbackPage (#1913)

* Update FeedbackPage

* Update logo

* close #1259
This commit is contained in:
Glavo 2023-01-07 21:32:52 +08:00 committed by GitHub
parent 593e70fa43
commit 1b5522958a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 103 additions and 662 deletions

View File

@ -98,36 +98,13 @@ public class AboutPage extends StackPane {
contributors.setSubtitle(i18n("about.thanks_to.contributors.statement")); contributors.setSubtitle(i18n("about.thanks_to.contributors.statement"));
contributors.setExternalLink("https://github.com/huanghongxun/HMCL/graphs/contributors"); contributors.setExternalLink("https://github.com/huanghongxun/HMCL/graphs/contributors");
thanks.getContent().setAll(yushijinhun, bangbang93, glavo, mcbbs, mcmod, gamerteam, redLnn, contributors);
}
ComponentList community = new ComponentList();
{
IconedTwoLineListItem users = new IconedTwoLineListItem(); IconedTwoLineListItem users = new IconedTwoLineListItem();
users.setImage(new Image("/assets/img/craft_table.png", 32, 32, false, true)); users.setImage(new Image("/assets/img/craft_table.png", 32, 32, false, true));
users.setTitle(i18n("about.thanks_to.users")); users.setTitle(i18n("about.thanks_to.users"));
users.setSubtitle(i18n("about.thanks_to.users.statement")); users.setSubtitle(i18n("about.thanks_to.users.statement"));
users.setExternalLink("https://hmcl.huangyuhui.net/api/redirect/sponsor"); users.setExternalLink("https://hmcl.huangyuhui.net/api/redirect/sponsor");
IconedTwoLineListItem qq = new IconedTwoLineListItem(); thanks.getContent().setAll(yushijinhun, bangbang93, glavo, mcbbs, mcmod, gamerteam, redLnn, contributors, users);
qq.setImage(new Image("/assets/img/icon.png", 32, 32, false, true));
qq.setTitle(i18n("about.community.qqchannel"));
qq.setSubtitle(i18n("about.community.qqchannel.statement"));
qq.setExternalLink("https://pd.qq.com/s/qor74cm6");
IconedTwoLineListItem discord = new IconedTwoLineListItem();
discord.setImage(new Image("/assets/img/discord.png", 32, 32, false, true));
discord.setTitle(i18n("about.community.discord"));
discord.setSubtitle(i18n("about.community.discord.statement"));
discord.setExternalLink("https://discord.gg/jVvC7HfM6U");
IconedTwoLineListItem kookapp = new IconedTwoLineListItem();
kookapp.setImage(new Image("/assets/img/kookapp.png", 32, 32, false, true));
kookapp.setTitle(i18n("about.community.kookapp"));
kookapp.setSubtitle(i18n("about.community.kookapp.statement"));
kookapp.setExternalLink("https://kook.top/Kx7n3t");
community.getContent().setAll(users, qq, discord, kookapp);
} }
ComponentList dep = new ComponentList(); ComponentList dep = new ComponentList();
@ -209,9 +186,6 @@ public class AboutPage extends StackPane {
ComponentList.createComponentListTitle(i18n("about.thanks_to")), ComponentList.createComponentListTitle(i18n("about.thanks_to")),
thanks, thanks,
ComponentList.createComponentListTitle(i18n("about.community")),
community,
ComponentList.createComponentListTitle(i18n("about.dependency")), ComponentList.createComponentListTitle(i18n("about.dependency")),
dep, dep,

View File

@ -17,454 +17,70 @@
*/ */
package org.jackhuang.hmcl.ui.main; package org.jackhuang.hmcl.ui.main;
import com.google.gson.JsonParseException; import com.jfoenix.controls.JFXScrollPane;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import com.jfoenix.controls.*;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.scene.control.ScrollPane;
import javafx.scene.control.Label; import javafx.scene.image.Image;
import javafx.scene.layout.*; import javafx.scene.layout.VBox;
import org.apache.commons.lang3.mutable.MutableObject; import org.jackhuang.hmcl.ui.construct.ComponentList;
import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.ui.construct.IconedTwoLineListItem;
import org.jackhuang.hmcl.game.OAuthServer; import org.jackhuang.hmcl.ui.construct.SpinnerPane;
import org.jackhuang.hmcl.setting.Accounts;
import org.jackhuang.hmcl.setting.HMCLAccounts;
import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.construct.*;
import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.HttpRequest;
import org.jackhuang.hmcl.util.io.NetworkUtils;
import org.jackhuang.hmcl.util.io.ResponseCodeException;
import org.jackhuang.hmcl.util.javafx.BindingMapping;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class FeedbackPage extends VBox implements PageAware { public class FeedbackPage extends SpinnerPane {
private final ObservableList<FeedbackResponse> feedbacks = FXCollections.observableArrayList();
private final SpinnerPane spinnerPane = new SpinnerPane();
public FeedbackPage() { public FeedbackPage() {
setSpacing(10); VBox content = new VBox();
setPadding(new Insets(10)); content.setPadding(new Insets(10));
content.setSpacing(10);
content.setFillWidth(true);
ScrollPane scrollPane = new ScrollPane(content);
scrollPane.setFitToWidth(true);
JFXScrollPane.smoothScrolling(scrollPane);
setContent(scrollPane);
ComponentList community = new ComponentList();
{ {
HBox loginPane = new HBox(16); IconedTwoLineListItem users = new IconedTwoLineListItem();
loginPane.setAlignment(Pos.CENTER_LEFT); users.setImage(new Image("/assets/img/craft_table.png", 32, 32, false, true));
loginPane.getStyleClass().add("card"); users.setTitle(i18n("feedback.qq_group"));
users.setSubtitle(i18n("feedback.qq_group.statement"));
users.setExternalLink("https://hmcl.huangyuhui.net/api/redirect/sponsor");
TwoLineListItem accountInfo = new TwoLineListItem(); IconedTwoLineListItem github = new IconedTwoLineListItem();
HBox.setHgrow(accountInfo, Priority.ALWAYS); github.setImage(new Image("/assets/img/github.png", 32, 32, false, true));
accountInfo.titleProperty().bind(BindingMapping.of(HMCLAccounts.accountProperty()) github.setTitle(i18n("feedback.github"));
.map(account -> account == null ? i18n("account.not_logged_in") : account.getNickname())); github.setSubtitle(i18n("feedback.github.statement"));
accountInfo.subtitleProperty().bind(BindingMapping.of(HMCLAccounts.accountProperty()) github.setExternalLink("https://github.com/huanghongxun/HMCL/issues/new/choose");
.map(account -> account == null ? i18n("account.not_logged_in") : account.getEmail()));
JFXButton logButton = new JFXButton(); IconedTwoLineListItem qq = new IconedTwoLineListItem();
logButton.textProperty().bind(BindingMapping.of(HMCLAccounts.accountProperty()) qq.setImage(new Image("/assets/img/icon@2x.png", 32, 32, false, true));
.map(account -> account == null ? i18n("account.login") : i18n("account.logout"))); qq.setTitle(i18n("feedback.qq_channel"));
logButton.setOnAction(e -> log()); qq.setSubtitle(i18n("feedback.qq_channel.statement"));
qq.setExternalLink("https://pd.qq.com/s/qor74cm6");
loginPane.getChildren().setAll(accountInfo, logButton); IconedTwoLineListItem discord = new IconedTwoLineListItem();
getChildren().add(loginPane); discord.setImage(new Image("/assets/img/discord.png", 32, 32, false, true));
discord.setTitle(i18n("feedback.discord"));
discord.setSubtitle(i18n("feedback.discord.statement"));
discord.setExternalLink("https://discord.gg/jVvC7HfM6U");
IconedTwoLineListItem kookapp = new IconedTwoLineListItem();
kookapp.setImage(new Image("/assets/img/kookapp.png", 32, 32, false, true));
kookapp.setTitle(i18n("feedback.kookapp"));
kookapp.setSubtitle(i18n("feedback.kookapp.statement"));
kookapp.setExternalLink("https://kook.top/Kx7n3t");
community.getContent().setAll(users, github, qq, discord, kookapp);
} }
{ content.getChildren().addAll(
HBox searchPane = new HBox(8); ComponentList.createComponentListTitle(i18n("feedback.channel")),
searchPane.getStyleClass().add("card"); community
getChildren().add(searchPane); );
JFXTextField searchField = new JFXTextField(); this.setContent(content);
searchField.setOnAction(e -> search(searchField.getText(), "time", true));
HBox.setHgrow(searchField, Priority.ALWAYS);
searchField.setPromptText(i18n("search"));
JFXButton searchButton = new JFXButton();
searchButton.getStyleClass().add("toggle-icon4");
searchButton.setGraphic(SVG.magnify(Theme.blackFillBinding(), -1, -1));
searchButton.setOnAction(e -> search(searchField.getText(), "time", true));
JFXButton addButton = new JFXButton();
addButton.getStyleClass().add("toggle-icon4");
addButton.setGraphic(SVG.plus(Theme.blackFillBinding(), -1, -1));
addButton.setOnAction(e -> addFeedback());
searchPane.getChildren().setAll(searchField, searchButton, addButton);
}
{
spinnerPane.getStyleClass().add("card");
VBox.setVgrow(spinnerPane, Priority.ALWAYS);
JFXListView<FeedbackResponse> listView = new JFXListView<>();
spinnerPane.setContent(listView);
Bindings.bindContent(listView.getItems(), feedbacks);
MutableObject<Object> lastCell = new MutableObject<>();
listView.setCellFactory(x -> new MDListCell<FeedbackResponse>(listView, lastCell) {
private final TwoLineListItem content = new TwoLineListItem();
private final JFXButton likeButton = new JFXButton();
private final JFXButton unlikeButton = new JFXButton();
private final HBox container;
{
container = new HBox(8);
container.setPickOnBounds(false);
container.setAlignment(Pos.CENTER_LEFT);
HBox.setHgrow(content, Priority.ALWAYS);
content.setMouseTransparent(false);
setSelectable();
likeButton.getStyleClass().add("toggle-icon4");
likeButton.setGraphic(FXUtils.limitingSize(SVG.thumbUpOutline(Theme.blackFillBinding(), 24, 24), 24, 24));
unlikeButton.getStyleClass().add("toggle-icon4");
unlikeButton.setGraphic(FXUtils.limitingSize(SVG.thumbDownOutline(Theme.blackFillBinding(), 24, 24), 24, 24));
container.getChildren().setAll(content, likeButton, unlikeButton);
StackPane.setMargin(container, new Insets(10, 16, 10, 16));
getContainer().getChildren().setAll(container);
}
@Override
protected void updateControl(FeedbackResponse feedback, boolean empty) {
if (empty) return;
content.setTitle(feedback.getTitle());
content.setSubtitle(feedback.getAuthor());
content.getTags().setAll(
"#" + feedback.getId(),
i18n("feedback.state." + feedback.getState().name().toLowerCase(Locale.US)),
i18n("feedback.type." + feedback.getType().name().toLowerCase(Locale.US)));
content.setOnMouseClicked(e -> {
getFeedback(feedback.getId())
.thenAcceptAsync(Schedulers.javafx(), f -> {
Controllers.dialog(new ViewFeedbackDialog(f));
})
.start();
});
}
});
getChildren().add(spinnerPane);
}
} }
@Override
public void onPageShown() {
search("", "time", false);
}
private void search(String keyword, String order, boolean showAll) {
HMCLAccounts.HMCLAccount account = HMCLAccounts.getAccount();
Task.supplyAsync(() -> {
Map<String, String> query = mapOf(
pair("keyword", keyword),
pair("order", order)
);
if (showAll) {
query.put("showAll", "1");
}
HttpRequest req = HttpRequest.GET(NetworkUtils.withQuery("https://hmcl.huangyuhui.net/api/feedback", query));
if (account != null) {
req.authorization("Bearer", HMCLAccounts.getAccount().getIdToken())
.header("Authorization-Provider", HMCLAccounts.getAccount().getProvider());
}
return req.<List<FeedbackResponse>>getJson(new TypeToken<List<FeedbackResponse>>(){}.getType());
}).whenComplete(Schedulers.javafx(), (result, exception) -> {
spinnerPane.hideSpinner();
if (exception != null) {
if (exception instanceof ResponseCodeException) {
int responseCode = ((ResponseCodeException) exception).getResponseCode();
if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
spinnerPane.setFailedReason(i18n("feedback.failed.permission"));
return;
} else if (responseCode == 429) {
spinnerPane.setFailedReason(i18n("feedback.failed.too_frequently"));
return;
}
}
spinnerPane.setFailedReason(i18n("feedback.failed"));
} else {
feedbacks.setAll(result);
}
}).start();
}
private Task<FeedbackResponse> getFeedback(int id) {
return Task.supplyAsync(() -> HttpRequest.GET("https://hmcl.huangyuhui.net/api/feedback/" + id).getJson(FeedbackResponse.class));
}
private void log() {
if (HMCLAccounts.getAccount() == null) {
// login
Controllers.dialog(new LoginDialog());
} else {
// logout
HMCLAccounts.setAccount(null);
}
}
private void addFeedback() {
if (HMCLAccounts.getAccount() == null) {
Controllers.dialog(i18n("feedback.add.login"));
return;
}
Controllers.dialog(new AddFeedbackDialog());
}
private static final class LoginDialog extends JFXDialogLayout {
private final SpinnerPane spinnerPane = new SpinnerPane();
private final Label errorLabel = new Label();
private final BooleanProperty logging = new SimpleBooleanProperty();
public LoginDialog() {
setHeading(new Label(i18n("feedback.login")));
VBox vbox = new VBox(8);
setBody(vbox);
HintPane hintPane = new HintPane(MessageDialogPane.MessageType.INFO);
hintPane.textProperty().bind(BindingMapping.of(logging).map(logging -> i18n("account.hmcl.hint")));
hintPane.setOnMouseClicked(e -> {
if (logging.get() && OAuthServer.lastlyOpenedURL != null) {
FXUtils.copyText(OAuthServer.lastlyOpenedURL);
}
});
vbox.getChildren().setAll(hintPane);
JFXButton loginButton = new JFXButton();
spinnerPane.setContent(loginButton);
loginButton.setText(i18n("account.login"));
loginButton.setOnAction(e -> login());
JFXButton cancelButton = new JFXButton();
cancelButton.setText(i18n("button.cancel"));
cancelButton.setOnAction(e -> fireEvent(new DialogCloseEvent()));
onEscPressed(this, cancelButton::fire);
setActions(errorLabel, spinnerPane, cancelButton);
}
private void login() {
spinnerPane.showSpinner();
errorLabel.setText("");
logging.set(true);
HMCLAccounts.login().whenComplete(Schedulers.javafx(), (result, exception) -> {
logging.set(false);
if (exception != null) {
if (exception instanceof IOException) {
errorLabel.setText(i18n("account.failed.connect_authentication_server"));
} else if (exception instanceof JsonParseException) {
errorLabel.setText(i18n("account.failed.server_response_malformed"));
} else {
errorLabel.setText(Accounts.localizeErrorMessage(exception));
}
} else {
fireEvent(new DialogCloseEvent());
}
}).start();
}
}
private static class AddFeedbackDialog extends DialogPane {
JFXTextField titleField = new JFXTextField();
JFXComboBox<FeedbackType> comboBox = new JFXComboBox<>();
JFXTextArea contentArea = new JFXTextArea();
public AddFeedbackDialog() {
setTitle(i18n("feedback.add"));
GridPane body = new GridPane();
body.setVgap(8);
body.setHgap(8);
HintPane searchHintPane = new HintPane(MessageDialogPane.MessageType.WARNING);
GridPane.setColumnSpan(searchHintPane, 2);
searchHintPane.setText(i18n("feedback.add.hint.search_before_add"));
body.addRow(0, searchHintPane);
HintPane titleHintPane = new HintPane(MessageDialogPane.MessageType.INFO);
GridPane.setColumnSpan(titleHintPane, 2);
titleHintPane.setText(i18n("feedback.add.hint.title"));
body.addRow(1, titleHintPane);
titleField.setValidators(new RequiredValidator());
body.addRow(2, new Label(i18n("feedback.title")), titleField);
comboBox.setMaxWidth(-1);
comboBox.getItems().setAll(FeedbackType.values());
comboBox.getSelectionModel().select(0);
comboBox.setConverter(stringConverter(e -> i18n("feedback.type." + e.name().toLowerCase())));
body.addRow(3, new Label(i18n("feedback.type")), comboBox);
Label contentLabel = new Label(i18n("feedback.content"));
GridPane.setColumnSpan(contentLabel, 2);
body.addRow(4, contentLabel);
contentArea.setValidators(new RequiredValidator());
contentArea.setPromptText(i18n("feedback.add.hint.content"));
GridPane.setColumnSpan(contentArea, 2);
body.addRow(5, contentArea);
validProperty().bind(Bindings.createBooleanBinding(() -> {
return titleField.validate() && contentArea.validate();
}, titleField.textProperty(), contentArea.textProperty()));
setBody(body);
}
@Override
protected void onAccept() {
setLoading();
addFeedback(titleField.getText(), comboBox.getValue(), contentArea.getText())
.whenComplete(Schedulers.javafx(), exception -> {
if (exception != null) {
onFailure(exception.getLocalizedMessage());
} else {
onSuccess();
}
})
.start();
}
private Task<?> addFeedback(String title, FeedbackType feedbackType, String content) {
return Task.runAsync(() -> {
HttpRequest.POST("https://hmcl.huangyuhui.net/api/feedback")
.json(mapOf(
pair("title", title),
pair("content", content),
pair("type", feedbackType.name().toLowerCase(Locale.ROOT)),
pair("launcher_version", Metadata.VERSION)
))
.authorization("Bearer", HMCLAccounts.getAccount().getIdToken())
.header("Authorization-Provider", HMCLAccounts.getAccount().getProvider())
.getString();
});
}
}
private static class ViewFeedbackDialog extends JFXDialogLayout {
public ViewFeedbackDialog(FeedbackResponse feedback) {
BorderPane heading = new BorderPane();
TwoLineListItem left = new TwoLineListItem();
heading.setLeft(left);
left.setTitle(feedback.getTitle());
left.setSubtitle(feedback.getAuthor());
left.getTags().add("#" + feedback.getId());
left.getTags().add(i18n("feedback.state." + feedback.getState().name().toLowerCase(Locale.US)));
left.getTags().add(feedback.getLauncherVersion());
left.getTags().add(i18n("feedback.type." + feedback.getType().name().toLowerCase()));
setHeading(heading);
Label content = new Label(feedback.getContent());
content.setWrapText(true);
TwoLineListItem response = new TwoLineListItem();
response.getStyleClass().setAll("two-line-item-second-large");
response.setTitle(i18n("feedback.response"));
response.setSubtitle(StringUtils.isBlank(feedback.getReason())
? i18n("feedback.response.empty")
: feedback.getReason());
VBox body = new VBox(content, response);
body.setSpacing(8);
setBody(body);
JFXButton okButton = new JFXButton();
okButton.setText(i18n("button.ok"));
okButton.setOnAction(e -> fireEvent(new DialogCloseEvent()));
setActions(okButton);
}
}
private static class FeedbackResponse {
private final int id;
private final String title;
private final String content;
private final String author;
@SerializedName("launcher_version")
private final String launcherVersion;
private final FeedbackType type;
private final FeedbackState state;
private final String reason;
public FeedbackResponse(int id, String title, String content, String author, String launcherVersion, FeedbackType type, FeedbackState state, String reason) {
this.id = id;
this.title = title;
this.content = content;
this.author = author;
this.launcherVersion = launcherVersion;
this.type = type;
this.state = state;
this.reason = reason;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
public String getAuthor() {
return author;
}
public String getLauncherVersion() {
return launcherVersion;
}
public FeedbackType getType() {
return type;
}
public FeedbackState getState() {
return state;
}
public String getReason() {
return reason;
}
}
private enum FeedbackType {
FEATURE,
BUG
}
private enum FeedbackState {
OPEN,
REJECTED,
ACCEPTED
}
} }

View File

@ -26,13 +26,6 @@ about.author=Author
about.author.statement=@huanghongxun on bilibili about.author.statement=@huanghongxun on bilibili
about.claim=EULA about.claim=EULA
about.claim.statement=Click on this link for full text. about.claim.statement=Click on this link for full text.
about.community=Community
about.community.qqchannel=QQ Channel
about.community.qqchannel.statement=Join our QQ Channel community !
about.community.discord=Discord
about.community.discord.statement=Join our Discord community !
about.community.kookapp=KOOK
about.community.kookapp.statement=Join our KOOK community !
about.dependency=Third-party Libraries about.dependency=Third-party Libraries
about.legal=Legal Acknowledgement about.legal=Legal Acknowledgement
about.thanks_to=Thanks to about.thanks_to=Thanks to
@ -387,35 +380,17 @@ fatal.unsupported_platform.osx_arm64=HMCL has provided support for Apple Silicon
fatal.unsupported_platform.windows_arm64=HMCL has provided native support for the Windows on ARM platform. If you encounter problems when playing game, please try to start the game with Java based on x86 architecture.\n\nIf you are using the <b>Qualcomm</b> platform, you may need to install the <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">OpenGL Compatibility Pack</a> before playing games.\nClick the link to go to the Microsoft Store and install the compatibility pack. fatal.unsupported_platform.windows_arm64=HMCL has provided native support for the Windows on ARM platform. If you encounter problems when playing game, please try to start the game with Java based on x86 architecture.\n\nIf you are using the <b>Qualcomm</b> platform, you may need to install the <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">OpenGL Compatibility Pack</a> before playing games.\nClick the link to go to the Microsoft Store and install the compatibility pack.
feedback=Feedback feedback=Feedback
feedback.add=Add a Feedback feedback.channel=Feedback channel
feedback.add.hint.search_before_add=Before submitting feedback, you should search the keyword to see if there are duplicated entries. If so, you can upvote it to promote its priority.\n\ feedback.discord=Discord
\n\ feedback.discord.statement=Join our Discord community.
Please provide valuable feedback. Any content that is considered spam, a violation of People's Republic of China's regulations, or unrelated posts other than the launcher itself will lead to an account ban. feedback.github=GitHub Issue
feedback.add.hint.title=The feedback title should summarize your issue concisely. Issues like "I have a problem", "I have an idea", "Game won't open", etc. will be closed automatically. feedback.github.statement=Creating an issue on GitHub.
feedback.add.hint.content=The feedback content should describe your encountered issue or feature you wanted to add. If it's the former, you need to tell us the exact steps to reproduce the issue, e.g. what issue occurred when which buttons are clicked in what specific order. \n\ feedback.kookapp=KOOK
\n\ feedback.kookapp.statement=Join our KOOK community.
If it's the latter, you need to convince us on why it is needed, or what issue it could solve. feedback.qq_channel=QQ Channel
feedback.add.login=You must log in/register an HMCL account first to provide feedback. feedback.qq_channel.statement=Join our QQ Channel community.
feedback.add.permission=You must contribute to our project first before adding feedback\! feedback.qq_group=HMCL User Group
feedback.author=Author feedback.qq_group.statement=Join HMCL user QQ group through donation.
feedback.content=Content
feedback.empty=No feedback to display
feedback.failed=Failed to load
feedback.failed.permission=This feature is limited to registered HMCL users with feedback permission only.
feedback.failed.too_frequently=Whoa\! Slow your searches down\!
feedback.like=Like
feedback.login=Log in to your HMCL account
feedback.response=Reply
feedback.response.empty=Not Viewed Yet
feedback.state.accepted=Accepted
feedback.state.open=Open
feedback.state.rejected=Rejected
feedback.title=Title
feedback.type=Type
feedback.type.bug=Bug Report
feedback.type.feature=Feature Request
feedback.unlike=Dislike
feedback.version=Launcher Version
file=File file=File

View File

@ -26,13 +26,6 @@ about.author=Autor
about.author.statement=@huanghongxun en bilibili about.author.statement=@huanghongxun en bilibili
about.claim=EULA about.claim=EULA
about.claim.statement=Haz clic en este enlace para ver el texto completo. about.claim.statement=Haz clic en este enlace para ver el texto completo.
about.community=Comunidad
about.community.qqchannel=QQ Canal
about.community.qqchannel.statement=¡Únete a nuestra comunidad de QQ Canal!
about.community.discord=Discord
about.community.discord.statement=¡Únete a nuestra comunidad de Discord!
about.community.kaiheila=KaiHeiLa
about.community.kaiheila.statement=¡Únete a nuestra comunidad de KaiHeiLa!
about.dependency=Bibliotecas de terceros about.dependency=Bibliotecas de terceros
about.legal=Reconocimiento legal about.legal=Reconocimiento legal
about.thanks_to=Gracias a about.thanks_to=Gracias a
@ -361,35 +354,12 @@ fatal.illegal_char=Su ruta de usuario contiene un carácter ilegal '\=', por lo
Por ejemplo, no podrá utilizar authlib-injector o cambiar el skin de su cuenta offline. Por ejemplo, no podrá utilizar authlib-injector o cambiar el skin de su cuenta offline.
feedback=Comentarios feedback=Comentarios
feedback.add=Añadir un comentario feedback.discord=Discord
feedback.add.hint.search_before_add=Antes de enviar un comentario, debes buscar la palabra clave para ver si hay entradas duplicadas. Si es así, puedes votar a favor para promover su prioridad. feedback.discord.statement=¡Únete a nuestra comunidad de Discord!
\n\ feedback.kookapp=KaiHeiLa
Por favor, proporciona comentarios valiosos. Cualquier contenido que se considere spam, una violación de las regulaciones de la República Popular de China, o mensajes no relacionados con el launcher en sí, dará lugar a una prohibición de la cuenta. feedback.kookapp.statement=¡Únete a nuestra comunidad de KaiHeiLa!
feedback.add.hint.title=El título del comentario debe resumir tu problema de forma concisa. Los temas como "Tengo un problema", "Tengo una idea", "El juego no se abre", etc. se cerrarán automáticamente. feedback.qq_channel=QQ Canal
feedback.add.hint.content=El contenido del comentario debe describir el problema encontrado o la función que quieres añadir. Si se trata de lo primero, tienes que decirnos los pasos exactos para reproducir el problema, por ejemplo, qué problema se produce cuando se hace clic en qué botones y en qué orden específico. \n\ feedback.qq_channel.statement=¡Únete a nuestra comunidad de QQ Canal!
\n\
Si es lo segundo, necesitas convencernos de por qué es necesario, o qué problema podría resolver.
feedback.add.login=Debe iniciar sesión/registrar una cuenta HMCL primero para proporcionar comentarios.
feedback.add.permission=¡Debe contribuir primero a nuestro proyecto antes de añadir comentarios!
feedback.author=Autor
feedback.content=Contenido
feedback.empty=No hay comentarios para mostrar
feedback.failed=No se ha podido cargar
feedback.failed.permission=Esta función está limitada a los usuarios registrados de HMCL con permiso de comentarios.
feedback.failed.too_frequently=¡Qué! ¡Reduce la velocidad de tus búsquedas!
feedback.like=Me gusta
feedback.login=Acceder a tu cuenta HMCL
feedback.response=Responder
feedback.response.empty=No visto todavía
feedback.state.accepted=Aceptado
feedback.state.open=Abierto
feedback.state.rejected=Rechazado
feedback.title=Título
feedback.type=Tipo
feedback.type.bug=Informe de error
feedback.type.feature=Solicitud de característica
feedback.unlike=No me gusta
feedback.version=Versión del launcher
file=Archivo file=Archivo

View File

@ -24,13 +24,6 @@ about.author=Author
about.author.statement=bilibili : @huanghongxun about.author.statement=bilibili : @huanghongxun
about.claim=EULA about.claim=EULA
about.claim.statement=テキスト全体のリンクをクリックします。 about.claim.statement=テキスト全体のリンクをクリックします。
about.community=コミュニティ
about.community.qqchannel=QQ チャネル
about.community.qqchannel.statement=チャットに参加しよう!
about.community.discord=Discord
about.community.discord.statement=チャットに参加しよう!
about.community.kookapp=KOOK
about.community.kookapp.statement=チャットに参加しよう!
about.dependency=Dependencies about.dependency=Dependencies
about.legal=法的承認 about.legal=法的承認
about.thanks_to=Thanks to about.thanks_to=Thanks to
@ -325,31 +318,12 @@ fatal.samba=If you are trying to run HMCL in a shared folder by Samba, HMCL may
fatal.illegal_char=ユーザーフォルダーのパスに不正な文字'='が含まれています, ログインアカウントやオフラインログインではスキンの変更ができなくなり。 fatal.illegal_char=ユーザーフォルダーのパスに不正な文字'='が含まれています, ログインアカウントやオフラインログインではスキンの変更ができなくなり。
feedback=フィードバック feedback=フィードバック
Feedback.add=フィードバックを追加 feedback.discord=Discord
Feedback.add.hint.search_before_add=新しいフィードバックを追加する前に、キーワードを検索して、報告する内容がすでに報告されているかどうかを確認する必要があります。持っている場合は、それを賛成して優先順位を上げることができます feedback.discord.statement=チャットに参加しよう!
Feedback.add.hint.title=フィードバックのタイトルは、ニーズを簡潔に要約できる必要があります。 「問題がある」、「アイデアがある」、「ゲームが開かない」など、一般的な問題を一目で確認できないタイトルは使用できません。 feedback.kookapp=KOOK
Feedback.add.hint.content=フィードバックコンテンツは、ニーズを完全かつ簡潔に表現する必要があります。問題が発生した場合は、ランチャーを開いた後にクリックされたボタンや、操作が実行された後にトリガーされる問題など、繰り返しパスを詳細に説明する必要があります。新しい機能を追加する場合は、プレーヤーがその機能を必要とする理由、その機能で解決できる問題、およびその機能の実装方法について詳しく説明する必要があります。 feedback.kookapp.statement=チャットに参加しよう!
Feedback.add.login=フィードバックの許可を得るには、HMCLアカウントにログイン/登録する必要があります。 feedback.qq_channel=QQ チャネル
Feedback.add.permission=新しいフィードバックを追加するには、フィードバック権限を取得する必要があります。 feedback.qq_channel.statement=チャットに参加しよう!
feedback.author=作成者
feedback.content=コンテンツ
Feedback.empty=条件を満たすアイテムはありません。
Feedback.failed=ロードに失敗しました
Feedback.failed.permission=フィードバックを送信する権限を持つアカウントにログインしている場合にのみ、キーワードで検索できます。
Feedback.failed.too_frequently=頻繁すぎる。あとでもう一度試してみてください。
Feedback.like=Like
Feedback.login=HMCLアカウントにログインします
feedback.response=応答
Feedback.response.empty=応答なし
feedback.state.accepted=承認済み
Feedback.state.open=保留中
Feedback.state.rejected=拒否されました
feedback.title=タイトル
feedback.type=タイプ
Feedback.type.bug=バグレポート
Feedback.type.feature=機能リクエスト
Feedback.unlike=Unlike
Feedback.version=ランチャーバージョン
file=ファイル file=ファイル

View File

@ -24,13 +24,6 @@ about.author=Автор
about.author.statement=bilibili: @huanghongxun about.author.statement=bilibili: @huanghongxun
about.claim=EULA about.claim=EULA
about.claim.statement=Кликните на ссылку, чтобы увидеть весь текст. about.claim.statement=Кликните на ссылку, чтобы увидеть весь текст.
about.community=Сообщество
about.community.qqchannel=QQ канал
about.community.qqchannel.statement=Присоединиться!
about.community.discord=Discord
about.community.discord.statement=Присоединиться!
about.community.kookapp=KOOK
about.community.kookapp.statement=Присоединиться!
about.dependency=Зависимости about.dependency=Зависимости
about.legal=Юридическое подтверждение about.legal=Юридическое подтверждение
about.thanks_to=Отдельная благодарность about.thanks_to=Отдельная благодарность
@ -328,31 +321,12 @@ fatal.samba=Если вы пытаетесь запустить лаунчер
fatal.illegal_char=Недопустимый символ '=' в пути к папке пользователя. Лаунчер может работать, но некоторые функции не будут работать.\nВы не сможете использовать аккаунт authlib-injector или изменить офлайн скин. fatal.illegal_char=Недопустимый символ '=' в пути к папке пользователя. Лаунчер может работать, но некоторые функции не будут работать.\nВы не сможете использовать аккаунт authlib-injector или изменить офлайн скин.
feedback=Обратная связь feedback=Обратная связь
feedback.add=Добавить отзыв (на английском или китайском) feedback.discord=Discord
feedback.add.hint.search_before_add=Прежде чем добавлять новый отзыв, следует провести поиск по ключевому слову, чтобы выяснить, сообщалось ли уже о том, о чем вы хотите сообщить, или нет. Если есть, вы можете проголосовать за него, чтобы повысить его приоритет. feedback.discord.statement=Присоединиться!
feedback.add.hint.title=Заголовок отзыва должен кратко выражать ваши потребности. Такие заголовки, как "У меня проблема", "У меня есть идея", "Игра не открывается" и т.д. которые не позволяют другим увидеть общую проблему с первого взгляда, неприемлемы. feedback.kookapp=KOOK
feedback.add.hint.content=Содержание отзыва должно полностью и кратко выражать ваши потребности. Если вы столкнулись с проблемой, необходимо подробно описать путь повторения, например, какая кнопка нажимается после открытия программы запуска, и какая проблема возникает после выполнения какой операции. Если вы хотите добавить новые функции, вам нужно всё продумать: почему игрокам нужна эта функция, какие проблемы она может решить и как её можно реализовать. feedback.kookapp.statement=Присоединиться!
feedback.add.login=Чтобы получить разрешение на обратную связь, необходимо войти/зарегистрировать аккаунт HMCL. feedback.qq_channel=QQ канал
feedback.add.permission=Чтобы добавлять отзывы, необходимо получить разрешение. feedback.qq_channel.statement=Присоединиться!
feedback.author=Автор
feedback.content=Контент
feedback.empty=Нет элементов, удовлетворяющих условиям.
feedback.failed=Не удалось загрузить
feedback.failed.permission=Поиск по ключевым словам возможен только при входе в аккаунт с разрешением отправки отзывов.
feedback.failed.too_frequently=Слишком часто. Повторите попытку позже.
feedback.like=Нравится
feedback.login=Войти в аккаунт HMCL
feedback.response=Ответ
feedback.response.empty=Не ответили
feedback.state.accepted=Принято
feedback.state.open=В ожидании
feedback.state.rejected=Отклонено
feedback.title=Заголовок
feedback.type=Тип
feedback.type.bug=Сообщить об ошибке
feedback.type.feature=Запрос функции
feedback.unlike=Не нравится
feedback.version=Версия лаунчера
file=Файл file=Файл

View File

@ -24,13 +24,6 @@ about.author=作者
about.author.statement=bilibili: @huanghongxun about.author.statement=bilibili: @huanghongxun
about.claim=用戶協議 about.claim=用戶協議
about.claim.statement=點擊連結以查看全文 about.claim.statement=點擊連結以查看全文
about.community=社區
about.community.qqchannel=QQ 頻道
about.community.qqchannel.statement=歡迎加入 QQ 頻道 討論區,加入後請遵守討論區規定。
about.community.discord=Discord
about.community.discord.statement=歡迎加入 Discord 討論區,加入後請遵守討論區規定。
about.community.kookapp=KOOK
about.community.kookapp.statement=歡迎加入 KOOK 討論區,加入後請遵守討論區規定。
about.dependency=相依元件 about.dependency=相依元件
about.legal=法律聲明 about.legal=法律聲明
about.thanks_to=鳴謝 about.thanks_to=鳴謝
@ -351,32 +344,18 @@ fatal.unsupported_platform=Minecraft 尚未你您的平臺提供完善支持,
fatal.unsupported_platform.osx_arm64=HMCL 已為 Apple Silicon 平臺提供支援,使用 ARM 原生 Java 啟動遊戲以獲得更流暢的遊戲體驗。\n如果你在遊戲中遭遇問題使用 x86-64 架構的 Java 啟動遊戲可能有更好的相容性。 fatal.unsupported_platform.osx_arm64=HMCL 已為 Apple Silicon 平臺提供支援,使用 ARM 原生 Java 啟動遊戲以獲得更流暢的遊戲體驗。\n如果你在遊戲中遭遇問題使用 x86-64 架構的 Java 啟動遊戲可能有更好的相容性。
fatal.unsupported_platform.windows_arm64=HMCL 已為 Windows on Arm 平臺提供原生支持。如果你在遊戲中遭遇問題,請嘗試使用 x86 架構的 Java 啟動遊戲。\n\n如果你正在使用<b>高通</b>平臺,你可能需要安裝 <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">OpenGL 相容包</a>後才能進行遊戲。點擊連結前往 Microsoft Store 安裝相容包。 fatal.unsupported_platform.windows_arm64=HMCL 已為 Windows on Arm 平臺提供原生支持。如果你在遊戲中遭遇問題,請嘗試使用 x86 架構的 Java 啟動遊戲。\n\n如果你正在使用<b>高通</b>平臺,你可能需要安裝 <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">OpenGL 相容包</a>後才能進行遊戲。點擊連結前往 Microsoft Store 安裝相容包。
feedback=回饋 feedback=反饋
feedback.add=新增回饋 feedback.channel=反饋渠道
feedback.add.hint.search_before_add=添加回饋前,請先搜尋已有回饋中是否已經有人提出過相關內容,如果有,你可以透過給對應回饋按讚來提升對應回饋的優先度。\n請你發布有意義的回饋。如果您發布了違反國家法律法規、灌水等不良訊息或求助遊戲內容玩法等問題你的帳號將被封禁。 feedback.discord=Discord
feedback.add.hint.title=回饋標題需能簡練概括你的需求。"我有問題"、"我有一個想法"、"遊戲打不開" 等無法讓其他人一眼看出大致問題的標題是不被接受的。 feedback.discord.statement=歡迎加入 Discord 討論區,加入後請遵守討論區規定。
feedback.add.hint.content=回饋內容需完整且簡練地表達你的需求。如果你遇到了問題,你需要詳細描述復現路徑,比如在打開啟動器後通過點擊什麼按鈕,做了什麼操作後觸發了什麼問題。如果你希望添加新功能,你需要闡述:為什麼玩家需要該功能,該功能能解決什麼問題,該功能可以怎麼實現。 feedback.github=GitHub Issue
feedback.add.login=你需要先登入/註冊 HMCL 回饋帳號並獲得回饋權限才能添加回饋。 feedback.github.statement=打開一個 GitHub Issue。
feedback.add.permission=你需要獲得回饋權限才能添加回饋。 feedback.kookapp=KOOK
feedback.author=發布者 feedback.kookapp.statement=歡迎加入 KOOK 討論區,加入後請遵守討論區規定。
feedback.content=正文 feedback.qq_channel=QQ 頻道
feedback.empty=沒有滿足條件的回饋 feedback.qq_channel.statement=歡迎加入 QQ 頻道討論區,加入後請遵守討論區規定。
feedback.failed=載入失敗 feedback.qq_group=HMCL 用戶群
feedback.failed.permission=登錄帳戶並取得回饋權限後才能根據關鍵字搜索回饋 feedback.qq_group.statement=通過捐贈支持加入 HMCL 用戶 QQ 群。
feedback.failed.too_frequently=搜索次數太頻繁啦
feedback.like=贊成
feedback.login=登入 HMCL 帳號
feedback.response=回復
feedback.response.empty=尚未查看
feedback.state.accepted=接受
feedback.state.open=開放
feedback.state.rejected=拒絕
feedback.title=標題
feedback.type=類型
feedback.type.bug=問題回饋
feedback.type.feature=新功能請求
feedback.unlike=反對
feedback.version=啟動器版本
file=檔案 file=檔案

View File

@ -24,13 +24,6 @@ about.author=作者
about.author.statement=bilibili ID: @huanghongxun about.author.statement=bilibili ID: @huanghongxun
about.claim=用户协议 about.claim=用户协议
about.claim.statement=点击链接以查看全文 about.claim.statement=点击链接以查看全文
about.community=社区
about.community.qqchannel=QQ 频道
about.community.qqchannel.statement=欢迎加入 QQ 频道 讨论区,加入后请遵守讨论区规定。
about.community.discord=Discord
about.community.discord.statement=欢迎加入 Discord 讨论区,加入后请遵守讨论区规定。
about.community.kookapp=KOOK
about.community.kookapp.statement=欢迎加入 KOOK 讨论区,加入后请遵守讨论区规定。
about.dependency=依赖 about.dependency=依赖
about.legal=法律声明 about.legal=法律声明
about.thanks_to=鸣谢 about.thanks_to=鸣谢
@ -352,31 +345,17 @@ fatal.unsupported_platform.osx_arm64=HMCL 已为 Apple Silicon 平台提供支
fatal.unsupported_platform.windows_arm64=HMCL 已为 Windows on Arm 平台提供原生支持。如果你在游戏中遭遇问题,请尝试使用 x86 架构的 Java 启动游戏。\n\n如果你正在使用<b>高通</b>平台,你可能需要安装 <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">OpenGL 兼容包</a>后才能进行游戏。点击链接前往 Microsoft Store 安装兼容包。 fatal.unsupported_platform.windows_arm64=HMCL 已为 Windows on Arm 平台提供原生支持。如果你在游戏中遭遇问题,请尝试使用 x86 架构的 Java 启动游戏。\n\n如果你正在使用<b>高通</b>平台,你可能需要安装 <a href="ms-windows-store://pdp/?productid=9NQPSL29BFFF">OpenGL 兼容包</a>后才能进行游戏。点击链接前往 Microsoft Store 安装兼容包。
feedback=反馈 feedback=反馈
feedback.add=新增反馈 feedback.channel=反馈渠道
feedback.add.hint.search_before_add=添加反馈前,请先搜索已有反馈中是否已经有人提出过相关内容,如果有,你可以通过给对应反馈点赞来提升对应反馈的优先级。\n请你发布有意义的反馈。如果您发布了违反国家法律法规、灌水等不良信息或求助游戏内容玩法等问题你的账号将被封禁。 feedback.discord=Discord
feedback.add.hint.title=反馈标题需能简练概括你的需求。带有 "我有问题"、"我有一个想法"、"游戏打不开" 等无法让其他人一眼看出大致问题的标题的反馈将会被直接关闭。 feedback.discord.statement=欢迎加入 Discord 讨论区,加入后请遵守讨论区规定。
feedback.add.hint.content=反馈内容需完整且简练地表达你的需求。如果你遇到了问题,你需要详细描述复现路径,比如在打开启动器后通过点击什么按钮,做了什么操作后触发了什么问题。如果你希望添加新功能,你需要阐述:为什么玩家需要该功能,该功能能解决什么问题,该功能可以怎么实现。 feedback.github=GitHub Issue
feedback.add.login=你需要先登录/注册 HMCL 反馈帐户并获得反馈权限才能添加反馈! feedback.github.statement=打开一个 GitHub Issue。
feedback.add.permission=你需要赞助等方式获得反馈权限才能添加反馈! feedback.kookapp=KOOK
feedback.author=发布者 feedback.kookapp.statement=欢迎加入 KOOK 讨论区,加入后请遵守讨论区规定。
feedback.content=正文 feedback.qq_channel=QQ 频道
feedback.empty=没有满足条件的反馈 feedback.qq_channel.statement=欢迎加入 QQ 频道讨论区,加入后请遵守讨论区规定。
feedback.failed=加载失败 feedback.qq_group=HMCL 用户群
feedback.failed.permission=登录账户并取得反馈权限后才能根据关键字搜索反馈! feedback.qq_group.statement=通过捐赠支持加入 HMCL 用户 QQ 群。
feedback.failed.too_frequently=搜索次数太频繁啦!
feedback.like=赞成
feedback.login=登录 HMCL 帐户
feedback.response=回复
feedback.response.empty=尚未查看
feedback.state.accepted=接受
feedback.state.open=开放
feedback.state.rejected=拒绝
feedback.title=标题
feedback.type=类型
feedback.type.bug=问题反馈
feedback.type.feature=新功能请求
feedback.unlike=反对
feedback.version=启动器版本
file=文件 file=文件