Skip to main content

workshop_rs/output/
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 `Program`, 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::core::error::Result;
13use crate::core::signatures::ExpectedDomain;
14use crate::frontend::parser;
15use crate::output::emitter::{self, EmitOptions};
16
17/// Conversion options: opt-in fallback for missing target-locale mappings.
18#[derive(Debug, Clone, Default, PartialEq, Eq)]
19#[non_exhaustive]
20pub struct ConvertOptions {
21    /// When a canonical identity has no spelling for the target locale, its
22    /// spelling in this declared locale is used instead. `None` (the
23    /// default) keeps missing mappings failing explicitly. The fallback
24    /// choice is visible in [`Conversion::fallback_ids`].
25    pub fallback_locale: Option<Locale>,
26}
27
28/// The result of a raw Workshop locale conversion.
29#[derive(Debug, Clone, PartialEq, Eq)]
30#[non_exhaustive]
31pub struct Conversion {
32    /// The converted localized Workshop text.
33    pub text: String,
34    /// Canonical identities (and the `settings` marker) whose spelling came
35    /// from the opt-in fallback locale instead of the target locale. Empty
36    /// when no fallback occurred.
37    pub fallback_ids: Vec<String>,
38}
39
40/// Convert raw Workshop text from `from` to `to`, parsing with the catalog as
41/// the canonical signature context (expected enum domains resolve ambiguous
42/// bare members that the catalog documents).
43pub fn convert(
44    input: &str,
45    catalog: &Catalog,
46    from: &Locale,
47    to: &Locale,
48    options: &ConvertOptions,
49) -> Result<Conversion> {
50    convert_with_context(input, catalog, from, to, options, catalog)
51}
52
53/// The context-aware form of [`convert`]: `context` supplies the expected
54/// enum domains for argument positions the catalog does not document (e.g. a
55/// provider manifest chained with the catalog via
56/// [`crate::core::signatures::ChainedExpectedDomain`]).
57pub fn convert_with_context(
58    input: &str,
59    catalog: &Catalog,
60    from: &Locale,
61    to: &Locale,
62    options: &ConvertOptions,
63    context: &dyn ExpectedDomain,
64) -> Result<Conversion> {
65    let program = parser::parse_with_context(input, catalog, from, context)?;
66    let emit_options = EmitOptions {
67        fallback_locale: options.fallback_locale.clone(),
68    };
69    let output = emitter::emit_with_options(&program, catalog, to, &emit_options)?;
70    Ok(Conversion {
71        text: output.text,
72        fallback_ids: output.fallback_ids,
73    })
74}