add string/number distinction to generated Rust methods

This commit is contained in:
Damien Elmes 2021-03-27 14:17:20 +10:00
parent e4002d7a5e
commit b5b21edd11
3 changed files with 57 additions and 27 deletions

View file

@ -165,9 +165,11 @@ impl From<String> for Variable {
| "kilobytes" | "daysStart" | "daysEnd" | "days" | "secs-per-card" | "remaining" | "kilobytes" | "daysStart" | "daysEnd" | "days" | "secs-per-card" | "remaining"
| "hourStart" | "hourEnd" | "correct" => VariableKind::Int, | "hourStart" | "hourEnd" | "correct" => VariableKind::Int,
"average-seconds" | "cards-per-minute" => VariableKind::Float, "average-seconds" | "cards-per-minute" => VariableKind::Float,
"val" | "found" | "expected" | "part" | "percent" | "day" => VariableKind::Any, "val" | "found" | "expected" | "part" | "percent" | "day" | "number" | "up"
| "down" | "seconds" | "megs" => VariableKind::Any,
term => { term => {
if term.ends_with("Count") || term.ends_with("Secs") { let term = term.to_ascii_lowercase();
if term.ends_with("count") {
VariableKind::Int VariableKind::Int
} else { } else {
VariableKind::String VariableKind::String

View file

@ -7,7 +7,7 @@ use inflections::Inflect;
use std::{fmt::Write, fs, path::PathBuf}; use std::{fmt::Write, fs, path::PathBuf};
use crate::{ use crate::{
extract::{Module, Translation}, extract::{Module, Translation, VariableKind},
gather::{TranslationsByFile, TranslationsByLang}, gather::{TranslationsByFile, TranslationsByLang},
}; };
@ -31,9 +31,8 @@ pub fn write_strings(map: &TranslationsByLang, modules: &[Module]) {
fn write_methods(modules: &[Module], buf: &mut String) { fn write_methods(modules: &[Module], buf: &mut String) {
buf.push_str( buf.push_str(
r#" r#"
use crate::I18n; use crate::{I18n,Number};
use crate::tr_args; use fluent::{FluentValue, FluentArgs};
use fluent::FluentValue;
use std::borrow::Cow; use std::borrow::Cow;
impl I18n { impl I18n {
@ -46,12 +45,15 @@ impl I18n {
let doc = translation.text.replace("\n", " "); let doc = translation.text.replace("\n", " ");
let in_args; let in_args;
let out_args; let out_args;
let var_build;
if translation.variables.is_empty() { if translation.variables.is_empty() {
in_args = "".to_string(); in_args = "".to_string();
out_args = ", None".to_string(); out_args = ", None".to_string();
var_build = "".to_string();
} else { } else {
in_args = build_in_args(translation); in_args = build_in_args(translation);
out_args = build_out_args(translation); var_build = build_vars(translation);
out_args = ", Some(args)".to_string();
} }
writeln!( writeln!(
@ -60,6 +62,7 @@ impl I18n {
/// {doc} /// {doc}
#[inline] #[inline]
pub fn {func}<'a>(&'a self{in_args}) -> Cow<'a, str> {{ pub fn {func}<'a>(&'a self{in_args}) -> Cow<'a, str> {{
{var_build}
self.translate("{key}"{out_args}) self.translate("{key}"{out_args})
}}"#, }}"#,
func = func, func = func,
@ -67,6 +70,7 @@ impl I18n {
doc = doc, doc = doc,
in_args = in_args, in_args = in_args,
out_args = out_args, out_args = out_args,
var_build = var_build,
) )
.unwrap(); .unwrap();
} }
@ -75,19 +79,35 @@ impl I18n {
buf.push_str("}\n"); buf.push_str("}\n");
} }
fn build_out_args(translation: &Translation) -> String { fn build_vars(translation: &Translation) -> String {
let v: Vec<_> = translation if translation.variables.is_empty() {
.variables "let args = None;\n".into()
.iter() } else {
.map(|var| { let mut buf = String::from(
format!( r#"
r#""{fluent_name}"=>{rust_name}"#, let mut args = FluentArgs::new();
fluent_name = var.name, "#,
rust_name = var.name.to_snake_case() );
for v in &translation.variables {
let fluent_name = &v.name;
let rust_name = v.name.to_snake_case();
let trailer = match v.kind {
VariableKind::Any => "",
VariableKind::Int | VariableKind::Float => ".into()",
VariableKind::String => ".into()",
};
writeln!(
buf,
r#" args.set("{fluent_name}", {rust_name}{trailer});"#,
fluent_name = fluent_name,
rust_name = rust_name,
trailer = trailer,
) )
}) .unwrap();
.collect(); }
format!(", Some(tr_args![{}])", v.join(", "))
buf
}
} }
fn build_in_args(translation: &Translation) -> String { fn build_in_args(translation: &Translation) -> String {
@ -95,13 +115,13 @@ fn build_in_args(translation: &Translation) -> String {
.variables .variables
.iter() .iter()
.map(|var| { .map(|var| {
// let kind = match var.kind { let kind = match var.kind {
// VariableKind::Int => "i64", VariableKind::Int => "impl Number",
// VariableKind::Float => "f64", VariableKind::Float => "impl Number",
// VariableKind::String => "&str", VariableKind::String => "impl Into<String>",
// VariableKind::Any => "&str", // VariableKind::Any => "&str",
// }; _ => "impl Into<FluentValue<'a>>",
let kind = "impl Into<FluentValue<'a>>"; };
format!("{}: {}", var.name.to_snake_case(), kind) format!("{}: {}", var.name.to_snake_case(), kind)
}) })
.collect(); .collect();

View file

@ -3,7 +3,7 @@
mod generated; mod generated;
use fluent::{FluentArgs, FluentResource, FluentValue}; use fluent::{types::FluentNumber, FluentArgs, FluentResource, FluentValue};
use fluent_bundle::bundle::FluentBundle as FluentBundleOrig; use fluent_bundle::bundle::FluentBundle as FluentBundleOrig;
use num_format::Locale; use num_format::Locale;
use serde::Serialize; use serde::Serialize;
@ -17,6 +17,14 @@ type FluentBundle<T> = FluentBundleOrig<T, intl_memoizer::concurrent::IntlLangMe
pub use fluent::fluent_args as tr_args; pub use fluent::fluent_args as tr_args;
pub trait Number: Into<FluentNumber> {}
impl Number for i32 {}
impl Number for i64 {}
impl Number for u32 {}
impl Number for f32 {}
impl Number for u64 {}
impl Number for usize {}
fn remapped_lang_name(lang: &LanguageIdentifier) -> &str { fn remapped_lang_name(lang: &LanguageIdentifier) -> &str {
let region = match &lang.region { let region = match &lang.region {
Some(region) => Some(region.as_str()), Some(region) => Some(region.as_str()),