mirror of
https://github.com/ankitects/anki.git
synced 2025-12-20 10:22:57 -05:00
localize some error messages
This commit is contained in:
parent
67a741958c
commit
d612aa0945
8 changed files with 96 additions and 65 deletions
|
|
@ -18,6 +18,7 @@ enum StringsGroup {
|
|||
MEDIA_CHECK = 2;
|
||||
CARD_TEMPLATES = 3;
|
||||
SYNC = 4;
|
||||
NETWORK = 5;
|
||||
}
|
||||
|
||||
// 1-15 reserved for future use; 2047 for errors
|
||||
|
|
@ -102,6 +103,7 @@ message NetworkError {
|
|||
PROXY_AUTH = 3;
|
||||
}
|
||||
NetworkErrorKind kind = 2;
|
||||
string localized = 3;
|
||||
}
|
||||
|
||||
message SyncError {
|
||||
|
|
@ -117,6 +119,7 @@ message SyncError {
|
|||
RESYNC_REQUIRED = 7;
|
||||
}
|
||||
SyncErrorKind kind = 2;
|
||||
string localized = 3;
|
||||
}
|
||||
|
||||
message MediaSyncProgress {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ class NetworkError(StringError):
|
|||
def kind(self) -> NetworkErrorKind:
|
||||
return self.args[1]
|
||||
|
||||
def localized(self) -> str:
|
||||
return self.args[2]
|
||||
|
||||
|
||||
class IOError(StringError):
|
||||
pass
|
||||
|
|
@ -57,6 +60,9 @@ class SyncError(StringError):
|
|||
def kind(self) -> SyncErrorKind:
|
||||
return self.args[1]
|
||||
|
||||
def localized(self) -> str:
|
||||
return self.args[2]
|
||||
|
||||
|
||||
def proto_exception_to_native(err: pb.BackendError) -> Exception:
|
||||
val = err.WhichOneof("value")
|
||||
|
|
@ -64,7 +70,7 @@ def proto_exception_to_native(err: pb.BackendError) -> Exception:
|
|||
return Interrupted()
|
||||
elif val == "network_error":
|
||||
e = err.network_error
|
||||
return NetworkError(e.info, e.kind)
|
||||
return NetworkError(e.info, e.kind, e.localized)
|
||||
elif val == "io_error":
|
||||
return IOError(err.io_error.info)
|
||||
elif val == "db_error":
|
||||
|
|
@ -75,7 +81,7 @@ def proto_exception_to_native(err: pb.BackendError) -> Exception:
|
|||
return StringError(err.invalid_input.info)
|
||||
elif val == "sync_error":
|
||||
e2 = err.sync_error
|
||||
return SyncError(e2.info, e2.kind)
|
||||
return SyncError(e2.info, e2.kind, e2.localized)
|
||||
else:
|
||||
assert_impossible_literal(val)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,18 +10,14 @@ from typing import List, Union
|
|||
|
||||
import aqt
|
||||
from anki import hooks
|
||||
from anki.lang import _
|
||||
from anki.rsbackend import (
|
||||
DBError,
|
||||
Interrupted,
|
||||
MediaSyncProgress,
|
||||
NetworkError,
|
||||
NetworkErrorKind,
|
||||
Progress,
|
||||
ProgressKind,
|
||||
StringsGroup,
|
||||
SyncError,
|
||||
SyncErrorKind,
|
||||
)
|
||||
from anki.types import assert_impossible
|
||||
from anki.utils import intTime
|
||||
|
|
@ -114,40 +110,10 @@ class MediaSyncer:
|
|||
|
||||
self._log_and_notify(tr(StringsGroup.SYNC, "media-failed"))
|
||||
if isinstance(exc, SyncError):
|
||||
kind = exc.kind()
|
||||
if kind == SyncErrorKind.AUTH_FAILED:
|
||||
self.mw.pm.set_sync_key(None)
|
||||
showWarning(
|
||||
_("AnkiWeb ID or password was incorrect; please try again.")
|
||||
)
|
||||
elif kind == SyncErrorKind.SERVER_ERROR:
|
||||
showWarning(
|
||||
_(
|
||||
"AnkiWeb encountered a problem. Please try again in a few minutes."
|
||||
)
|
||||
)
|
||||
elif kind == SyncErrorKind.MEDIA_CHECK_REQUIRED:
|
||||
showWarning(_("Please use the Tools>Check Media menu option."))
|
||||
elif kind == SyncErrorKind.RESYNC_REQUIRED:
|
||||
showWarning(
|
||||
_(
|
||||
"Please sync again, and post on the support forum if this message keeps appearing."
|
||||
)
|
||||
)
|
||||
else:
|
||||
showWarning(_("Unexpected error: {}").format(str(exc)))
|
||||
showWarning(exc.localized())
|
||||
elif isinstance(exc, NetworkError):
|
||||
nkind = exc.kind()
|
||||
if nkind in (NetworkErrorKind.OFFLINE, NetworkErrorKind.TIMEOUT):
|
||||
showWarning(
|
||||
_("Syncing failed; please check your internet connection.")
|
||||
+ "\n\n"
|
||||
+ _("Detailed error: {}").format(str(exc))
|
||||
)
|
||||
else:
|
||||
showWarning(_("Unexpected error: {}").format(str(exc)))
|
||||
elif isinstance(exc, DBError):
|
||||
showWarning(_("Problem accessing the media database: {}").format(str(exc)))
|
||||
msg = exc.localized()
|
||||
msg += "\n\n" + tr(StringsGroup.NETWORK, "details", details=str(exc))
|
||||
else:
|
||||
raise exc
|
||||
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@ enum Progress<'a> {
|
|||
}
|
||||
|
||||
/// Convert an Anki error to a protobuf error.
|
||||
impl std::convert::From<AnkiError> for pb::BackendError {
|
||||
fn from(err: AnkiError) -> Self {
|
||||
fn anki_error_to_proto_error(err: AnkiError, i18n: &I18n) -> pb::BackendError {
|
||||
use pb::backend_error::Value as V;
|
||||
let localized = err.localized_description(i18n);
|
||||
let value = match err {
|
||||
AnkiError::InvalidInput { info } => V::InvalidInput(pb::StringError { info }),
|
||||
AnkiError::TemplateError { info } => V::TemplateParse(pb::TemplateParseError { info }),
|
||||
|
|
@ -50,22 +50,23 @@ impl std::convert::From<AnkiError> for pb::BackendError {
|
|||
AnkiError::NetworkError { info, kind } => V::NetworkError(pb::NetworkError {
|
||||
info,
|
||||
kind: kind.into(),
|
||||
localized,
|
||||
}),
|
||||
AnkiError::SyncError { info, kind } => V::SyncError(pb::SyncError {
|
||||
info,
|
||||
kind: kind.into(),
|
||||
localized,
|
||||
}),
|
||||
AnkiError::Interrupted => V::Interrupted(Empty {}),
|
||||
};
|
||||
|
||||
pb::BackendError { value: Some(value) }
|
||||
}
|
||||
}
|
||||
|
||||
// Convert an Anki error to a protobuf output.
|
||||
impl std::convert::From<AnkiError> for pb::backend_output::Value {
|
||||
fn from(err: AnkiError) -> Self {
|
||||
pb::backend_output::Value::Error(err.into())
|
||||
impl std::convert::From<pb::BackendError> for pb::backend_output::Value {
|
||||
fn from(err: pb::BackendError) -> Self {
|
||||
pb::backend_output::Value::Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,8 +137,9 @@ impl Backend {
|
|||
Err(_e) => {
|
||||
// unable to decode
|
||||
let err = AnkiError::invalid_input("couldn't decode backend request");
|
||||
let oerr = anki_error_to_proto_error(err, &self.i18n);
|
||||
let output = pb::BackendOutput {
|
||||
value: Some(err.into()),
|
||||
value: Some(oerr.into()),
|
||||
};
|
||||
output.encode(&mut buf).expect("encode failed");
|
||||
return buf;
|
||||
|
|
@ -153,10 +155,14 @@ impl Backend {
|
|||
let oval = if let Some(ival) = input.value {
|
||||
match self.run_command_inner(ival) {
|
||||
Ok(output) => output,
|
||||
Err(err) => err.into(),
|
||||
Err(err) => anki_error_to_proto_error(err, &self.i18n).into(),
|
||||
}
|
||||
} else {
|
||||
AnkiError::invalid_input("unrecognized backend input value").into()
|
||||
anki_error_to_proto_error(
|
||||
AnkiError::invalid_input("unrecognized backend input value"),
|
||||
&self.i18n,
|
||||
)
|
||||
.into()
|
||||
};
|
||||
|
||||
pb::BackendOutput { value: Some(oval) }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use crate::i18n::{I18n, StringsGroup};
|
||||
pub use failure::{Error, Fail};
|
||||
use reqwest::StatusCode;
|
||||
use std::io;
|
||||
|
|
@ -53,6 +54,36 @@ impl AnkiError {
|
|||
kind: SyncErrorKind::Other,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn localized_description(&self, i18n: &I18n) -> String {
|
||||
match self {
|
||||
AnkiError::SyncError { info, kind } => {
|
||||
let cat = i18n.get(StringsGroup::Sync);
|
||||
match kind {
|
||||
SyncErrorKind::ServerMessage => info.into(),
|
||||
SyncErrorKind::Other => info.into(),
|
||||
SyncErrorKind::Conflict => cat.tr("conflict"),
|
||||
SyncErrorKind::ServerError => cat.tr("server-error"),
|
||||
SyncErrorKind::ClientTooOld => cat.tr("client-too-old"),
|
||||
SyncErrorKind::AuthFailed => cat.tr("wrong-pass"),
|
||||
SyncErrorKind::MediaCheckRequired => cat.tr("media-check-required"),
|
||||
SyncErrorKind::ResyncRequired => cat.tr("resync-required"),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
AnkiError::NetworkError { kind, .. } => {
|
||||
let cat = i18n.get(StringsGroup::Network);
|
||||
match kind {
|
||||
NetworkErrorKind::Offline => cat.tr("offline"),
|
||||
NetworkErrorKind::Timeout => cat.tr("timeout"),
|
||||
NetworkErrorKind::ProxyAuth => cat.tr("proxy-auth"),
|
||||
NetworkErrorKind::Other => cat.tr("other"),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
_ => "".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ fn ftl_fallback_for_group(group: StringsGroup) -> String {
|
|||
StringsGroup::MediaCheck => include_str!("media-check.ftl"),
|
||||
StringsGroup::CardTemplates => include_str!("card-template-rendering.ftl"),
|
||||
StringsGroup::Sync => include_str!("sync.ftl"),
|
||||
StringsGroup::Network => include_str!("network.ftl"),
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
|
|
@ -69,6 +70,7 @@ fn localized_ftl_for_group(group: StringsGroup, lang_ftl_folder: &Path) -> Optio
|
|||
StringsGroup::MediaCheck => "media-check.ftl",
|
||||
StringsGroup::CardTemplates => "card-template-rendering.ftl",
|
||||
StringsGroup::Sync => "sync.ftl",
|
||||
StringsGroup::Network => "network.ftl",
|
||||
});
|
||||
fs::read_to_string(&path)
|
||||
.map_err(|e| {
|
||||
|
|
|
|||
6
rslib/src/i18n/network.ftl
Normal file
6
rslib/src/i18n/network.ftl
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
offline = Please check your internet connection.
|
||||
timeout = Connection timed out. Please try again on a different network.
|
||||
proxy-auth = Your proxy requires authentication.
|
||||
other = A network error occurred.
|
||||
|
||||
details = Error details: {$details}
|
||||
|
|
@ -14,3 +14,14 @@ media-aborted = Media sync aborted.
|
|||
media-disabled = Media sync disabled.
|
||||
|
||||
abort-button = Abort
|
||||
|
||||
## Error messages
|
||||
|
||||
conflict = Only one copy of Anki can sync to your account at once. Please wait a few minutes, then try again.
|
||||
server-error = AnkiWeb encountered a problem. Please try again in a few minutes.
|
||||
client-too-old =
|
||||
Your Anki version is too old. Please update to the latest version to continue syncing.
|
||||
wrong-pass = AnkiWeb ID or password was incorrect; please try again.
|
||||
media-check-required = Please use the Check Media function, then sync again.
|
||||
resync-required =
|
||||
Please sync again. If this message keeps appearing, please post on the support site.
|
||||
|
|
|
|||
Loading…
Reference in a new issue