Skip to main content

workshop_rs/
convert.rs

1//! Raw Workshop locale conversion: parse -> canonical semantics -> emit.
2//!
3//! [`convert`] parses raw Workshop text in a source locale into
4//! locale-independent WIR, then emits it in a target locale. Canonical
5//! identities are locale-independent; only the spellings change. Missing
6//! target-locale mappings fail explicitly by default (an error, never a
7//! guess and never a silent passthrough of another locale's spelling);
8//! fallback is opt-in via [`ConvertOptions`] and recorded in
9//! [`Conversion::fallback_ids`].
10
11use crate::catalog::{Catalog, Locale};
12use crate::emitter::{self, EmitOptions};
13use crate::error::Result;
14use crate::parser;
15use crate::signatures::ExpectedDomain;
16
17/// Conversion options: opt-in fallback for missing target-locale mappings.
18#[derive(Debug, Clone, Default, PartialEq, Eq)]
19pub struct ConvertOptions {
20    /// When a canonical identity has no spelling for the target locale, its
21    /// spelling in this declared locale is used instead. `None` (the
22    /// default) keeps missing mappings failing explicitly. The fallback
23    /// choice is visible in [`Conversion::fallback_ids`].
24    pub fallback_locale: Option<Locale>,
25}
26
27/// The result of a raw Workshop locale conversion.
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct Conversion {
30    /// The converted localized Workshop text.
31    pub text: String,
32    /// Canonical identities (and the `settings` marker) whose spelling came
33    /// from the opt-in fallback locale instead of the target locale. Empty
34    /// when no fallback occurred.
35    pub fallback_ids: Vec<String>,
36}
37
38/// Convert raw Workshop text from `from` to `to`, parsing with the catalog as
39/// the canonical signature context (expected enum domains resolve ambiguous
40/// bare members that the catalog documents).
41pub fn convert(
42    input: &str,
43    catalog: &Catalog,
44    from: &Locale,
45    to: &Locale,
46    options: &ConvertOptions,
47) -> Result<Conversion> {
48    convert_with_context(input, catalog, from, to, options, catalog)
49}
50
51/// The context-aware form of [`convert`]: `context` supplies the expected
52/// enum domains for argument positions the catalog does not document (e.g. a
53/// provider manifest chained with the catalog via
54/// [`crate::signatures::ChainedExpectedDomain`]).
55pub fn convert_with_context(
56    input: &str,
57    catalog: &Catalog,
58    from: &Locale,
59    to: &Locale,
60    options: &ConvertOptions,
61    context: &dyn ExpectedDomain,
62) -> Result<Conversion> {
63    let program = parser::parse_with_context(input, catalog, from, context)?;
64    let emit_options = EmitOptions {
65        fallback_locale: options.fallback_locale.clone(),
66    };
67    let output = emitter::emit_with_options_for_conversion(&program, catalog, to, &emit_options)?;
68    Ok(Conversion {
69        text: output.text,
70        fallback_ids: output.fallback_ids,
71    })
72}