mirror of
https://github.com/storytold/craft-launcher.git
synced 2026-11-02 18:07:04 +00:00
A value holding {other} was expanded again by a later argument. fmt now
walks the template once, so values stay exactly as they came.
This commit is contained in:
@@ -5,7 +5,19 @@ use std::collections::{BTreeSet, HashSet};
|
||||
|
||||
use super::catalog::{Catalog, unescape};
|
||||
use super::lang::{name_sort_key, plural_czech, plural_east_slavic, plural_polish};
|
||||
use super::{LANGUAGES, Lang, LangInfo, lang_from_tag, message, tr, trn};
|
||||
use super::{LANGUAGES, Lang, LangInfo, fmt, lang_from_tag, message, tr, trn};
|
||||
|
||||
#[test]
|
||||
fn a_filled_in_value_is_never_read_as_a_placeholder() {
|
||||
assert_eq!(fmt("{name}: {error}", &[("name", "{error}"), ("error", "disk full")]), "{error}: disk full");
|
||||
assert_eq!(fmt("{a} and {a}", &[("a", "{a}")]), "{a} and {a}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholders_nobody_filled_stay_as_written() {
|
||||
assert_eq!(fmt("{a} {b} { {} }{", &[("a", "1")]), "1 {b} { {} }{");
|
||||
assert_eq!(fmt("{{a}", &[("a", "1")]), "{1");
|
||||
}
|
||||
|
||||
/// Each catalog's rows as (line number, context, source, translation), split exactly as the
|
||||
/// parser does: `trim_end` only, since a plain row *starts* with a TAB.
|
||||
|
||||
@@ -53,12 +53,22 @@ pub fn t_id<'a>(id: &str, label: &'a str) -> &'a str {
|
||||
#[cfg(test)]
|
||||
pub(crate) use strict::{StrictCjkDrawing, drew_cjk};
|
||||
|
||||
/// Fill `{name}` placeholders. Unknown placeholders are left as written.
|
||||
/// Fill `{name}` placeholders in one pass. Values and unknown placeholders stay as written.
|
||||
pub fn fmt(template: &str, args: &[(&str, &str)]) -> String {
|
||||
let mut out = template.to_string();
|
||||
for (k, v) in args {
|
||||
out = out.replace(&format!("{{{k}}}"), v);
|
||||
let mut out = String::with_capacity(template.len());
|
||||
let mut rest = template;
|
||||
while let Some((before, after)) = rest.split_once('{') {
|
||||
out.push_str(before);
|
||||
let filled = after.split_once('}').and_then(|(name, tail)| args.iter().find(|(k, _)| *k == name).map(|(_, v)| (*v, tail)));
|
||||
if let Some((value, tail)) = filled {
|
||||
out.push_str(value);
|
||||
rest = tail;
|
||||
} else {
|
||||
out.push('{');
|
||||
rest = after;
|
||||
}
|
||||
}
|
||||
out.push_str(rest);
|
||||
out
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user