ferrocat 0.13.0

Rust-first gettext and ICU toolkit for PO parsing, catalog updates, and MessageFormat parsing.
Documentation
use ferrocat::{
    CatalogCombineInput, CatalogMessageKey, CatalogUpdateInput, CombineCatalogOptions,
    CompileCatalogArtifactOptions, CompileSelectedCatalogArtifactOptions, CompiledCatalogIdIndex,
    CompiledKeyStrategy, EffectiveTranslation, EffectiveTranslationRef, MergeExtractedMessage,
    ParseCatalogOptions, SerializeOptions, SourceExtractedMessage, combine_catalogs,
    compile_catalog_artifact, compile_catalog_artifact_selected, has_select_ordinal, merge_catalog,
    parse_catalog, parse_icu, parse_po, stringify_po,
};

#[test]
fn umbrella_crate_reexports_po_and_icu_surfaces() {
    let mut file = parse_po(
        r#"
msgid "hello"
msgstr "world"
"#,
    )
    .expect("parse po");

    file.items[0].msgstr = "Welt".to_owned().into();

    let rendered = stringify_po(&file, &SerializeOptions::default());
    assert!(rendered.contains(r#"msgstr "Welt""#));

    let merged = merge_catalog(
        rendered.as_str(),
        &[MergeExtractedMessage {
            msgid: "hello".into(),
            ..MergeExtractedMessage::default()
        }],
    )
    .expect("merge catalog");
    assert!(merged.contains(r#"msgid "hello""#));

    let combine_inputs = [
        CatalogCombineInput::new("msgid \"hello\"\nmsgstr \"world\"\n"),
        CatalogCombineInput::new("msgid \"bye\"\nmsgstr \"\"\n"),
    ];
    let combined = combine_catalogs(CombineCatalogOptions::new(&combine_inputs, "en"))
        .expect("combine catalogs");
    assert!(combined.content.contains(r#"msgid "bye""#));

    let message = parse_icu("{count, selectordinal, one {#st} other {#th}}").expect("parse icu");
    assert!(has_select_ordinal(&message));

    let _source_input = CatalogUpdateInput::SourceFirst(vec![SourceExtractedMessage {
        msgid: "hello".into(),
        ..SourceExtractedMessage::default()
    }]);

    let parsed_catalog = parse_catalog(ParseCatalogOptions {
        content: "msgid \"hello\"\nmsgstr \"world\"\n",
        locale: Some("de"),
        source_locale: "en",
        ..ParseCatalogOptions::default()
    })
    .expect("parse catalog");
    let normalized = parsed_catalog
        .into_normalized_view()
        .expect("normalized view");
    let key = CatalogMessageKey::new("hello", None);
    assert!(matches!(
        normalized.effective_translation(&key),
        Some(EffectiveTranslationRef::Singular("world"))
    ));
    assert_eq!(
        normalized.effective_translation_with_source_fallback(&key, "en"),
        Some(EffectiveTranslation::Singular("world".to_owned()))
    );

    let source = parse_catalog(ParseCatalogOptions {
        content: "msgid \"hello\"\nmsgstr \"hello\"\n",
        locale: Some("en"),
        source_locale: "en",
        ..ParseCatalogOptions::default()
    })
    .expect("parse source catalog")
    .into_normalized_view()
    .expect("normalized source catalog");
    let artifact = compile_catalog_artifact(
        &[&normalized, &source],
        &CompileCatalogArtifactOptions {
            requested_locale: "de",
            source_locale: "en",
            ..CompileCatalogArtifactOptions::default()
        },
    )
    .expect("compile artifact");
    assert_eq!(artifact.messages.len(), 1);

    let index =
        CompiledCatalogIdIndex::new(&[&normalized, &source], CompiledKeyStrategy::FerrocatV1)
            .expect("compiled id index");
    let compiled_ids = index
        .iter()
        .map(|(id, _)| id.to_owned())
        .collect::<Vec<_>>();
    let selected_artifact = compile_catalog_artifact_selected(
        &[&normalized, &source],
        &index,
        &CompileSelectedCatalogArtifactOptions {
            requested_locale: "de",
            source_locale: "en",
            compiled_ids: &compiled_ids,
            ..CompileSelectedCatalogArtifactOptions::default()
        },
    )
    .expect("compile selected artifact");
    assert_eq!(selected_artifact.messages.len(), 1);
}