diff --git a/rslib/i18n/src/lib.rs b/rslib/i18n/src/lib.rs index 1b93eee8f..c97a9ba81 100644 --- a/rslib/i18n/src/lib.rs +++ b/rslib/i18n/src/lib.rs @@ -426,50 +426,50 @@ mod test { #[test] fn i18n() { // English template - let i18n = I18n::new(&["zz"]); - assert_eq!(i18n.translate("valid-key", None), "a valid key"); - assert_eq!(i18n.translate("invalid-key", None), "invalid-key"); + let tr = I18n::new(&["zz"]); + assert_eq!(tr.translate("valid-key", None), "a valid key"); + assert_eq!(tr.translate("invalid-key", None), "invalid-key"); assert_eq!( - i18n.translate("two-args-key", Some(tr_args!["one"=>1.1, "two"=>"2"])), + tr.translate("two-args-key", Some(tr_args!["one"=>1.1, "two"=>"2"])), "two args: 1.1 and 2" ); assert_eq!( - i18n.translate("plural", Some(tr_args!["hats"=>1.0])), + tr.translate("plural", Some(tr_args!["hats"=>1.0])), "You have 1 hat." ); assert_eq!( - i18n.translate("plural", Some(tr_args!["hats"=>1.1])), + tr.translate("plural", Some(tr_args!["hats"=>1.1])), "You have 1.1 hats." ); assert_eq!( - i18n.translate("plural", Some(tr_args!["hats"=>3])), + tr.translate("plural", Some(tr_args!["hats"=>3])), "You have 3 hats." ); // Another language - let i18n = I18n::new(&["ja_JP"]); - assert_eq!(i18n.translate("valid-key", None), "キー"); - assert_eq!(i18n.translate("only-in-english", None), "not translated"); - assert_eq!(i18n.translate("invalid-key", None), "invalid-key"); + let tr = I18n::new(&["ja_JP"]); + assert_eq!(tr.translate("valid-key", None), "キー"); + assert_eq!(tr.translate("only-in-english", None), "not translated"); + assert_eq!(tr.translate("invalid-key", None), "invalid-key"); assert_eq!( - i18n.translate("two-args-key", Some(tr_args!["one"=>1, "two"=>"2"])), + tr.translate("two-args-key", Some(tr_args!["one"=>1, "two"=>"2"])), "1と2" ); // Decimal separator - let i18n = I18n::new(&["pl-PL"]); + let tr = I18n::new(&["pl-PL"]); // Polish will use a comma if the string is translated assert_eq!( - i18n.translate("one-arg-key", Some(tr_args!["one"=>2.07])), + tr.translate("one-arg-key", Some(tr_args!["one"=>2.07])), "fake Polish 2,07" ); // but if it falls back on English, it will use an English separator assert_eq!( - i18n.translate("two-args-key", Some(tr_args!["one"=>1, "two"=>2.07])), + tr.translate("two-args-key", Some(tr_args!["one"=>1, "two"=>2.07])), "two args: 1 and 2.07" ); } diff --git a/rslib/src/backend/collection.rs b/rslib/src/backend/collection.rs index 83df57dda..aa5104e70 100644 --- a/rslib/src/backend/collection.rs +++ b/rslib/src/backend/collection.rs @@ -15,7 +15,7 @@ use slog::error; impl CollectionService for Backend { fn latest_progress(&self, _input: pb::Empty) -> Result { let progress = self.progress_state.lock().unwrap().last_progress; - Ok(progress_to_proto(progress, &self.i18n)) + Ok(progress_to_proto(progress, &self.tr)) } fn set_wants_abort(&self, _input: pb::Empty) -> Result { @@ -43,7 +43,7 @@ impl CollectionService for Backend { input.media_folder_path, input.media_db_path, self.server, - self.i18n.clone(), + self.tr.clone(), logger, )?; @@ -79,26 +79,26 @@ impl CollectionService for Backend { self.with_col(|col| { col.check_database(progress_fn) .map(|problems| pb::CheckDatabaseOut { - problems: problems.to_i18n_strings(&col.i18n), + problems: problems.to_i18n_strings(&col.tr), }) }) } fn get_undo_status(&self, _input: pb::Empty) -> Result { - self.with_col(|col| Ok(col.undo_status().into_protobuf(&col.i18n))) + self.with_col(|col| Ok(col.undo_status().into_protobuf(&col.tr))) } fn undo(&self, _input: pb::Empty) -> Result { self.with_col(|col| { col.undo()?; - Ok(col.undo_status().into_protobuf(&col.i18n)) + Ok(col.undo_status().into_protobuf(&col.tr)) }) } fn redo(&self, _input: pb::Empty) -> Result { self.with_col(|col| { col.redo()?; - Ok(col.undo_status().into_protobuf(&col.i18n)) + Ok(col.undo_status().into_protobuf(&col.tr)) }) } } diff --git a/rslib/src/backend/err.rs b/rslib/src/backend/err.rs index b655ce1b3..6ed2c6d96 100644 --- a/rslib/src/backend/err.rs +++ b/rslib/src/backend/err.rs @@ -8,9 +8,9 @@ use crate::{ }; /// Convert an Anki error to a protobuf error. -pub(super) fn anki_error_to_proto_error(err: AnkiError, i18n: &I18n) -> pb::BackendError { +pub(super) fn anki_error_to_proto_error(err: AnkiError, tr: &I18n) -> pb::BackendError { use pb::backend_error::Value as V; - let localized = err.localized_description(i18n); + let localized = err.localized_description(tr); let value = match err { AnkiError::InvalidInput { .. } => V::InvalidInput(pb::Empty {}), AnkiError::TemplateError { .. } => V::TemplateParse(pb::Empty {}), diff --git a/rslib/src/backend/i18n.rs b/rslib/src/backend/i18n.rs index b4e62ee29..16ab33f93 100644 --- a/rslib/src/backend/i18n.rs +++ b/rslib/src/backend/i18n.rs @@ -19,7 +19,7 @@ impl I18nService for Backend { .collect(); Ok(self - .i18n + .tr .translate_via_index( input.module_index as usize, input.message_index as usize, @@ -31,15 +31,15 @@ impl I18nService for Backend { fn format_timespan(&self, input: pb::FormatTimespanIn) -> Result { use pb::format_timespan_in::Context; Ok(match input.context() { - Context::Precise => time_span(input.seconds, &self.i18n, true), - Context::Intervals => time_span(input.seconds, &self.i18n, false), - Context::AnswerButtons => answer_button_time(input.seconds, &self.i18n), + Context::Precise => time_span(input.seconds, &self.tr, true), + Context::Intervals => time_span(input.seconds, &self.tr, false), + Context::AnswerButtons => answer_button_time(input.seconds, &self.tr), } .into()) } fn i18n_resources(&self, input: pb::I18nResourcesIn) -> Result { - serde_json::to_vec(&self.i18n.resources_for_js(&input.modules)) + serde_json::to_vec(&self.tr.resources_for_js(&input.modules)) .map(Into::into) .map_err(Into::into) } diff --git a/rslib/src/backend/mod.rs b/rslib/src/backend/mod.rs index 3095ba94d..f8ad40c5f 100644 --- a/rslib/src/backend/mod.rs +++ b/rslib/src/backend/mod.rs @@ -62,7 +62,7 @@ use self::err::anki_error_to_proto_error; pub struct Backend { col: Arc>>, - i18n: I18n, + tr: I18n, server: bool, sync_abort: AbortHandleSlot, progress_state: Arc>, @@ -81,16 +81,16 @@ pub fn init_backend(init_msg: &[u8]) -> std::result::Result { Err(_) => return Err("couldn't decode init request".into()), }; - let i18n = I18n::new(&input.preferred_langs); + let tr = I18n::new(&input.preferred_langs); - Ok(Backend::new(i18n, input.server)) + Ok(Backend::new(tr, input.server)) } impl Backend { - pub fn new(i18n: I18n, server: bool) -> Backend { + pub fn new(tr: I18n, server: bool) -> Backend { Backend { col: Arc::new(Mutex::new(None)), - i18n, + tr, server, sync_abort: Arc::new(Mutex::new(None)), progress_state: Arc::new(Mutex::new(ProgressState { @@ -103,7 +103,7 @@ impl Backend { } pub fn i18n(&self) -> &I18n { - &self.i18n + &self.tr } pub fn run_method( @@ -134,7 +134,7 @@ impl Backend { pb::ServiceIndex::Cards => CardsService::run_method(self, method, input), }) .map_err(|err| { - let backend_err = anki_error_to_proto_error(err, &self.i18n); + let backend_err = anki_error_to_proto_error(err, &self.tr); let mut bytes = Vec::new(); backend_err.encode(&mut bytes).unwrap(); bytes @@ -143,7 +143,7 @@ impl Backend { pub fn run_db_command_bytes(&self, input: &[u8]) -> std::result::Result, Vec> { self.db_command(input).map_err(|err| { - let backend_err = anki_error_to_proto_error(err, &self.i18n); + let backend_err = anki_error_to_proto_error(err, &self.tr); let mut bytes = Vec::new(); backend_err.encode(&mut bytes).unwrap(); bytes diff --git a/rslib/src/backend/notetypes.rs b/rslib/src/backend/notetypes.rs index cab29ba03..1f715d59f 100644 --- a/rslib/src/backend/notetypes.rs +++ b/rslib/src/backend/notetypes.rs @@ -25,7 +25,7 @@ impl NoteTypesService for Backend { fn get_stock_notetype_legacy(&self, input: pb::StockNoteType) -> Result { // fixme: use individual functions instead of full vec - let mut all = all_stock_notetypes(&self.i18n); + let mut all = all_stock_notetypes(&self.tr); let idx = (input.kind as usize).min(all.len() - 1); let nt = all.swap_remove(idx); let schema11: NoteTypeSchema11 = nt.into(); diff --git a/rslib/src/backend/ops.rs b/rslib/src/backend/ops.rs index 22c39ac36..4977ebeb8 100644 --- a/rslib/src/backend/ops.rs +++ b/rslib/src/backend/ops.rs @@ -31,10 +31,10 @@ impl From for pb::OpChanges { } impl UndoStatus { - pub(crate) fn into_protobuf(self, i18n: &I18n) -> pb::UndoStatus { + pub(crate) fn into_protobuf(self, tr: &I18n) -> pb::UndoStatus { pb::UndoStatus { - undo: self.undo.map(|op| op.describe(i18n)).unwrap_or_default(), - redo: self.redo.map(|op| op.describe(i18n)).unwrap_or_default(), + undo: self.undo.map(|op| op.describe(tr)).unwrap_or_default(), + redo: self.redo.map(|op| op.describe(tr)).unwrap_or_default(), } } } diff --git a/rslib/src/backend/progress.rs b/rslib/src/backend/progress.rs index 10fe84ee4..3890c97d0 100644 --- a/rslib/src/backend/progress.rs +++ b/rslib/src/backend/progress.rs @@ -52,12 +52,12 @@ pub(super) enum Progress { DatabaseCheck(DatabaseCheckProgress), } -pub(super) fn progress_to_proto(progress: Option, i18n: &I18n) -> pb::Progress { +pub(super) fn progress_to_proto(progress: Option, tr: &I18n) -> pb::Progress { let progress = if let Some(progress) = progress { match progress { - Progress::MediaSync(p) => pb::progress::Value::MediaSync(media_sync_progress(p, i18n)), + Progress::MediaSync(p) => pb::progress::Value::MediaSync(media_sync_progress(p, tr)), Progress::MediaCheck(n) => { - pb::progress::Value::MediaCheck(i18n.media_check_checked(n).into()) + pb::progress::Value::MediaCheck(tr.media_check_checked(n).into()) } Progress::FullSync(p) => pb::progress::Value::FullSync(pb::progress::FullSync { transferred: p.transferred_bytes as u32, @@ -65,15 +65,15 @@ pub(super) fn progress_to_proto(progress: Option, i18n: &I18n) -> pb:: }), Progress::NormalSync(p) => { let stage = match p.stage { - SyncStage::Connecting => i18n.sync_syncing(), - SyncStage::Syncing => i18n.sync_syncing(), - SyncStage::Finalizing => i18n.sync_checking(), + SyncStage::Connecting => tr.sync_syncing(), + SyncStage::Syncing => tr.sync_syncing(), + SyncStage::Finalizing => tr.sync_checking(), } .to_string(); - let added = i18n + let added = tr .sync_added_updated_count(p.local_update, p.remote_update) .into(); - let removed = i18n + let removed = tr .sync_media_removed_count(p.local_remove, p.remote_remove) .into(); pb::progress::Value::NormalSync(pb::progress::NormalSync { @@ -86,15 +86,15 @@ pub(super) fn progress_to_proto(progress: Option, i18n: &I18n) -> pb:: let mut stage_total = 0; let mut stage_current = 0; let stage = match p { - DatabaseCheckProgress::Integrity => i18n.database_check_checking_integrity(), - DatabaseCheckProgress::Optimize => i18n.database_check_rebuilding(), - DatabaseCheckProgress::Cards => i18n.database_check_checking_cards(), + DatabaseCheckProgress::Integrity => tr.database_check_checking_integrity(), + DatabaseCheckProgress::Optimize => tr.database_check_rebuilding(), + DatabaseCheckProgress::Cards => tr.database_check_checking_cards(), DatabaseCheckProgress::Notes { current, total } => { stage_total = total; stage_current = current; - i18n.database_check_checking_notes() + tr.database_check_checking_notes() } - DatabaseCheckProgress::History => i18n.database_check_checking_history(), + DatabaseCheckProgress::History => tr.database_check_checking_history(), } .to_string(); pb::progress::Value::DatabaseCheck(pb::progress::DatabaseCheck { @@ -112,13 +112,13 @@ pub(super) fn progress_to_proto(progress: Option, i18n: &I18n) -> pb:: } } -fn media_sync_progress(p: MediaSyncProgress, i18n: &I18n) -> pb::progress::MediaSync { +fn media_sync_progress(p: MediaSyncProgress, tr: &I18n) -> pb::progress::MediaSync { pb::progress::MediaSync { - checked: i18n.sync_media_checked_count(p.checked).into(), - added: i18n + checked: tr.sync_media_checked_count(p.checked).into(), + added: tr .sync_media_added_count(p.uploaded_files, p.downloaded_files) .into(), - removed: i18n + removed: tr .sync_media_removed_count(p.uploaded_deletions, p.downloaded_deletions) .into(), } diff --git a/rslib/src/backend/scheduler/mod.rs b/rslib/src/backend/scheduler/mod.rs index f18a32c13..11ab3c0d6 100644 --- a/rslib/src/backend/scheduler/mod.rs +++ b/rslib/src/backend/scheduler/mod.rs @@ -34,7 +34,7 @@ impl SchedulingService for Backend { /// Message rendering only, for old graphs. fn studied_today_message(&self, input: pb::StudiedTodayMessageIn) -> Result { - Ok(studied_today(input.cards, input.seconds as f32, &self.i18n).into()) + Ok(studied_today(input.cards, input.seconds as f32, &self.tr).into()) } fn update_stats(&self, input: pb::UpdateStatsIn) -> Result { diff --git a/rslib/src/backend/sync/mod.rs b/rslib/src/backend/sync/mod.rs index 7d894ee0a..9dd218e68 100644 --- a/rslib/src/backend/sync/mod.rs +++ b/rslib/src/backend/sync/mod.rs @@ -356,7 +356,7 @@ impl Backend { media_folder_path, media_db_path, self.server, - self.i18n.clone(), + self.tr.clone(), logger, )?); diff --git a/rslib/src/browser_rows.rs b/rslib/src/browser_rows.rs index 83d59d09d..5156aaf1b 100644 --- a/rslib/src/browser_rows.rs +++ b/rslib/src/browser_rows.rs @@ -58,7 +58,7 @@ struct RowContext<'a> { notetype: Arc, deck: Option, original_deck: Option>, - i18n: &'a I18n, + tr: &'a I18n, timing: SchedTimingToday, render_context: Option, } @@ -152,7 +152,7 @@ impl<'a> RowContext<'a> { notetype, deck: None, original_deck: None, - i18n: &col.i18n, + tr: &col.tr, timing, render_context, }) @@ -236,9 +236,9 @@ impl<'a> RowContext<'a> { fn card_due_str(&mut self) -> String { let due = if self.card.original_deck_id != DeckID(0) { - self.i18n.browsing_filtered() + self.tr.browsing_filtered() } else if self.card.queue == CardQueue::New || self.card.ctype == CardType::New { - self.i18n.statistics_due_for_new_card(self.card.due) + self.tr.statistics_due_for_new_card(self.card.due) } else { let date = if self.card.queue == CardQueue::Learn { TimestampSecs(self.card.due as i64) @@ -262,16 +262,16 @@ impl<'a> RowContext<'a> { fn card_ease_str(&self) -> String { match self.card.ctype { - CardType::New => self.i18n.browsing_new().into(), + CardType::New => self.tr.browsing_new().into(), _ => format!("{}%", self.card.ease_factor / 10), } } fn card_interval_str(&self) -> String { match self.card.ctype { - CardType::New => self.i18n.browsing_new().into(), - CardType::Learn => self.i18n.browsing_learning().into(), - _ => time_span((self.card.interval * 86400) as f32, self.i18n, false), + CardType::New => self.tr.browsing_new().into(), + CardType::Learn => self.tr.browsing_learning().into(), + _ => time_span((self.card.interval * 86400) as f32, self.tr, false), } } diff --git a/rslib/src/collection.rs b/rslib/src/collection.rs index 9f97595b6..e1d5caee1 100644 --- a/rslib/src/collection.rs +++ b/rslib/src/collection.rs @@ -19,18 +19,18 @@ pub fn open_collection>( media_folder: P, media_db: P, server: bool, - i18n: I18n, + tr: I18n, log: Logger, ) -> Result { let col_path = path.into(); - let storage = SqliteStorage::open_or_create(&col_path, &i18n, server)?; + let storage = SqliteStorage::open_or_create(&col_path, &tr, server)?; let col = Collection { storage, col_path, media_folder: media_folder.into(), media_db: media_db.into(), - i18n, + tr, log, server, state: CollectionState::default(), @@ -55,8 +55,8 @@ pub fn open_test_collection() -> Collection { #[cfg(test)] pub fn open_test_collection_with_server(server: bool) -> Collection { use crate::log; - let i18n = I18n::template_only(); - open_collection(":memory:", "", "", server, i18n, log::terminal()).unwrap() + let tr = I18n::template_only(); + open_collection(":memory:", "", "", server, tr, log::terminal()).unwrap() } #[derive(Debug, Default)] @@ -76,7 +76,7 @@ pub struct Collection { pub(crate) col_path: PathBuf, pub(crate) media_folder: PathBuf, pub(crate) media_db: PathBuf, - pub(crate) i18n: I18n, + pub(crate) tr: I18n, pub(crate) log: Logger, pub(crate) server: bool, pub(crate) state: CollectionState, diff --git a/rslib/src/dbcheck.rs b/rslib/src/dbcheck.rs index a0dabe07e..93f67c68b 100644 --- a/rslib/src/dbcheck.rs +++ b/rslib/src/dbcheck.rs @@ -41,39 +41,39 @@ pub(crate) enum DatabaseCheckProgress { } impl CheckDatabaseOutput { - pub fn to_i18n_strings(&self, i18n: &I18n) -> Vec { + pub fn to_i18n_strings(&self, tr: &I18n) -> Vec { let mut probs = Vec::new(); if self.notetypes_recovered > 0 { - probs.push(i18n.database_check_notetypes_recovered()); + probs.push(tr.database_check_notetypes_recovered()); } if self.card_position_too_high > 0 { - probs.push(i18n.database_check_new_card_high_due(self.card_position_too_high)); + probs.push(tr.database_check_new_card_high_due(self.card_position_too_high)); } if self.card_properties_invalid > 0 { - probs.push(i18n.database_check_card_properties(self.card_properties_invalid)); + probs.push(tr.database_check_card_properties(self.card_properties_invalid)); } if self.cards_missing_note > 0 { - probs.push(i18n.database_check_card_missing_note(self.cards_missing_note)); + probs.push(tr.database_check_card_missing_note(self.cards_missing_note)); } if self.decks_missing > 0 { - probs.push(i18n.database_check_missing_decks(self.decks_missing)); + probs.push(tr.database_check_missing_decks(self.decks_missing)); } if self.field_count_mismatch > 0 { - probs.push(i18n.database_check_field_count(self.field_count_mismatch)); + probs.push(tr.database_check_field_count(self.field_count_mismatch)); } if self.card_ords_duplicated > 0 { - probs.push(i18n.database_check_duplicate_card_ords(self.card_ords_duplicated)); + probs.push(tr.database_check_duplicate_card_ords(self.card_ords_duplicated)); } if self.templates_missing > 0 { - probs.push(i18n.database_check_missing_templates(self.templates_missing)); + probs.push(tr.database_check_missing_templates(self.templates_missing)); } if self.revlog_properties_invalid > 0 { - probs.push(i18n.database_check_revlog_properties(self.revlog_properties_invalid)); + probs.push(tr.database_check_revlog_properties(self.revlog_properties_invalid)); } if self.invalid_utf8 > 0 { - probs.push(i18n.database_check_notes_with_invalid_utf8(self.invalid_utf8)); + probs.push(tr.database_check_notes_with_invalid_utf8(self.invalid_utf8)); } probs.into_iter().map(Into::into).collect() @@ -91,7 +91,7 @@ impl Collection { if self.storage.quick_check_corrupt() { debug!(self.log, "quick check failed"); return Err(AnkiError::DBError { - info: self.i18n.database_check_corrupt().into(), + info: self.tr.database_check_corrupt().into(), kind: DBErrorKind::Corrupt, }); } @@ -266,7 +266,7 @@ impl Collection { // if the collection is empty and the user has deleted all note types, ensure at least // one note type exists if self.storage.get_all_notetype_names()?.is_empty() { - let mut nt = all_stock_notetypes(&self.i18n).remove(0); + let mut nt = all_stock_notetypes(&self.tr).remove(0); self.add_notetype_inner(&mut nt, usn)?; } @@ -349,7 +349,7 @@ impl Collection { let extra_cards_required = self .storage .highest_card_ordinal_for_notetype(previous_id)?; - let mut basic = all_stock_notetypes(&self.i18n).remove(0); + let mut basic = all_stock_notetypes(&self.tr).remove(0); let mut field = 3; while basic.fields.len() < field_count { basic.add_field(format!("{}", field)); diff --git a/rslib/src/decks/mod.rs b/rslib/src/decks/mod.rs index 1b02467dd..a60102ed5 100644 --- a/rslib/src/decks/mod.rs +++ b/rslib/src/decks/mod.rs @@ -512,7 +512,7 @@ impl Collection { if deck.id.0 == 1 { // if deleting the default deck, ensure there's a new one, and avoid the grave let mut deck = deck.to_owned(); - deck.name = self.i18n.deck_config_default_name().into(); + deck.name = self.tr.deck_config_default_name().into(); deck.set_modified(usn); self.add_or_update_single_deck_with_existing_id(&mut deck, usn)?; } else { diff --git a/rslib/src/err.rs b/rslib/src/err.rs index 5ac57723a..8162576a0 100644 --- a/rslib/src/err.rs +++ b/rslib/src/err.rs @@ -90,37 +90,37 @@ impl AnkiError { } } - pub fn localized_description(&self, i18n: &I18n) -> String { + pub fn localized_description(&self, tr: &I18n) -> String { match self { AnkiError::SyncError { info, kind } => match kind { SyncErrorKind::ServerMessage => info.into(), SyncErrorKind::Other => info.into(), - SyncErrorKind::Conflict => i18n.sync_conflict(), - SyncErrorKind::ServerError => i18n.sync_server_error(), - SyncErrorKind::ClientTooOld => i18n.sync_client_too_old(), - SyncErrorKind::AuthFailed => i18n.sync_wrong_pass(), - SyncErrorKind::ResyncRequired => i18n.sync_resync_required(), - SyncErrorKind::ClockIncorrect => i18n.sync_clock_off(), - SyncErrorKind::DatabaseCheckRequired => i18n.sync_sanity_check_failed(), + SyncErrorKind::Conflict => tr.sync_conflict(), + SyncErrorKind::ServerError => tr.sync_server_error(), + SyncErrorKind::ClientTooOld => tr.sync_client_too_old(), + SyncErrorKind::AuthFailed => tr.sync_wrong_pass(), + SyncErrorKind::ResyncRequired => tr.sync_resync_required(), + SyncErrorKind::ClockIncorrect => tr.sync_clock_off(), + SyncErrorKind::DatabaseCheckRequired => tr.sync_sanity_check_failed(), // server message SyncErrorKind::SyncNotStarted => "sync not started".into(), } .into(), AnkiError::NetworkError { kind, info } => { let summary = match kind { - NetworkErrorKind::Offline => i18n.network_offline(), - NetworkErrorKind::Timeout => i18n.network_timeout(), - NetworkErrorKind::ProxyAuth => i18n.network_proxy_auth(), - NetworkErrorKind::Other => i18n.network_other(), + NetworkErrorKind::Offline => tr.network_offline(), + NetworkErrorKind::Timeout => tr.network_timeout(), + NetworkErrorKind::ProxyAuth => tr.network_proxy_auth(), + NetworkErrorKind::Other => tr.network_other(), }; - let details = i18n.network_details(info.as_str()); + let details = tr.network_details(info.as_str()); format!("{}\n\n{}", summary, details) } AnkiError::TemplateError { info } => { // already localized info.into() } - AnkiError::TemplateSaveError { ordinal } => i18n + AnkiError::TemplateSaveError { ordinal } => tr .card_templates_invalid_template_number(ordinal + 1) .into(), AnkiError::DBError { info, kind } => match kind { @@ -130,75 +130,75 @@ impl AnkiError { }, AnkiError::SearchError(kind) => { let reason = match kind { - SearchErrorKind::MisplacedAnd => i18n.search_misplaced_and(), - SearchErrorKind::MisplacedOr => i18n.search_misplaced_or(), - SearchErrorKind::EmptyGroup => i18n.search_empty_group(), - SearchErrorKind::UnopenedGroup => i18n.search_unopened_group(), - SearchErrorKind::UnclosedGroup => i18n.search_unclosed_group(), - SearchErrorKind::EmptyQuote => i18n.search_empty_quote(), - SearchErrorKind::UnclosedQuote => i18n.search_unclosed_quote(), - SearchErrorKind::MissingKey => i18n.search_missing_key(), + SearchErrorKind::MisplacedAnd => tr.search_misplaced_and(), + SearchErrorKind::MisplacedOr => tr.search_misplaced_or(), + SearchErrorKind::EmptyGroup => tr.search_empty_group(), + SearchErrorKind::UnopenedGroup => tr.search_unopened_group(), + SearchErrorKind::UnclosedGroup => tr.search_unclosed_group(), + SearchErrorKind::EmptyQuote => tr.search_empty_quote(), + SearchErrorKind::UnclosedQuote => tr.search_unclosed_quote(), + SearchErrorKind::MissingKey => tr.search_missing_key(), SearchErrorKind::UnknownEscape(ctx) => { - i18n.search_unknown_escape(ctx.replace('`', "'")) + tr.search_unknown_escape(ctx.replace('`', "'")) } SearchErrorKind::InvalidState(state) => { - i18n.search_invalid_argument("is:", state.replace('`', "'")) + tr.search_invalid_argument("is:", state.replace('`', "'")) } - SearchErrorKind::InvalidFlag => i18n.search_invalid_flag(), + SearchErrorKind::InvalidFlag => tr.search_invalid_flag(), SearchErrorKind::InvalidPropProperty(prop) => { - i18n.search_invalid_argument("prop:", prop.replace('`', "'")) + tr.search_invalid_argument("prop:", prop.replace('`', "'")) } SearchErrorKind::InvalidPropOperator(ctx) => { - i18n.search_invalid_prop_operator(ctx.as_str()) + tr.search_invalid_prop_operator(ctx.as_str()) } SearchErrorKind::Regex(text) => { format!("
`{}`
", text.replace('`', "'")).into() } SearchErrorKind::Other(Some(info)) => info.into(), - SearchErrorKind::Other(None) => i18n.search_invalid_other(), - SearchErrorKind::InvalidNumber { provided, context } => i18n + SearchErrorKind::Other(None) => tr.search_invalid_other(), + SearchErrorKind::InvalidNumber { provided, context } => tr .search_invalid_number( context.replace('`', "'"), provided.replace('`', "'"), ), - SearchErrorKind::InvalidWholeNumber { provided, context } => i18n + SearchErrorKind::InvalidWholeNumber { provided, context } => tr .search_invalid_whole_number( context.replace('`', "'"), provided.replace('`', "'"), ), - SearchErrorKind::InvalidPositiveWholeNumber { provided, context } => i18n + SearchErrorKind::InvalidPositiveWholeNumber { provided, context } => tr .search_invalid_positive_whole_number( context.replace('`', "'"), provided.replace('`', "'"), ), - SearchErrorKind::InvalidNegativeWholeNumber { provided, context } => i18n + SearchErrorKind::InvalidNegativeWholeNumber { provided, context } => tr .search_invalid_negative_whole_number( context.replace('`', "'"), provided.replace('`', "'"), ), - SearchErrorKind::InvalidAnswerButton { provided, context } => i18n + SearchErrorKind::InvalidAnswerButton { provided, context } => tr .search_invalid_answer_button( context.replace('`', "'"), provided.replace('`', "'"), ), }; - i18n.search_invalid_search(reason).into() + tr.search_invalid_search(reason).into() } AnkiError::InvalidInput { info } => { if info.is_empty() { - i18n.errors_invalid_input_empty().into() + tr.errors_invalid_input_empty().into() } else { - i18n.errors_invalid_input_details(info.as_str()).into() + tr.errors_invalid_input_details(info.as_str()).into() } } - AnkiError::ParseNumError => i18n.errors_parse_number_fail().into(), - AnkiError::DeckIsFiltered => i18n.errors_filtered_parent_deck().into(), - AnkiError::FilteredDeckEmpty => i18n.decks_filtered_deck_search_empty().into(), + AnkiError::ParseNumError => tr.errors_parse_number_fail().into(), + AnkiError::DeckIsFiltered => tr.errors_filtered_parent_deck().into(), + AnkiError::FilteredDeckEmpty => tr.decks_filtered_deck_search_empty().into(), _ => format!("{:?}", self), } } diff --git a/rslib/src/media/check.rs b/rslib/src/media/check.rs index 64a8dd9b2..0cb32e5ee 100644 --- a/rslib/src/media/check.rs +++ b/rslib/src/media/check.rs @@ -89,7 +89,7 @@ where pub fn summarize_output(&self, output: &mut MediaCheckOutput) -> String { let mut buf = String::new(); - let i = &self.ctx.i18n; + let i = &self.ctx.tr; // top summary area if output.trash_count > 0 { @@ -532,9 +532,9 @@ pub(crate) mod test { let mgr = MediaManager::new(&media_dir, media_db.clone())?; let log = log::terminal(); - let i18n = I18n::template_only(); + let tr = I18n::template_only(); - let col = open_collection(col_path, media_dir, media_db, false, i18n, log)?; + let col = open_collection(col_path, media_dir, media_db, false, tr, log)?; Ok((dir, mgr, col)) } diff --git a/rslib/src/notetype/emptycards.rs b/rslib/src/notetype/emptycards.rs index d7e9918cb..0d2c55a37 100644 --- a/rslib/src/notetype/emptycards.rs +++ b/rslib/src/notetype/emptycards.rs @@ -73,7 +73,7 @@ impl Collection { write!( buf, "
{}
    ", - self.i18n.empty_cards_for_note_type(nt.name.clone()) + self.tr.empty_cards_for_note_type(nt.name.clone()) ) .unwrap(); @@ -95,7 +95,7 @@ impl Collection { // "Cloze 1, 3" NoteTypeKind::Cloze => format!( "{} {}", - self.i18n.notetypes_cloze_name(), + self.tr.notetypes_cloze_name(), note.empty .iter() .map(|(ord, _)| (ord + 1).to_string()) @@ -113,7 +113,7 @@ impl Collection { "
  1. [anki:nid:{}] {}
  2. ", class, note.nid, - self.i18n.empty_cards_count_line( + self.tr.empty_cards_count_line( note.empty.len(), note.current_count, templates diff --git a/rslib/src/notetype/mod.rs b/rslib/src/notetype/mod.rs index 526ae7849..7c9498b2d 100644 --- a/rslib/src/notetype/mod.rs +++ b/rslib/src/notetype/mod.rs @@ -491,7 +491,7 @@ impl Collection { col.storage.remove_notetype(ntid)?; let all = col.storage.get_all_notetype_names()?; if all.is_empty() { - let mut nt = all_stock_notetypes(&col.i18n).remove(0); + let mut nt = all_stock_notetypes(&col.tr).remove(0); col.add_notetype_inner(&mut nt, col.usn()?)?; col.set_current_notetype_id(nt.id) } else { diff --git a/rslib/src/notetype/render.rs b/rslib/src/notetype/render.rs index 0ef9c2247..f0e7334c1 100644 --- a/rslib/src/notetype/render.rs +++ b/rslib/src/notetype/render.rs @@ -56,7 +56,7 @@ impl Collection { .ok_or_else(|| AnkiError::invalid_input("no such notetype"))?; if fill_empty { - fill_empty_fields(note, &template.config.q_format, &nt, &self.i18n); + fill_empty_fields(note, &template.config.q_format, &nt, &self.tr); } self.render_card(note, &card, &nt, template, false) @@ -116,7 +116,7 @@ impl Collection { &field_map, card.template_idx, nt.is_cloze(), - &self.i18n, + &self.tr, )?; Ok(RenderCardOutput { qnodes, anodes }) } @@ -165,14 +165,14 @@ fn flag_name(n: u8) -> &'static str { } } -fn fill_empty_fields(note: &mut Note, qfmt: &str, nt: &NoteType, i18n: &I18n) { +fn fill_empty_fields(note: &mut Note, qfmt: &str, nt: &NoteType, tr: &I18n) { if let Ok(tmpl) = ParsedTemplate::from_text(qfmt) { let cloze_fields = tmpl.cloze_fields(); for (val, field) in note.fields_mut().iter_mut().zip(nt.fields.iter()) { if field_is_empty(val) { if cloze_fields.contains(&field.name.as_str()) { - *val = i18n.card_templates_sample_cloze().into(); + *val = tr.card_templates_sample_cloze().into(); } else { *val = format!("({})", field.name); } diff --git a/rslib/src/notetype/stock.rs b/rslib/src/notetype/stock.rs index 3860cd8a0..79f7262f4 100644 --- a/rslib/src/notetype/stock.rs +++ b/rslib/src/notetype/stock.rs @@ -14,8 +14,8 @@ use crate::{ use crate::backend_proto::stock_note_type::Kind; impl SqliteStorage { - pub(crate) fn add_stock_notetypes(&self, i18n: &I18n) -> Result<()> { - for (idx, mut nt) in all_stock_notetypes(i18n).into_iter().enumerate() { + pub(crate) fn add_stock_notetypes(&self, tr: &I18n) -> Result<()> { + for (idx, mut nt) in all_stock_notetypes(tr).into_iter().enumerate() { self.add_new_notetype(&mut nt)?; if idx == Kind::Basic as usize { self.set_config_entry(&ConfigEntry::boxed( @@ -31,13 +31,13 @@ impl SqliteStorage { } // if changing this, make sure to update StockNoteType enum -pub fn all_stock_notetypes(i18n: &I18n) -> Vec { +pub fn all_stock_notetypes(tr: &I18n) -> Vec { vec![ - basic(i18n), - basic_forward_reverse(i18n), - basic_optional_reverse(i18n), - basic_typing(i18n), - cloze(i18n), + basic(tr), + basic_forward_reverse(tr), + basic_optional_reverse(tr), + basic_typing(tr), + cloze(tr), ] } @@ -46,17 +46,17 @@ fn fieldref>(name: S) -> String { format!("{{{{{}}}}}", name.as_ref()) } -pub(crate) fn basic(i18n: &I18n) -> NoteType { +pub(crate) fn basic(tr: &I18n) -> NoteType { let mut nt = NoteType { - name: i18n.notetypes_basic_name().into(), + name: tr.notetypes_basic_name().into(), ..Default::default() }; - let front = i18n.notetypes_front_field(); - let back = i18n.notetypes_back_field(); + let front = tr.notetypes_front_field(); + let back = tr.notetypes_back_field(); nt.add_field(front.as_ref()); nt.add_field(back.as_ref()); nt.add_template( - i18n.notetypes_card_1_name(), + tr.notetypes_card_1_name(), fieldref(front), format!( "{}\n\n
    \n\n{}", @@ -68,11 +68,11 @@ pub(crate) fn basic(i18n: &I18n) -> NoteType { nt } -pub(crate) fn basic_typing(i18n: &I18n) -> NoteType { - let mut nt = basic(i18n); - nt.name = i18n.notetypes_basic_type_answer_name().into(); - let front = i18n.notetypes_front_field(); - let back = i18n.notetypes_back_field(); +pub(crate) fn basic_typing(tr: &I18n) -> NoteType { + let mut nt = basic(tr); + nt.name = tr.notetypes_basic_type_answer_name().into(); + let front = tr.notetypes_front_field(); + let back = tr.notetypes_back_field(); let tmpl = &mut nt.templates[0].config; tmpl.q_format = format!("{}\n\n{{{{type:{}}}}}", fieldref(front.as_ref()), back); tmpl.a_format = format!( @@ -84,13 +84,13 @@ pub(crate) fn basic_typing(i18n: &I18n) -> NoteType { nt } -pub(crate) fn basic_forward_reverse(i18n: &I18n) -> NoteType { - let mut nt = basic(i18n); - nt.name = i18n.notetypes_basic_reversed_name().into(); - let front = i18n.notetypes_front_field(); - let back = i18n.notetypes_back_field(); +pub(crate) fn basic_forward_reverse(tr: &I18n) -> NoteType { + let mut nt = basic(tr); + nt.name = tr.notetypes_basic_reversed_name().into(); + let front = tr.notetypes_front_field(); + let back = tr.notetypes_back_field(); nt.add_template( - i18n.notetypes_card_2_name(), + tr.notetypes_card_2_name(), fieldref(back), format!( "{}\n\n
    \n\n{}", @@ -102,10 +102,10 @@ pub(crate) fn basic_forward_reverse(i18n: &I18n) -> NoteType { nt } -pub(crate) fn basic_optional_reverse(i18n: &I18n) -> NoteType { - let mut nt = basic_forward_reverse(i18n); - nt.name = i18n.notetypes_basic_optional_reversed_name().into(); - let addrev = i18n.notetypes_add_reverse_field(); +pub(crate) fn basic_optional_reverse(tr: &I18n) -> NoteType { + let mut nt = basic_forward_reverse(tr); + nt.name = tr.notetypes_basic_optional_reversed_name().into(); + let addrev = tr.notetypes_add_reverse_field(); nt.add_field(addrev.as_ref()); let tmpl = &mut nt.templates[1].config; tmpl.q_format = format!("{{{{#{}}}}}{}{{{{/{}}}}}", addrev, tmpl.q_format, addrev); @@ -113,14 +113,14 @@ pub(crate) fn basic_optional_reverse(i18n: &I18n) -> NoteType { nt } -pub(crate) fn cloze(i18n: &I18n) -> NoteType { +pub(crate) fn cloze(tr: &I18n) -> NoteType { let mut nt = NoteType { - name: i18n.notetypes_cloze_name().into(), + name: tr.notetypes_cloze_name().into(), ..Default::default() }; - let text = i18n.notetypes_text_field(); + let text = tr.notetypes_text_field(); nt.add_field(text.as_ref()); - let back_extra = i18n.notetypes_back_extra_field(); + let back_extra = tr.notetypes_back_extra_field(); nt.add_field(back_extra.as_ref()); let qfmt = format!("{{{{cloze:{}}}}}", text); let afmt = format!("{}
    \n{{{{{}}}}}", qfmt, back_extra); diff --git a/rslib/src/ops.rs b/rslib/src/ops.rs index 45a403b85..0d0b2c386 100644 --- a/rslib/src/ops.rs +++ b/rslib/src/ops.rs @@ -36,36 +36,36 @@ pub enum Op { } impl Op { - pub fn describe(self, i18n: &I18n) -> String { + pub fn describe(self, tr: &I18n) -> String { match self { - Op::AddDeck => i18n.undo_add_deck(), - Op::AddNote => i18n.undo_add_note(), - Op::AnswerCard => i18n.undo_answer_card(), - Op::Bury => i18n.studying_bury(), - Op::RemoveDeck => i18n.decks_delete_deck(), - Op::RemoveNote => i18n.studying_delete_note(), - Op::RenameDeck => i18n.actions_rename_deck(), - Op::ScheduleAsNew => i18n.undo_forget_card(), - Op::SetDueDate => i18n.actions_set_due_date(), - Op::Suspend => i18n.studying_suspend(), - Op::UnburyUnsuspend => i18n.undo_unbury_unsuspend(), - Op::UpdateCard => i18n.undo_update_card(), - Op::UpdateDeck => i18n.undo_update_deck(), - Op::UpdateNote => i18n.undo_update_note(), - Op::UpdatePreferences => i18n.preferences_preferences(), - Op::UpdateTag => i18n.undo_update_tag(), - Op::SetDeck => i18n.browsing_change_deck(), - Op::SetFlag => i18n.undo_set_flag(), - Op::FindAndReplace => i18n.browsing_find_and_replace(), - Op::ClearUnusedTags => i18n.browsing_clear_unused_tags(), - Op::SortCards => i18n.browsing_reschedule(), - Op::RenameTag => i18n.actions_rename_tag(), - Op::RemoveTag => i18n.actions_remove_tag(), - Op::ReparentTag => i18n.actions_rename_tag(), - Op::ReparentDeck => i18n.actions_rename_deck(), - Op::BuildFilteredDeck => i18n.undo_build_filtered_deck(), - Op::RebuildFilteredDeck => i18n.undo_build_filtered_deck(), - Op::EmptyFilteredDeck => i18n.studying_empty(), + Op::AddDeck => tr.undo_add_deck(), + Op::AddNote => tr.undo_add_note(), + Op::AnswerCard => tr.undo_answer_card(), + Op::Bury => tr.studying_bury(), + Op::RemoveDeck => tr.decks_delete_deck(), + Op::RemoveNote => tr.studying_delete_note(), + Op::RenameDeck => tr.actions_rename_deck(), + Op::ScheduleAsNew => tr.undo_forget_card(), + Op::SetDueDate => tr.actions_set_due_date(), + Op::Suspend => tr.studying_suspend(), + Op::UnburyUnsuspend => tr.undo_unbury_unsuspend(), + Op::UpdateCard => tr.undo_update_card(), + Op::UpdateDeck => tr.undo_update_deck(), + Op::UpdateNote => tr.undo_update_note(), + Op::UpdatePreferences => tr.preferences_preferences(), + Op::UpdateTag => tr.undo_update_tag(), + Op::SetDeck => tr.browsing_change_deck(), + Op::SetFlag => tr.undo_set_flag(), + Op::FindAndReplace => tr.browsing_find_and_replace(), + Op::ClearUnusedTags => tr.browsing_clear_unused_tags(), + Op::SortCards => tr.browsing_reschedule(), + Op::RenameTag => tr.actions_rename_tag(), + Op::RemoveTag => tr.actions_remove_tag(), + Op::ReparentTag => tr.actions_rename_tag(), + Op::ReparentDeck => tr.actions_rename_deck(), + Op::BuildFilteredDeck => tr.undo_build_filtered_deck(), + Op::RebuildFilteredDeck => tr.undo_build_filtered_deck(), + Op::EmptyFilteredDeck => tr.studying_empty(), } .into() } diff --git a/rslib/src/scheduler/answering/mod.rs b/rslib/src/scheduler/answering/mod.rs index 25f30be35..e66460db0 100644 --- a/rslib/src/scheduler/answering/mod.rs +++ b/rslib/src/scheduler/answering/mod.rs @@ -207,7 +207,7 @@ impl Collection { .maybe_as_days(secs_until_rollover) .as_seconds(), collapse_time, - &self.i18n, + &self.tr, ), answer_button_time_collapsible( choices @@ -216,7 +216,7 @@ impl Collection { .maybe_as_days(secs_until_rollover) .as_seconds(), collapse_time, - &self.i18n, + &self.tr, ), answer_button_time_collapsible( choices @@ -225,7 +225,7 @@ impl Collection { .maybe_as_days(secs_until_rollover) .as_seconds(), collapse_time, - &self.i18n, + &self.tr, ), answer_button_time_collapsible( choices @@ -234,7 +234,7 @@ impl Collection { .maybe_as_days(secs_until_rollover) .as_seconds(), collapse_time, - &self.i18n, + &self.tr, ), ]) } diff --git a/rslib/src/scheduler/timespan.rs b/rslib/src/scheduler/timespan.rs index 3d1f33fac..1088fcc87 100644 --- a/rslib/src/scheduler/timespan.rs +++ b/rslib/src/scheduler/timespan.rs @@ -4,26 +4,26 @@ use crate::i18n::I18n; /// Short string like '4d' to place above answer buttons. -pub fn answer_button_time(seconds: f32, i18n: &I18n) -> String { +pub fn answer_button_time(seconds: f32, tr: &I18n) -> String { let span = Timespan::from_secs(seconds).natural_span(); let amount = span.as_rounded_unit_for_answer_buttons(); match span.unit() { - TimespanUnit::Seconds => i18n.scheduling_answer_button_time_seconds(amount), - TimespanUnit::Minutes => i18n.scheduling_answer_button_time_minutes(amount), - TimespanUnit::Hours => i18n.scheduling_answer_button_time_hours(amount), - TimespanUnit::Days => i18n.scheduling_answer_button_time_days(amount), - TimespanUnit::Months => i18n.scheduling_answer_button_time_months(amount), - TimespanUnit::Years => i18n.scheduling_answer_button_time_years(amount), + TimespanUnit::Seconds => tr.scheduling_answer_button_time_seconds(amount), + TimespanUnit::Minutes => tr.scheduling_answer_button_time_minutes(amount), + TimespanUnit::Hours => tr.scheduling_answer_button_time_hours(amount), + TimespanUnit::Days => tr.scheduling_answer_button_time_days(amount), + TimespanUnit::Months => tr.scheduling_answer_button_time_months(amount), + TimespanUnit::Years => tr.scheduling_answer_button_time_years(amount), } .into() } /// Short string like '4d' to place above answer buttons. /// Times within the collapse time are represented like '<10m' -pub fn answer_button_time_collapsible(seconds: u32, collapse_secs: u32, i18n: &I18n) -> String { - let string = answer_button_time(seconds as f32, i18n); +pub fn answer_button_time_collapsible(seconds: u32, collapse_secs: u32, tr: &I18n) -> String { + let string = answer_button_time(seconds as f32, tr); if seconds == 0 { - i18n.scheduling_end().into() + tr.scheduling_end().into() } else if seconds < collapse_secs { format!("<{}", string) } else { @@ -35,7 +35,7 @@ pub fn answer_button_time_collapsible(seconds: u32, collapse_secs: u32, i18n: &I /// If precise is true, show to two decimal places, eg /// eg 70 seconds -> "1.17 minutes" /// If false, seconds and days are shown without decimals. -pub fn time_span(seconds: f32, i18n: &I18n, precise: bool) -> String { +pub fn time_span(seconds: f32, tr: &I18n, precise: bool) -> String { let span = Timespan::from_secs(seconds).natural_span(); let amount = if precise { span.as_unit() @@ -43,12 +43,12 @@ pub fn time_span(seconds: f32, i18n: &I18n, precise: bool) -> String { span.as_rounded_unit() }; match span.unit() { - TimespanUnit::Seconds => i18n.scheduling_time_span_seconds(amount), - TimespanUnit::Minutes => i18n.scheduling_time_span_minutes(amount), - TimespanUnit::Hours => i18n.scheduling_time_span_hours(amount), - TimespanUnit::Days => i18n.scheduling_time_span_days(amount), - TimespanUnit::Months => i18n.scheduling_time_span_months(amount), - TimespanUnit::Years => i18n.scheduling_time_span_years(amount), + TimespanUnit::Seconds => tr.scheduling_time_span_seconds(amount), + TimespanUnit::Minutes => tr.scheduling_time_span_minutes(amount), + TimespanUnit::Hours => tr.scheduling_time_span_hours(amount), + TimespanUnit::Days => tr.scheduling_time_span_days(amount), + TimespanUnit::Months => tr.scheduling_time_span_months(amount), + TimespanUnit::Years => tr.scheduling_time_span_years(amount), } .into() } @@ -171,20 +171,20 @@ mod test { #[test] fn answer_buttons() { - let i18n = I18n::template_only(); - assert_eq!(answer_button_time(30.0, &i18n), "30s"); - assert_eq!(answer_button_time(70.0, &i18n), "1m"); - assert_eq!(answer_button_time(1.1 * MONTH, &i18n), "1.1mo"); + let tr = I18n::template_only(); + assert_eq!(answer_button_time(30.0, &tr), "30s"); + assert_eq!(answer_button_time(70.0, &tr), "1m"); + assert_eq!(answer_button_time(1.1 * MONTH, &tr), "1.1mo"); } #[test] fn time_spans() { - let i18n = I18n::template_only(); - assert_eq!(time_span(1.0, &i18n, false), "1 second"); - assert_eq!(time_span(30.3, &i18n, false), "30 seconds"); - assert_eq!(time_span(30.3, &i18n, true), "30.3 seconds"); - assert_eq!(time_span(90.0, &i18n, false), "1.5 minutes"); - assert_eq!(time_span(45.0 * 86_400.0, &i18n, false), "1.5 months"); - assert_eq!(time_span(365.0 * 86_400.0 * 1.5, &i18n, false), "1.5 years"); + let tr = I18n::template_only(); + assert_eq!(time_span(1.0, &tr, false), "1 second"); + assert_eq!(time_span(30.3, &tr, false), "30 seconds"); + assert_eq!(time_span(30.3, &tr, true), "30.3 seconds"); + assert_eq!(time_span(90.0, &tr, false), "1.5 minutes"); + assert_eq!(time_span(45.0 * 86_400.0, &tr, false), "1.5 months"); + assert_eq!(time_span(365.0 * 86_400.0 * 1.5, &tr, false), "1.5 years"); } } diff --git a/rslib/src/search/sqlwriter.rs b/rslib/src/search/sqlwriter.rs index 8ce5450bd..5699753f2 100644 --- a/rslib/src/search/sqlwriter.rs +++ b/rslib/src/search/sqlwriter.rs @@ -610,13 +610,13 @@ mod test { let col_path = dir.path().join("col.anki2"); fs::write(&col_path, MEDIACHECK_ANKI2).unwrap(); - let i18n = I18n::template_only(); + let tr = I18n::template_only(); let mut col = open_collection( &col_path, &PathBuf::new(), &PathBuf::new(), false, - i18n, + tr, log::terminal(), ) .unwrap(); diff --git a/rslib/src/stats/card.rs b/rslib/src/stats/card.rs index a31c5ba4f..b7c85bd52 100644 --- a/rslib/src/stats/card.rs +++ b/rslib/src/stats/card.rs @@ -127,74 +127,71 @@ impl Collection { } fn card_stats_to_string(&mut self, cs: CardStats) -> Result { - let i18n = &self.i18n; + let tr = &self.tr; - let mut stats = vec![(i18n.card_stats_added().into(), cs.added.date_string())]; + let mut stats = vec![(tr.card_stats_added().into(), cs.added.date_string())]; if let Some(first) = cs.first_review { - stats.push((i18n.card_stats_first_review().into(), first.date_string())) + stats.push((tr.card_stats_first_review().into(), first.date_string())) } if let Some(last) = cs.latest_review { - stats.push((i18n.card_stats_latest_review().into(), last.date_string())) + stats.push((tr.card_stats_latest_review().into(), last.date_string())) } match cs.due { Due::Time(secs) => { - stats.push((i18n.statistics_due_date().into(), secs.date_string())); + stats.push((tr.statistics_due_date().into(), secs.date_string())); } Due::Position(pos) => { - stats.push((i18n.card_stats_new_card_position().into(), pos.to_string())); + stats.push((tr.card_stats_new_card_position().into(), pos.to_string())); } Due::Unknown => {} }; if cs.interval_secs > 0 { stats.push(( - i18n.card_stats_interval().into(), - time_span(cs.interval_secs as f32, i18n, true), + tr.card_stats_interval().into(), + time_span(cs.interval_secs as f32, tr, true), )); } if cs.ease > 0 { - stats.push((i18n.card_stats_ease().into(), format!("{}%", cs.ease))); + stats.push((tr.card_stats_ease().into(), format!("{}%", cs.ease))); } - stats.push(( - i18n.card_stats_review_count().into(), - cs.reviews.to_string(), - )); - stats.push((i18n.card_stats_lapse_count().into(), cs.lapses.to_string())); + stats.push((tr.card_stats_review_count().into(), cs.reviews.to_string())); + stats.push((tr.card_stats_lapse_count().into(), cs.lapses.to_string())); if cs.total_secs > 0.0 { stats.push(( - i18n.card_stats_average_time().into(), - time_span(cs.average_secs, i18n, true), + tr.card_stats_average_time().into(), + time_span(cs.average_secs, tr, true), )); stats.push(( - i18n.card_stats_total_time().into(), - time_span(cs.total_secs, i18n, true), + tr.card_stats_total_time().into(), + time_span(cs.total_secs, tr, true), )); } - stats.push((i18n.card_stats_card_template().into(), cs.card_type)); - stats.push((i18n.card_stats_note_type().into(), cs.note_type)); - stats.push((i18n.card_stats_deck_name().into(), cs.deck)); - stats.push((i18n.card_stats_card_id().into(), cs.cid.0.to_string())); - stats.push((i18n.card_stats_note_id().into(), cs.nid.0.to_string())); + stats.push((tr.card_stats_card_template().into(), cs.card_type)); + stats.push((tr.card_stats_note_type().into(), cs.note_type)); + stats.push((tr.card_stats_deck_name().into(), cs.deck)); + stats.push((tr.card_stats_card_id().into(), cs.cid.0.to_string())); + stats.push((tr.card_stats_note_id().into(), cs.nid.0.to_string())); let revlog = cs .revlog .into_iter() .rev() - .map(|e| revlog_to_text(e, i18n)) + .map(|e| revlog_to_text(e, tr)) .collect(); let revlog_titles = RevlogText { - time: i18n.card_stats_review_log_date().into(), - kind: i18n.card_stats_review_log_type().into(), + time: tr.card_stats_review_log_date().into(), + kind: tr.card_stats_review_log_type().into(), kind_class: "".to_string(), - rating: i18n.card_stats_review_log_rating().into(), - interval: i18n.card_stats_interval().into(), - ease: i18n.card_stats_ease().into(), + rating: tr.card_stats_review_log_rating().into(), + interval: tr.card_stats_interval().into(), + ease: tr.card_stats_ease().into(), rating_class: "".to_string(), - taken_secs: i18n.card_stats_review_log_time_taken().into(), + taken_secs: tr.card_stats_review_log_time_taken().into(), }; Ok(CardStatsTemplate { @@ -207,15 +204,15 @@ impl Collection { } } -fn revlog_to_text(e: RevlogEntry, i18n: &I18n) -> RevlogText { +fn revlog_to_text(e: RevlogEntry, tr: &I18n) -> RevlogText { let dt = Local.timestamp(e.id.as_secs().0, 0); let time = dt.format("%Y-%m-%d @ %H:%M").to_string(); let kind = match e.review_kind { - RevlogReviewKind::Learning => i18n.card_stats_review_log_type_learn().into(), - RevlogReviewKind::Review => i18n.card_stats_review_log_type_review().into(), - RevlogReviewKind::Relearning => i18n.card_stats_review_log_type_relearn().into(), - RevlogReviewKind::EarlyReview => i18n.card_stats_review_log_type_filtered().into(), - RevlogReviewKind::Manual => i18n.card_stats_review_log_type_manual().into(), + RevlogReviewKind::Learning => tr.card_stats_review_log_type_learn().into(), + RevlogReviewKind::Review => tr.card_stats_review_log_type_review().into(), + RevlogReviewKind::Relearning => tr.card_stats_review_log_type_relearn().into(), + RevlogReviewKind::EarlyReview => tr.card_stats_review_log_type_filtered().into(), + RevlogReviewKind::Manual => tr.card_stats_review_log_type_manual().into(), }; let kind_class = match e.review_kind { RevlogReviewKind::Learning => String::from("revlog-learn"), @@ -229,7 +226,7 @@ fn revlog_to_text(e: RevlogEntry, i18n: &I18n) -> RevlogText { String::from("") } else { let interval_secs = e.interval_secs(); - time_span(interval_secs as f32, i18n, true) + time_span(interval_secs as f32, tr, true) }; let ease = if e.ease_factor > 0 { format!("{}%", e.ease_factor / 10) @@ -241,7 +238,7 @@ fn revlog_to_text(e: RevlogEntry, i18n: &I18n) -> RevlogText { } else { "".to_string() }; - let taken_secs = i18n + let taken_secs = tr .statistics_seconds_taken((e.taken_millis / 1000) as i32) .into(); diff --git a/rslib/src/stats/today.rs b/rslib/src/stats/today.rs index 8c90d6561..594b68bf9 100644 --- a/rslib/src/stats/today.rs +++ b/rslib/src/stats/today.rs @@ -3,7 +3,7 @@ use crate::{i18n::I18n, prelude::*, scheduler::timespan::Timespan}; -pub fn studied_today(cards: u32, secs: f32, i18n: &I18n) -> String { +pub fn studied_today(cards: u32, secs: f32, tr: &I18n) -> String { let span = Timespan::from_secs(secs).natural_span(); let amount = span.as_unit(); let unit = span.unit().as_str(); @@ -12,7 +12,7 @@ pub fn studied_today(cards: u32, secs: f32, i18n: &I18n) -> String { } else { 0.0 }; - i18n.statistics_studied_today(unit, secs_per_card, amount, cards) + tr.statistics_studied_today(unit, secs_per_card, amount, cards) .into() } @@ -20,7 +20,7 @@ impl Collection { pub fn studied_today(&mut self) -> Result { let timing = self.timing_today()?; let today = self.storage.studied_today(timing.next_day_at)?; - Ok(studied_today(today.cards, today.seconds as f32, &self.i18n)) + Ok(studied_today(today.cards, today.seconds as f32, &self.tr)) } } @@ -32,9 +32,9 @@ mod test { #[test] fn today() { // temporary test of fluent term handling - let i18n = I18n::template_only(); + let tr = I18n::template_only(); assert_eq!( - &studied_today(3, 13.0, &i18n).replace("\n", " "), + &studied_today(3, 13.0, &tr).replace("\n", " "), "Studied 3 cards in 13 seconds today (4.33s/card)" ); } diff --git a/rslib/src/storage/card/mod.rs b/rslib/src/storage/card/mod.rs index 5dae4f7a0..46e65904b 100644 --- a/rslib/src/storage/card/mod.rs +++ b/rslib/src/storage/card/mod.rs @@ -507,8 +507,8 @@ mod test { #[test] fn add_card() { - let i18n = I18n::template_only(); - let storage = SqliteStorage::open_or_create(Path::new(":memory:"), &i18n, false).unwrap(); + let tr = I18n::template_only(); + let storage = SqliteStorage::open_or_create(Path::new(":memory:"), &tr, false).unwrap(); let mut card = Card::default(); storage.add_card(&mut card).unwrap(); let id1 = card.id; diff --git a/rslib/src/storage/deck/mod.rs b/rslib/src/storage/deck/mod.rs index 171e29a78..b26a0ccd0 100644 --- a/rslib/src/storage/deck/mod.rs +++ b/rslib/src/storage/deck/mod.rs @@ -335,11 +335,11 @@ impl SqliteStorage { // Upgrading/downgrading/legacy - pub(super) fn add_default_deck(&self, i18n: &I18n) -> Result<()> { + pub(super) fn add_default_deck(&self, tr: &I18n) -> Result<()> { let mut deck = Deck::new_normal(); deck.id.0 = 1; // fixme: separate key - deck.name = i18n.deck_config_default_name().into(); + deck.name = tr.deck_config_default_name().into(); self.add_or_update_deck_with_existing_id(&deck) } diff --git a/rslib/src/storage/deckconf/mod.rs b/rslib/src/storage/deckconf/mod.rs index e2ba266f8..9a405fc31 100644 --- a/rslib/src/storage/deckconf/mod.rs +++ b/rslib/src/storage/deckconf/mod.rs @@ -113,10 +113,10 @@ impl SqliteStorage { // Creating/upgrading/downgrading - pub(super) fn add_default_deck_config(&self, i18n: &I18n) -> Result<()> { + pub(super) fn add_default_deck_config(&self, tr: &I18n) -> Result<()> { let mut conf = DeckConf::default(); conf.id.0 = 1; - conf.name = i18n.deck_config_default_name().into(); + conf.name = tr.deck_config_default_name().into(); self.add_deck_conf(&mut conf) } diff --git a/rslib/src/storage/sqlite.rs b/rslib/src/storage/sqlite.rs index 9d4d20c7e..a348b6a4a 100644 --- a/rslib/src/storage/sqlite.rs +++ b/rslib/src/storage/sqlite.rs @@ -136,7 +136,7 @@ fn trace(s: &str) { } impl SqliteStorage { - pub(crate) fn open_or_create(path: &Path, i18n: &I18n, server: bool) -> Result { + pub(crate) fn open_or_create(path: &Path, tr: &I18n, server: bool) -> Result { let db = open_or_create_collection_db(path)?; let (create, ver) = schema_version(&db)?; @@ -184,9 +184,9 @@ impl SqliteStorage { } if create { - storage.add_default_deck_config(i18n)?; - storage.add_default_deck(i18n)?; - storage.add_stock_notetypes(i18n)?; + storage.add_default_deck_config(tr)?; + storage.add_default_deck(tr)?; + storage.add_stock_notetypes(tr)?; } if create || upgrade { diff --git a/rslib/src/sync/mod.rs b/rslib/src/sync/mod.rs index 224c1893a..24b3aea80 100644 --- a/rslib/src/sync/mod.rs +++ b/rslib/src/sync/mod.rs @@ -1235,8 +1235,8 @@ mod test { fn open_col(dir: &Path, server: bool, fname: &str) -> Result { let path = dir.join(fname); - let i18n = I18n::template_only(); - open_collection(path, "".into(), "".into(), server, i18n, log::terminal()) + let tr = I18n::template_only(); + open_collection(path, "".into(), "".into(), server, tr, log::terminal()) } #[async_trait(?Send)] @@ -1390,7 +1390,7 @@ mod test { col1.add_or_update_deck(&mut deck)?; // and a new notetype - let mut nt = all_stock_notetypes(&col1.i18n).remove(0); + let mut nt = all_stock_notetypes(&col1.tr).remove(0); nt.name = "new".into(); col1.add_notetype(&mut nt)?; @@ -1550,7 +1550,10 @@ mod test { // removing things like a notetype forces a full sync col2.remove_notetype(ntid)?; let out = ctx.normal_sync(&mut col2).await; - assert!(matches!(out.required, SyncActionRequired::FullSyncRequired { .. })); + assert!(matches!( + out.required, + SyncActionRequired::FullSyncRequired { .. } + )); Ok(()) } diff --git a/rslib/src/template.rs b/rslib/src/template.rs index 788f57065..c4e03740a 100644 --- a/rslib/src/template.rs +++ b/rslib/src/template.rs @@ -246,14 +246,14 @@ fn parse_inner<'a, I: Iterator>>>( } } -fn template_error_to_anki_error(err: TemplateError, q_side: bool, i18n: &I18n) -> AnkiError { +fn template_error_to_anki_error(err: TemplateError, q_side: bool, tr: &I18n) -> AnkiError { let header = if q_side { - i18n.card_template_rendering_front_side_problem() + tr.card_template_rendering_front_side_problem() } else { - i18n.card_template_rendering_back_side_problem() + tr.card_template_rendering_back_side_problem() }; - let details = localized_template_error(i18n, err); - let more_info = i18n.card_template_rendering_more_info(); + let details = localized_template_error(tr, err); + let more_info = tr.card_template_rendering_more_info(); let info = format!( "{}
    {}
    {}", header, details, TEMPLATE_ERROR_LINK, more_info @@ -262,31 +262,31 @@ fn template_error_to_anki_error(err: TemplateError, q_side: bool, i18n: &I18n) - AnkiError::TemplateError { info } } -fn localized_template_error(i18n: &I18n, err: TemplateError) -> String { +fn localized_template_error(tr: &I18n, err: TemplateError) -> String { match err { - TemplateError::NoClosingBrackets(tag) => i18n + TemplateError::NoClosingBrackets(tag) => tr .card_template_rendering_no_closing_brackets("}}", tag) .into(), - TemplateError::ConditionalNotClosed(tag) => i18n + TemplateError::ConditionalNotClosed(tag) => tr .card_template_rendering_conditional_not_closed(format!("{{{{/{}}}}}", tag)) .into(), TemplateError::ConditionalNotOpen { closed, currently_open, } => if let Some(open) = currently_open { - i18n.card_template_rendering_wrong_conditional_closed( + tr.card_template_rendering_wrong_conditional_closed( format!("{{{{/{}}}}}", closed), format!("{{{{/{}}}}}", open), ) } else { - i18n.card_template_rendering_conditional_not_open( + tr.card_template_rendering_conditional_not_open( format!("{{{{/{}}}}}", closed), format!("{{{{#{}}}}}", closed), format!("{{{{^{}}}}}", closed), ) } .into(), - TemplateError::FieldNotFound { field, filters } => i18n + TemplateError::FieldNotFound { field, filters } => tr .card_template_rendering_no_such_field(format!("{{{{{}{}}}}}", filters, field), field) .into(), } @@ -531,7 +531,7 @@ pub fn render_card( field_map: &HashMap<&str, Cow>, card_ord: u16, is_cloze: bool, - i18n: &I18n, + tr: &I18n, ) -> Result<(Vec, Vec)> { // prepare context let mut context = RenderContext { @@ -544,22 +544,22 @@ pub fn render_card( // question side let (mut qnodes, qtmpl) = ParsedTemplate::from_text(qfmt) .and_then(|tmpl| Ok((tmpl.render(&context)?, tmpl))) - .map_err(|e| template_error_to_anki_error(e, true, i18n))?; + .map_err(|e| template_error_to_anki_error(e, true, tr))?; // check if the front side was empty let empty_message = if is_cloze && cloze_is_empty(field_map, card_ord) { Some(format!( "
    {}
    {}
    ", - i18n.card_template_rendering_missing_cloze(card_ord + 1), + tr.card_template_rendering_missing_cloze(card_ord + 1), TEMPLATE_BLANK_CLOZE_LINK, - i18n.card_template_rendering_more_info() + tr.card_template_rendering_more_info() )) } else if !is_cloze && !qtmpl.renders_with_fields(context.nonempty_fields) { Some(format!( "
    {}
    {}
    ", - i18n.card_template_rendering_empty_front(), + tr.card_template_rendering_empty_front(), TEMPLATE_BLANK_LINK, - i18n.card_template_rendering_more_info() + tr.card_template_rendering_more_info() )) } else { None @@ -573,7 +573,7 @@ pub fn render_card( context.question_side = false; let anodes = ParsedTemplate::from_text(afmt) .and_then(|tmpl| tmpl.render(&context)) - .map_err(|e| template_error_to_anki_error(e, false, i18n))?; + .map_err(|e| template_error_to_anki_error(e, false, tr))?; Ok((qnodes, anodes)) } @@ -1113,10 +1113,10 @@ mod test { .map(|r| (r.0, r.1.into())) .collect(); - let i18n = I18n::template_only(); + let tr = I18n::template_only(); use crate::template::RenderedNode as FN; - let qnodes = super::render_card("test{{E}}", "", &map, 1, false, &i18n) + let qnodes = super::render_card("test{{E}}", "", &map, 1, false, &tr) .unwrap() .0; assert_eq!(