drop the separate i18n backend

This commit is contained in:
Damien Elmes 2020-03-14 09:45:00 +10:00
parent 874bc085fe
commit ba17567617
6 changed files with 31 additions and 106 deletions

View file

@ -145,7 +145,7 @@ current_catalog: Optional[
] = None ] = None
# the current Fluent translation instance # the current Fluent translation instance
current_i18n: Optional[anki.rsbackend.I18nBackend] current_i18n: Optional[anki.rsbackend.RustBackend]
# path to locale folder # path to locale folder
locale_folder = "" locale_folder = ""
@ -175,9 +175,9 @@ def set_lang(lang: str, locale_dir: str) -> None:
current_catalog = gettext.translation( current_catalog = gettext.translation(
"anki", gettext_dir, languages=[lang], fallback=True "anki", gettext_dir, languages=[lang], fallback=True
) )
current_i18n = anki.rsbackend.I18nBackend(
preferred_langs=[lang], ftl_folder=ftl_dir current_i18n = anki.rsbackend.RustBackend(ftl_folder=ftl_dir, langs=[lang])
)
locale_folder = locale_dir locale_folder = locale_dir

View file

@ -200,12 +200,20 @@ def _on_progress(progress_bytes: bytes) -> bool:
class RustBackend: class RustBackend:
def __init__(self, server: bool = False) -> None: def __init__(
self,
ftl_folder: Optional[str] = None,
langs: Optional[List[str]] = None,
server: bool = False,
) -> None:
# pick up global defaults if not provided
if ftl_folder is None:
ftl_folder = os.path.join(anki.lang.locale_folder, "fluent") ftl_folder = os.path.join(anki.lang.locale_folder, "fluent")
if langs is None:
langs = [anki.lang.currentLang]
init_msg = pb.BackendInit( init_msg = pb.BackendInit(
locale_folder_path=ftl_folder, locale_folder_path=ftl_folder, preferred_langs=langs, server=server,
preferred_langs=[anki.lang.currentLang],
server=server,
) )
self._backend = ankirspy.open_backend(init_msg.SerializeToString()) self._backend = ankirspy.open_backend(init_msg.SerializeToString())
self._backend.set_progress_callback(_on_progress) self._backend.set_progress_callback(_on_progress)
@ -428,19 +436,6 @@ def translate_string_in(
return pb.TranslateStringIn(key=key, args=args) return pb.TranslateStringIn(key=key, args=args)
class I18nBackend:
def __init__(self, preferred_langs: List[str], ftl_folder: str) -> None:
init_msg = pb.I18nBackendInit(
locale_folder_path=ftl_folder, preferred_langs=preferred_langs
)
self._backend = ankirspy.open_i18n(init_msg.SerializeToString())
def translate(self, key: TR, **kwargs: Union[str, int, float]) -> str:
return self._backend.translate(
translate_string_in(key, **kwargs).SerializeToString()
)
# temporarily force logging of media handling # temporarily force logging of media handling
if "RUST_LOG" not in os.environ: if "RUST_LOG" not in os.environ:
os.environ["RUST_LOG"] = "warn,anki::media=debug" os.environ["RUST_LOG"] = "warn,anki::media=debug"

View file

@ -17,6 +17,7 @@ import anki.lang
import aqt.buildinfo import aqt.buildinfo
from anki import version as _version from anki import version as _version
from anki.consts import HELP_SITE from anki.consts import HELP_SITE
from anki.rsbackend import RustBackend
from anki.utils import checksum, isLin, isMac from anki.utils import checksum, isLin, isMac
from aqt.qt import * from aqt.qt import *
from aqt.utils import locale_dir from aqt.utils import locale_dir
@ -162,15 +163,15 @@ dialogs = DialogManager()
# Qt requires its translator to be installed before any GUI widgets are # Qt requires its translator to be installed before any GUI widgets are
# loaded, and we need the Qt language to match the gettext language or # loaded, and we need the Qt language to match the gettext language or
# translated shortcuts will not work. # translated shortcuts will not work.
#
# The Qt translator needs to be retained to work.
# A reference to the Qt translator needs to be held to prevent it from
# being immediately deallocated.
_qtrans: Optional[QTranslator] = None _qtrans: Optional[QTranslator] = None
def setupLang( def setupLangAndBackend(
pm: ProfileManager, app: QApplication, force: Optional[str] = None pm: ProfileManager, app: QApplication, force: Optional[str] = None
) -> None: ) -> RustBackend:
global _qtrans global _qtrans
try: try:
locale.setlocale(locale.LC_ALL, "") locale.setlocale(locale.LC_ALL, "")
@ -218,6 +219,8 @@ def setupLang(
if _qtrans.load("qtbase_" + qt_lang, qt_dir): if _qtrans.load("qtbase_" + qt_lang, qt_dir):
app.installTranslator(_qtrans) app.installTranslator(_qtrans)
return anki.lang.current_i18n
# App initialisation # App initialisation
########################################################################## ##########################################################################
@ -465,8 +468,8 @@ environment points to a valid, writable folder.""",
if opts.profile: if opts.profile:
pm.openProfile(opts.profile) pm.openProfile(opts.profile)
# i18n # i18n & backend
setupLang(pm, app, opts.lang) backend = setupLangAndBackend(pm, app, opts.lang)
if isLin and pm.glMode() == "auto": if isLin and pm.glMode() == "auto":
from aqt.utils import gfxDriverIsBroken from aqt.utils import gfxDriverIsBroken
@ -483,7 +486,7 @@ environment points to a valid, writable folder.""",
# load the main window # load the main window
import aqt.main import aqt.main
mw = aqt.main.AnkiQt(app, pm, opts, args) mw = aqt.main.AnkiQt(app, pm, backend, opts, args)
if exec: if exec:
app.exec() app.exec()
else: else:

View file

@ -29,6 +29,7 @@ from anki import hooks
from anki.collection import _Collection from anki.collection import _Collection
from anki.hooks import runHook from anki.hooks import runHook
from anki.lang import _, ngettext from anki.lang import _, ngettext
from anki.rsbackend import RustBackend
from anki.sound import AVTag, SoundOrVideoTag from anki.sound import AVTag, SoundOrVideoTag
from anki.storage import Collection from anki.storage import Collection
from anki.utils import devMode, ids2str, intTime, isMac, isWin, splitFields from anki.utils import devMode, ids2str, intTime, isMac, isWin, splitFields
@ -78,10 +79,12 @@ class AnkiQt(QMainWindow):
self, self,
app: QApplication, app: QApplication,
profileManager: ProfileManagerType, profileManager: ProfileManagerType,
backend: RustBackend,
opts: Namespace, opts: Namespace,
args: List[Any], args: List[Any],
) -> None: ) -> None:
QMainWindow.__init__(self) QMainWindow.__init__(self)
self.backend = backend
self.state = "startup" self.state = "startup"
self.opts = opts self.opts = opts
self.col: Optional[_Collection] = None self.col: Optional[_Collection] = None

