localize some error messages

This commit is contained in:
Damien Elmes 2020-02-17 11:38:22 +10:00
parent 67a741958c
commit d612aa0945
8 changed files with 96 additions and 65 deletions

View file

@ -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 {

View file

@ -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)

View file

@ -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

View file

@ -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) }

View file

@ -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)]

View file

@ -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| {

View 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}

View file

@ -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.