更新 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.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();
users.setImage(new Image("/assets/img/craft_table.png", 32, 32, false, true));
users.setTitle(i18n("about.thanks_to.users"));
users.setSubtitle(i18n("about.thanks_to.users.statement"));
users.setExternalLink("https://hmcl.huangyuhui.net/api/redirect/sponsor");
IconedTwoLineListItem qq = new IconedTwoLineListItem();
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);
thanks.getContent().setAll(yushijinhun, bangbang93, glavo, mcbbs, mcmod, gamerteam, redLnn, contributors, users);
}
ComponentList dep = new ComponentList();
@ -209,9 +186,6 @@ public class AboutPage extends StackPane {
ComponentList.createComponentListTitle(i18n("about.thanks_to")),
thanks,
ComponentList.createComponentListTitle(i18n("about.community")),
community,
ComponentList.createComponentListTitle(i18n("about.dependency")),
dep,

View File

@ -17,454 +17,70 @@
*/
package org.jackhuang.hmcl.ui.main;
import com.google.gson.JsonParseException;
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 com.jfoenix.controls.JFXScrollPane;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import org.apache.commons.lang3.mutable.MutableObject;
import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.game.OAuthServer;
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 javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.ui.construct.ComponentList;
import org.jackhuang.hmcl.ui.construct.IconedTwoLineListItem;
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
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;
public class FeedbackPage extends VBox implements PageAware {
private final ObservableList<FeedbackResponse> feedbacks = FXCollections.observableArrayList();
private final SpinnerPane spinnerPane = new SpinnerPane();
public class FeedbackPage extends SpinnerPane {
public FeedbackPage() {
setSpacing(10);
setPadding(new Insets(10));
VBox content = new VBox();
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);
loginPane.setAlignment(Pos.CENTER_LEFT);
loginPane.getStyleClass().add("card");
IconedTwoLineListItem users = new IconedTwoLineListItem();
users.setImage(new Image("/assets/img/craft_table.png", 32, 32, false, true));
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();
HBox.setHgrow(accountInfo, Priority.ALWAYS);
accountInfo.titleProperty().bind(BindingMapping.of(HMCLAccounts.accountProperty())
.map(account -> account == null ? i18n("account.not_logged_in") : account.getNickname()));
accountInfo.subtitleProperty().bind(BindingMapping.of(HMCLAccounts.accountProperty())
.map(account -> account == null ? i18n("account.not_logged_in") : account.getEmail()));
IconedTwoLineListItem github = new IconedTwoLineListItem();
github.setImage(new Image("/assets/img/github.png", 32, 32, false, true));
github.setTitle(i18n("feedback.github"));
github.setSubtitle(i18n("feedback.github.statement"));
github.setExternalLink("https://github.com/huanghongxun/HMCL/issues/new/choose");
JFXButton logButton = new JFXButton();
logButton.textProperty().bind(BindingMapping.of(HMCLAccounts.accountProperty())
.map(account -> account == null ? i18n("account.login") : i18n("account.logout")));
logButton.setOnAction(e -> log());
IconedTwoLineListItem qq = new IconedTwoLineListItem();
qq.setImage(new Image("/assets/img/icon@2x.png", 32, 32, false, true));
qq.setTitle(i18n("feedback.qq_channel"));
qq.setSubtitle(i18n("feedback.qq_channel.statement"));
qq.setExternalLink("https://pd.qq.com/s/qor74cm6");
loginPane.getChildren().setAll(accountInfo, logButton);
getChildren().add(loginPane);
IconedTwoLineListItem discord = new IconedTwoLineListItem();
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);
}
{
HBox searchPane = new HBox(8);
searchPane.getStyleClass().add("card");
getChildren().add(searchPane);
content.getChildren().addAll(
ComponentList.createComponentListTitle(i18n("feedback.channel")),
community
);
JFXTextField searchField = new JFXTextField();
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);
}
this.setContent(content);
}
@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.claim=EULA
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.legal=Legal Acknowledgement
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.
feedback=Feedback
feedback.add=Add a Feedback
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\
\n\
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.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.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\
\n\
If it's the latter, you need to convince us on why it is needed, or what issue it could solve.
feedback.add.login=You must log in/register an HMCL account first to provide feedback.
feedback.add.permission=You must contribute to our project first before adding feedback\!
feedback.author=Author
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
feedback.channel=Feedback channel
feedback.discord=Discord
feedback.discord.statement=Join our Discord community.
feedback.github=GitHub Issue
feedback.github.statement=Creating an issue on GitHub.
feedback.kookapp=KOOK
feedback.kookapp.statement=Join our KOOK community.
feedback.qq_channel=QQ Channel
feedback.qq_channel.statement=Join our QQ Channel community.
feedback.qq_group=HMCL User Group
feedback.qq_group.statement=Join HMCL user QQ group through donation.
file=File

View File

@ -26,13 +26,6 @@ about.author=Autor
about.author.statement=@huanghongxun en bilibili
about.claim=EULA
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.legal=Reconocimiento legal
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.
feedback=Comentarios
feedback.add=Añadir un comentario
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.
\n\
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.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.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\
\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
feedback.discord=Discord
feedback.discord.statement=¡Únete a nuestra comunidad de Discord!
feedback.kookapp=KaiHeiLa
feedback.kookapp.statement=¡Únete a nuestra comunidad de KaiHeiLa!
feedback.qq_channel=QQ Canal
feedback.qq_channel.statement=¡Únete a nuestra comunidad de QQ Canal!
file=Archivo

View File

