FString -> TR

This commit is contained in:
Damien Elmes 2020-04-01 17:59:08 +10:00
parent 5392bd8e28
commit 546f4b44fc
7 changed files with 65 additions and 72 deletions

View file

@ -11,7 +11,7 @@ use crate::config::SortKind;
use crate::deckconf::{DeckConf, DeckConfID};
use crate::decks::DeckID;
use crate::err::{AnkiError, NetworkErrorKind, Result, SyncErrorKind};
use crate::i18n::{tr_args, FString, I18n};
use crate::i18n::{tr_args, I18n, TR};
use crate::latex::{extract_latex, extract_latex_expanding_clozes, ExtractedLatex};
use crate::log::{default_logger, Logger};
use crate::media::check::MediaChecker;
@ -771,7 +771,7 @@ fn progress_to_proto_bytes(progress: Progress, i18n: &I18n) -> Vec<u8> {
value: Some(match progress {
Progress::MediaSync(p) => pb::progress::Value::MediaSync(media_sync_progress(p, i18n)),
Progress::MediaCheck(n) => {
let s = i18n.trn(FString::MediaCheckChecked, tr_args!["count"=>n]);
let s = i18n.trn(TR::MediaCheckChecked, tr_args!["count"=>n]);
pb::progress::Value::MediaCheck(s)
}
}),
@ -784,13 +784,13 @@ fn progress_to_proto_bytes(progress: Progress, i18n: &I18n) -> Vec<u8> {
fn media_sync_progress(p: &MediaSyncProgress, i18n: &I18n) -> pb::MediaSyncProgress {
pb::MediaSyncProgress {
checked: i18n.trn(FString::SyncMediaCheckedCount, tr_args!["count"=>p.checked]),
checked: i18n.trn(TR::SyncMediaCheckedCount, tr_args!["count"=>p.checked]),
added: i18n.trn(
FString::SyncMediaAddedCount,
TR::SyncMediaAddedCount,
tr_args!["up"=>p.uploaded_files,"down"=>p.downloaded_files],
),
removed: i18n.trn(
FString::SyncMediaRemovedCount,
TR::SyncMediaRemovedCount,
tr_args!["up"=>p.uploaded_deletions,"down"=>p.downloaded_deletions],
),
}

View file

@ -1,7 +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::{tr_strs, FString, I18n};
use crate::i18n::{tr_strs, I18n, TR};
pub use failure::{Error, Fail};
use reqwest::StatusCode;
use std::io;
@ -69,21 +69,21 @@ impl AnkiError {
AnkiError::SyncError { info, kind } => match kind {
SyncErrorKind::ServerMessage => info.into(),
SyncErrorKind::Other => info.into(),
SyncErrorKind::Conflict => i18n.tr(FString::SyncConflict),
SyncErrorKind::ServerError => i18n.tr(FString::SyncServerError),
SyncErrorKind::ClientTooOld => i18n.tr(FString::SyncClientTooOld),
SyncErrorKind::AuthFailed => i18n.tr(FString::SyncWrongPass),
SyncErrorKind::ResyncRequired => i18n.tr(FString::SyncResyncRequired),
SyncErrorKind::Conflict => i18n.tr(TR::SyncConflict),
SyncErrorKind::ServerError => i18n.tr(TR::SyncServerError),
SyncErrorKind::ClientTooOld => i18n.tr(TR::SyncClientTooOld),
SyncErrorKind::AuthFailed => i18n.tr(TR::SyncWrongPass),
SyncErrorKind::ResyncRequired => i18n.tr(TR::SyncResyncRequired),
}
.into(),
AnkiError::NetworkError { kind, info } => {
let summary = match kind {
NetworkErrorKind::Offline => i18n.tr(FString::NetworkOffline),
NetworkErrorKind::Timeout => i18n.tr(FString::NetworkTimeout),
NetworkErrorKind::ProxyAuth => i18n.tr(FString::NetworkProxyAuth),
NetworkErrorKind::Other => i18n.tr(FString::NetworkOther),
NetworkErrorKind::Offline => i18n.tr(TR::NetworkOffline),
NetworkErrorKind::Timeout => i18n.tr(TR::NetworkTimeout),
NetworkErrorKind::ProxyAuth => i18n.tr(TR::NetworkProxyAuth),
NetworkErrorKind::Other => i18n.tr(TR::NetworkOther),
};
let details = i18n.trn(FString::NetworkDetails, tr_strs!["details"=>info]);
let details = i18n.trn(TR::NetworkDetails, tr_strs!["details"=>info]);
format!("{}\n\n{}", summary, details)
}
AnkiError::TemplateError { info } => {

View file

@ -15,10 +15,9 @@ use unic_langid::LanguageIdentifier;
mod autogen;
use crate::i18n::autogen::FLUENT_KEYS;
pub use crate::backend_proto::FluentString as TR;
pub use fluent::fluent_args as tr_args;
pub use crate::backend_proto::FluentString as FString;
/// Helper for creating args with &strs
#[macro_export]
macro_rules! tr_strs {
@ -284,13 +283,13 @@ impl I18n {
}
/// Get translation with zero arguments.
pub fn tr(&self, key: FString) -> Cow<str> {
pub fn tr(&self, key: TR) -> Cow<str> {
let key = FLUENT_KEYS[key as usize];
self.tr_(key, None)
}
/// Get translation with one or more arguments.
pub fn trn(&self, key: FString, args: FluentArgs) -> String {
pub fn trn(&self, key: TR, args: FluentArgs) -> String {
let key = FLUENT_KEYS[key as usize];
self.tr_(key, Some(args)).into()
}

View file

@ -3,7 +3,7 @@
use crate::collection::Collection;
use crate::err::{AnkiError, DBErrorKind, Result};
use crate::i18n::{tr_args, tr_strs, FString};
use crate::i18n::{tr_args, tr_strs, TR};
use crate::latex::extract_latex_expanding_clozes;
use crate::log::debug;
use crate::media::database::MediaDatabaseContext;
@ -99,41 +99,41 @@ where
if output.trash_count > 0 {
let megs = (output.trash_bytes as f32) / 1024.0 / 1024.0;
buf += &i.trn(
FString::MediaCheckTrashCount,
TR::MediaCheckTrashCount,
tr_args!["count"=>output.trash_count, "megs"=>megs],
);
buf.push('\n');
}
buf += &i.trn(
FString::MediaCheckMissingCount,
TR::MediaCheckMissingCount,
tr_args!["count"=>output.missing.len()],
);
buf.push('\n');
buf += &i.trn(
FString::MediaCheckUnusedCount,
TR::MediaCheckUnusedCount,
tr_args!["count"=>output.unused.len()],
);
buf.push('\n');
if !output.renamed.is_empty() {
buf += &i.trn(
FString::MediaCheckRenamedCount,
TR::MediaCheckRenamedCount,
tr_args!["count"=>output.renamed.len()],
);
buf.push('\n');
}
if !output.oversize.is_empty() {
buf += &i.trn(
FString::MediaCheckOversizeCount,
TR::MediaCheckOversizeCount,
tr_args!["count"=>output.oversize.len()],
);
buf.push('\n');
}
if !output.dirs.is_empty() {
buf += &i.trn(
FString::MediaCheckSubfolderCount,
TR::MediaCheckSubfolderCount,
tr_args!["count"=>output.dirs.len()],
);
buf.push('\n');
@ -142,13 +142,10 @@ where
buf.push('\n');
if !output.renamed.is_empty() {
buf += &i.tr(FString::MediaCheckRenamedHeader);
buf += &i.tr(TR::MediaCheckRenamedHeader);
buf.push('\n');
for (old, new) in &output.renamed {
buf += &i.trn(
FString::MediaCheckRenamedFile,
tr_strs!["old"=>old,"new"=>new],
);
buf += &i.trn(TR::MediaCheckRenamedFile, tr_strs!["old"=>old,"new"=>new]);
buf.push('\n');
}
buf.push('\n')
@ -156,10 +153,10 @@ where
if !output.oversize.is_empty() {
output.oversize.sort();
buf += &i.tr(FString::MediaCheckOversizeHeader);
buf += &i.tr(TR::MediaCheckOversizeHeader);
buf.push('\n');
for fname in &output.oversize {
buf += &i.trn(FString::MediaCheckOversizeFile, tr_strs!["filename"=>fname]);
buf += &i.trn(TR::MediaCheckOversizeFile, tr_strs!["filename"=>fname]);
buf.push('\n');
}
buf.push('\n')
@ -167,13 +164,10 @@ where
if !output.dirs.is_empty() {
output.dirs.sort();
buf += &i.tr(FString::MediaCheckSubfolderHeader);
buf += &i.tr(TR::MediaCheckSubfolderHeader);
buf.push('\n');
for fname in &output.dirs {
buf += &i.trn(
FString::MediaCheckSubfolderFile,
tr_strs!["filename"=>fname],
);
buf += &i.trn(TR::MediaCheckSubfolderFile, tr_strs!["filename"=>fname]);
buf.push('\n');
}
buf.push('\n')
@ -181,10 +175,10 @@ where
if !output.missing.is_empty() {
output.missing.sort();
buf += &i.tr(FString::MediaCheckMissingHeader);
buf += &i.tr(TR::MediaCheckMissingHeader);
buf.push('\n');
for fname in &output.missing {
buf += &i.trn(FString::MediaCheckMissingFile, tr_strs!["filename"=>fname]);
buf += &i.trn(TR::MediaCheckMissingFile, tr_strs!["filename"=>fname]);
buf.push('\n');
}
buf.push('\n')
@ -192,10 +186,10 @@ where
if !output.unused.is_empty() {
output.unused.sort();
buf += &i.tr(FString::MediaCheckUnusedHeader);
buf += &i.tr(TR::MediaCheckUnusedHeader);
buf.push('\n');
for fname in &output.unused {
buf += &i.trn(FString::MediaCheckUnusedFile, tr_strs!["filename"=>fname]);
buf += &i.trn(TR::MediaCheckUnusedFile, tr_strs!["filename"=>fname]);
buf.push('\n');
}
}

View file

@ -1,19 +1,19 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use crate::i18n::{tr_args, FString, I18n};
use crate::i18n::{tr_args, I18n, TR};
/// Short string like '4d' to place above answer buttons.
pub fn answer_button_time(seconds: f32, i18n: &I18n) -> String {
let span = Timespan::from_secs(seconds).natural_span();
let args = tr_args!["amount" => span.as_rounded_unit()];
let key = match span.unit() {
TimespanUnit::Seconds => FString::SchedulingAnswerButtonTimeSeconds,
TimespanUnit::Minutes => FString::SchedulingAnswerButtonTimeMinutes,
TimespanUnit::Hours => FString::SchedulingAnswerButtonTimeHours,
TimespanUnit::Days => FString::SchedulingAnswerButtonTimeDays,
TimespanUnit::Months => FString::SchedulingAnswerButtonTimeMonths,
TimespanUnit::Years => FString::SchedulingAnswerButtonTimeYears,
TimespanUnit::Seconds => TR::SchedulingAnswerButtonTimeSeconds,
TimespanUnit::Minutes => TR::SchedulingAnswerButtonTimeMinutes,
TimespanUnit::Hours => TR::SchedulingAnswerButtonTimeHours,
TimespanUnit::Days => TR::SchedulingAnswerButtonTimeDays,
TimespanUnit::Months => TR::SchedulingAnswerButtonTimeMonths,
TimespanUnit::Years => TR::SchedulingAnswerButtonTimeYears,
};
i18n.trn(key, args)
}
@ -31,12 +31,12 @@ pub fn time_span(seconds: f32, i18n: &I18n, precise: bool) -> String {
};
let args = tr_args!["amount" => amount];
let key = match span.unit() {
TimespanUnit::Seconds => FString::SchedulingTimeSpanSeconds,
TimespanUnit::Minutes => FString::SchedulingTimeSpanMinutes,
TimespanUnit::Hours => FString::SchedulingTimeSpanHours,
TimespanUnit::Days => FString::SchedulingTimeSpanDays,
TimespanUnit::Months => FString::SchedulingTimeSpanMonths,
TimespanUnit::Years => FString::SchedulingTimeSpanYears,
TimespanUnit::Seconds => TR::SchedulingTimeSpanSeconds,
TimespanUnit::Minutes => TR::SchedulingTimeSpanMinutes,
TimespanUnit::Hours => TR::SchedulingTimeSpanHours,
TimespanUnit::Days => TR::SchedulingTimeSpanDays,
TimespanUnit::Months => TR::SchedulingTimeSpanMonths,
TimespanUnit::Years => TR::SchedulingTimeSpanYears,
};
i18n.trn(key, args)
}
@ -53,7 +53,7 @@ pub fn studied_today(cards: usize, secs: f32, i18n: &I18n) -> String {
};
let args = tr_args!["amount" => amount, "unit" => unit,
"cards" => cards, "secs-per-card" => secs_per];
i18n.trn(FString::StatisticsStudiedToday, args)
i18n.trn(TR::StatisticsStudiedToday, args)
}
// fixme: this doesn't belong here
@ -70,8 +70,8 @@ pub fn learning_congrats(remaining: usize, next_due: f32, i18n: &I18n) -> String
let remaining_args = tr_args!["remaining" => remaining];
format!(
"{} {}",
i18n.trn(FString::SchedulingNextLearnDue, next_args),
i18n.trn(FString::SchedulingLearnRemaining, remaining_args)
i18n.trn(TR::SchedulingNextLearnDue, next_args),
i18n.trn(TR::SchedulingLearnRemaining, remaining_args)
)
}

View file

@ -5,7 +5,7 @@ use super::SqliteStorage;
use crate::{
deckconf::{DeckConf, DeckConfID},
err::Result,
i18n::{FString, I18n},
i18n::{I18n, TR},
};
use rusqlite::{params, NO_PARAMS};
use std::collections::HashMap;
@ -75,7 +75,7 @@ impl SqliteStorage {
pub(super) fn add_default_deck_config(&self, i18n: &I18n) -> Result<()> {
let mut conf = DeckConf::default();
conf.id.0 = 1;
conf.name = i18n.tr(FString::DeckConfigDefaultName).into();
conf.name = i18n.tr(TR::DeckConfigDefaultName).into();
self.add_deck_conf(&mut conf)
}

View file

@ -2,7 +2,7 @@
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use crate::err::{AnkiError, Result, TemplateError};
use crate::i18n::{tr_strs, FString, I18n};
use crate::i18n::{tr_strs, I18n, TR};
use crate::template_filters::apply_filters;
use lazy_static::lazy_static;
use nom::branch::alt;
@ -196,12 +196,12 @@ fn parse_inner<'a, I: Iterator<Item = TemplateResult<Token<'a>>>>(
fn template_error_to_anki_error(err: TemplateError, q_side: bool, i18n: &I18n) -> AnkiError {
let header = i18n.tr(if q_side {
FString::CardTemplateRenderingFrontSideProblem
TR::CardTemplateRenderingFrontSideProblem
} else {
FString::CardTemplateRenderingBackSideProblem
TR::CardTemplateRenderingBackSideProblem
});
let details = localized_template_error(i18n, err);
let more_info = i18n.tr(FString::CardTemplateRenderingMoreInfo);
let more_info = i18n.tr(TR::CardTemplateRenderingMoreInfo);
let info = format!(
"{}<br>{}<br><a href='{}'>{}</a>",
header, details, TEMPLATE_ERROR_LINK, more_info
@ -213,11 +213,11 @@ fn template_error_to_anki_error(err: TemplateError, q_side: bool, i18n: &I18n) -
fn localized_template_error(i18n: &I18n, err: TemplateError) -> String {
match err {
TemplateError::NoClosingBrackets(tag) => i18n.trn(
FString::CardTemplateRenderingNoClosingBrackets,
TR::CardTemplateRenderingNoClosingBrackets,
tr_strs!("tag"=>tag, "missing"=>"}}"),
),
TemplateError::ConditionalNotClosed(tag) => i18n.trn(
FString::CardTemplateRenderingConditionalNotClosed,
TR::CardTemplateRenderingConditionalNotClosed,
tr_strs!("missing"=>format!("{{{{/{}}}}}", tag)),
),
TemplateError::ConditionalNotOpen {
@ -226,14 +226,14 @@ fn localized_template_error(i18n: &I18n, err: TemplateError) -> String {
} => {
if let Some(open) = currently_open {
i18n.trn(
FString::CardTemplateRenderingWrongConditionalClosed,
TR::CardTemplateRenderingWrongConditionalClosed,
tr_strs!(
"found"=>format!("{{{{/{}}}}}", closed),
"expected"=>format!("{{{{/{}}}}}", open)),
)
} else {
i18n.trn(
FString::CardTemplateRenderingConditionalNotOpen,
TR::CardTemplateRenderingConditionalNotOpen,
tr_strs!(
"found"=>format!("{{{{/{}}}}}", closed),
"missing1"=>format!("{{{{#{}}}}}", closed),
@ -243,7 +243,7 @@ fn localized_template_error(i18n: &I18n, err: TemplateError) -> String {
}
}
TemplateError::FieldNotFound { field, filters } => i18n.trn(
FString::CardTemplateRenderingNoSuchField,
TR::CardTemplateRenderingNoSuchField,
tr_strs!(
"found"=>format!("{{{{{}{}}}}}", filters, field),
"field"=>field),
@ -509,9 +509,9 @@ pub fn render_card(
if !qtmpl.renders_with_fields(context.nonempty_fields) {
let info = format!(
"{}<br><a href='{}'>{}</a>",
i18n.tr(FString::CardTemplateRenderingEmptyFront),
i18n.tr(TR::CardTemplateRenderingEmptyFront),
TEMPLATE_BLANK_LINK,
i18n.tr(FString::CardTemplateRenderingMoreInfo)
i18n.tr(TR::CardTemplateRenderingMoreInfo)
);
return Err(AnkiError::TemplateError { info });
};