1use alloc::string::String;
2use core::str::FromStr;
3
4use crate::{I18nString, Resolver};
5
6fn translate_to<R: Resolver + ?Sized>(input: &I18nString, output: &mut String, resolver: &R) {
7 match input {
8 I18nString::Literal(s) => {
9 output.push_str(s);
10 }
11 I18nString::Template(template, args) => {
12 enum ParseState {
13 Normal,
14 HitLeftBrace { pos: usize },
15 HitRightBrace,
16 }
17
18 let template = resolver.resolve(template);
19
20 let mut state = ParseState::Normal;
21
22 for (idx, c) in template.char_indices() {
23 match state {
24 ParseState::Normal => {
25 if c == '{' {
26 state = ParseState::HitLeftBrace { pos: idx };
27 } else if c == '}' {
28 state = ParseState::HitRightBrace;
29 } else {
30 output.push(c);
31 }
32 }
33 ParseState::HitLeftBrace { pos } => {
34 if c == '}' {
35 match usize::from_str(&template[pos + 1..idx]).ok().and_then(|idx| args.get(idx)) {
36 Some(arg) => {
37 translate_to(arg, output, resolver);
38 }
39 None => {
40 output.push('{');
42 output.push_str(&template[pos + 1..idx]);
43 output.push('}');
44 }
45 }
46
47 state = ParseState::Normal;
48 } else if c == '{' {
49 output.push(c);
50 state = ParseState::Normal;
51 }
52 }
53 ParseState::HitRightBrace => {
54 if c == '}' {
55 output.push(c);
56 state = ParseState::Normal;
57 } else {
58 output.push('}');
60 output.push(c);
61 state = ParseState::Normal;
62 }
63 }
64 }
65 }
66
67 match state {
68 ParseState::Normal => {}
69 ParseState::HitLeftBrace { pos } => {
70 output.push('{');
72 output.push_str(&template[pos + 1..]);
73 }
74 ParseState::HitRightBrace => {
75 output.push('}');
77 }
78 }
79 }
80 }
81}
82
83impl I18nString {
84 pub fn translate<R: Resolver>(&self, resolver: R) -> String {
85 let mut res = String::with_capacity(32);
86 translate_to(self, &mut res, &resolver);
87 res
88 }
89}