@ -24,13 +24,6 @@ about.author=Author
about.author.statement=bilibili : @huanghongxun
about.claim=EULA
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.legal=法的承認
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=ユーザーフォルダーのパスに不正な文字'='が含まれています, ログインアカウントやオフラインログインではスキンの変更ができなくなり。
feedback=フィードバック
Feedback.add=フィードバックを追加
Feedback.add.hint.search_before_add=新しいフィードバックを追加する前に、キーワードを検索して、報告する内容がすでに報告されているかどうかを確認する必要があります。持っている場合は、それを賛成して優先順位を上げることができます
Feedback.add.hint.title=フィードバックのタイトルは、ニーズを簡潔に要約できる必要があります。 「問題がある」、「アイデアがある」、「ゲームが開かない」など、一般的な問題を一目で確認できないタイトルは使用できません。
Feedback.add.hint.content=フィードバックコンテンツは、ニーズを完全かつ簡潔に表現する必要があります。問題が発生した場合は、ランチャーを開いた後にクリックされたボタンや、操作が実行された後にトリガーされる問題など、繰り返しパスを詳細に説明する必要があります。新しい機能を追加する場合は、プレーヤーがその機能を必要とする理由、その機能で解決できる問題、およびその機能の実装方法について詳しく説明する必要があります。
Feedback.add.login=フィードバックの許可を得るには、HMCLアカウントにログイン/登録する必要があります。
Feedback.add.permission=新しいフィードバックを追加するには、フィードバック権限を取得する必要があります。
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=ランチャーバージョン
feedback.discord=Discord
feedback.discord.statement=チャットに参加しよう!
feedback.kookapp=KOOK
feedback.kookapp.statement=チャットに参加しよう!
feedback.qq_channel=QQ チャネル
feedback.qq_channel.statement=チャットに参加しよう!
file=ファイル

View File

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

View File

@ -24,13 +24,6 @@ about.author=作者
about.author.statement=bilibili: @huanghongxun
about.claim=用戶協議
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.legal=法律聲明
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.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.add=新增回饋
feedback.add.hint.search_before_add=添加回饋前,請先搜尋已有回饋中是否已經有人提出過相關內容,如果有,你可以透過給對應回饋按讚來提升對應回饋的優先度。\n請你發布有意義的回饋。如果您發布了違反國家法律法規、灌水等不良訊息或求助遊戲內容玩法等問題你的帳號將被封禁。
feedback.add.hint.title=回饋標題需能簡練概括你的需求。"我有問題"、"我有一個想法"、"遊戲打不開" 等無法讓其他人一眼看出大致問題的標題是不被接受的。
feedback.add.hint.content=回饋內容需完整且簡練地表達你的需求。如果你遇到了問題,你需要詳細描述復現路徑,比如在打開啟動器後通過點擊什麼按鈕,做了什麼操作後觸發了什麼問題。如果你希望添加新功能,你需要闡述:為什麼玩家需要該功能,該功能能解決什麼問題,該功能可以怎麼實現。
feedback.add.login=你需要先登入/註冊 HMCL 回饋帳號並獲得回饋權限才能添加回饋。
feedback.add.permission=你需要獲得回饋權限才能添加回饋。
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=啟動器版本
feedback=反饋
feedback.channel=反饋渠道
feedback.discord=Discord
feedback.discord.statement=歡迎加入 Discord 討論區,加入後請遵守討論區規定。
feedback.github=GitHub Issue
feedback.github.statement=打開一個 GitHub Issue。
feedback.kookapp=KOOK
feedback.kookapp.statement=歡迎加入 KOOK 討論區,加入後請遵守討論區規定。
feedback.qq_channel=QQ 頻道
feedback.qq_channel.statement=歡迎加入 QQ 頻道討論區,加入後請遵守討論區規定。
feedback.qq_group=HMCL 用戶群
feedback.qq_group.statement=通過捐贈支持加入 HMCL 用戶 QQ 群。
file=檔案

View File

@ -24,13 +24,6 @@ about.author=作者
about.author.statement=bilibili ID: @huanghongxun
about.claim=用户协议
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.legal=法律声明
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 安装兼容包。
feedback=反馈
feedback.add=新增反馈
feedback.add.hint.search_before_add=添加反馈前,请先搜索已有反馈中是否已经有人提出过相关内容,如果有,你可以通过给对应反馈点赞来提升对应反馈的优先级。\n请你发布有意义的反馈。如果您发布了违反国家法律法规、灌水等不良信息或求助游戏内容玩法等问题你的账号将被封禁。
feedback.add.hint.title=反馈标题需能简练概括你的需求。带有 "我有问题"、"我有一个想法"、"游戏打不开" 等无法让其他人一眼看出大致问题的标题的反馈将会被直接关闭。
feedback.add.hint.content=反馈内容需完整且简练地表达你的需求。如果你遇到了问题,你需要详细描述复现路径,比如在打开启动器后通过点击什么按钮,做了什么操作后触发了什么问题。如果你希望添加新功能,你需要阐述:为什么玩家需要该功能,该功能能解决什么问题,该功能可以怎么实现。
feedback.add.login=你需要先登录/注册 HMCL 反馈帐户并获得反馈权限才能添加反馈!
feedback.add.permission=你需要赞助等方式获得反馈权限才能添加反馈!
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=启动器版本
feedback.channel=反馈渠道
feedback.discord=Discord
feedback.discord.statement=欢迎加入 Discord 讨论区,加入后请遵守讨论区规定。
feedback.github=GitHub Issue
feedback.github.statement=打开一个 GitHub Issue。
feedback.kookapp=KOOK
feedback.kookapp.statement=欢迎加入 KOOK 讨论区,加入后请遵守讨论区规定。
feedback.qq_channel=QQ 频道
feedback.qq_channel.statement=欢迎加入 QQ 频道讨论区,加入后请遵守讨论区规定。
feedback.qq_group=HMCL 用户群
feedback.qq_group.statement=通过捐赠支持加入 HMCL 用户 QQ 群。
file=文件