View file

@ -621,52 +621,3 @@ fn media_sync_progress(p: &MediaSyncProgress, i18n: &I18n) -> pb::MediaSyncProgr
), ),
} }
} }
/// Standalone I18n backend
/// This is a hack to allow translating strings in the GUI
/// when a collection is not open, and in the future it should
/// either be shared with or merged into the backend object.
///////////////////////////////////////////////////////
pub struct I18nBackend {
i18n: I18n,
}
pub fn init_i18n_backend(init_msg: &[u8]) -> Result<I18nBackend> {
let input: pb::I18nBackendInit = match pb::I18nBackendInit::decode(init_msg) {
Ok(req) => req,
Err(_) => return Err(AnkiError::invalid_input("couldn't decode init msg")),
};
let log = log::terminal();
let i18n = I18n::new(&input.preferred_langs, input.locale_folder_path, log);
Ok(I18nBackend { i18n })
}
impl I18nBackend {
pub fn translate(&self, req: &[u8]) -> String {
let req = match pb::TranslateStringIn::decode(req) {
Ok(req) => req,
Err(_e) => return "decoding error".into(),
};
self.translate_string(req)
}
fn translate_string(&self, input: pb::TranslateStringIn) -> String {
let key = match pb::FluentString::from_i32(input.key) {
Some(key) => key,
None => return "invalid key".to_string(),
};
let map = input
.args
.iter()
.map(|(k, v)| (k.as_str(), translate_arg_to_fluent_val(&v)))
.collect();
self.i18n.trn(key, map)
}
}

View file

@ -1,9 +1,7 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use anki::backend::{ use anki::backend::{init_backend, Backend as RustBackend};
init_backend, init_i18n_backend, Backend as RustBackend, I18nBackend as RustI18nBackend,
};
use pyo3::exceptions::Exception; use pyo3::exceptions::Exception;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::types::PyBytes; use pyo3::types::PyBytes;
@ -87,30 +85,6 @@ impl Backend {
} }
} }
// I18n backend
//////////////////////////////////
#[pyclass]
struct I18nBackend {
backend: RustI18nBackend,
}
#[pyfunction]
fn open_i18n(init_msg: &PyBytes) -> PyResult<I18nBackend> {
match init_i18n_backend(init_msg.as_bytes()) {
Ok(backend) => Ok(I18nBackend { backend }),
Err(e) => Err(exceptions::Exception::py_err(format!("{:?}", e))),
}
}
#[pymethods]
impl I18nBackend {
fn translate(&self, input: &PyBytes) -> String {
let in_bytes = input.as_bytes();
self.backend.translate(in_bytes)
}
}
// Module definition // Module definition
////////////////////////////////// //////////////////////////////////
@ -119,7 +93,6 @@ fn ankirspy(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<Backend>()?; m.add_class::<Backend>()?;
m.add_wrapped(wrap_pyfunction!(buildhash)).unwrap(); m.add_wrapped(wrap_pyfunction!(buildhash)).unwrap();
m.add_wrapped(wrap_pyfunction!(open_backend)).unwrap(); m.add_wrapped(wrap_pyfunction!(open_backend)).unwrap();
m.add_wrapped(wrap_pyfunction!(open_i18n)).unwrap();
Ok(()) Ok(())
} }