///|
fn argument_text(
arguments : Map[String, Argument],
name : String,
) -> String raise MessageError {
match arguments.get(name) {
Some(Text(value)) => value
Some(Number(value)) => value.to_string()
None => raise MissingArgument(name)
}
}
///|
fn argument_number(
arguments : Map[String, Argument],
name : String,
) -> Int raise MessageError {
match arguments.get(name) {
Some(Number(value)) => value
Some(Text(_)) => raise WrongArgumentType(name)
None => raise MissingArgument(name)
}
}
///|
fn format_nodes(
nodes : Array[MessageNode],
arguments : Map[String, Argument],
locale : String,
pound : Int?,
) -> String raise MessageError {
let out = StringBuilder::new()
for node in nodes {
match node {
TextNode(text) => out.write_string(text)
ArgumentNode(name) => out.write_string(argument_text(arguments, name))
PoundNode =>
match pound {
Some(value) => out.write_string(value.to_string())
None => out.write_char('#')
}
ChoiceNode(name, kind, cases) => {
let selector = if kind == "select" {
argument_text(arguments, name)
} else {
let value = argument_number(arguments, name)
let exact = "=" + value.to_string()
if cases.contains(exact) {
exact
} else if kind == "selectordinal" {
ordinal_category(locale, value)
} else {
plural_category(locale, value)
}
}
let branch = match cases.get(selector) {
Some(value) => value
None =>
match cases.get("other") {
Some(value) => value
None => raise MissingChoice(selector)
}
}
let nested_pound = if kind == "select" {
pound
} else {
Some(argument_number(arguments, name))
}
out.write_string(format_nodes(branch, arguments, locale, nested_pound))
}
}
}
out.to_string()
}
///|
/// Format a parsed message with text and integer arguments.
pub fn format(
message : Message,
arguments : Map[String, Argument],
locale : String,
) -> String raise MessageError {
format_nodes(message.nodes, arguments, locale, None)
}