Skip to main content

eska_presentation/localization/
platform.rs

1//! Presentation-only captions for the open-ended Designer XML vocabulary.
2
3use eska_project_core::project::metadata_model::{MetadataKind, PropertyKey};
4
5use super::Localizer;
6
7impl Localizer {
8    /// Resolve contextual captions first, retaining `QName` boundaries for unknown extensions.
9    #[must_use]
10    pub fn property_caption(
11        &self,
12        owner: Option<MetadataKind>,
13        key: &PropertyKey,
14    ) -> Option<String> {
15        // Catalog names are ASCII identifiers; a hyphenated XML name must not impersonate
16        // the owner segment of a contextual Fluent key.
17        if !key.name.bytes().all(|byte| byte.is_ascii_alphanumeric()) {
18            return None;
19        }
20        let namespace = match key.namespace.as_deref()? {
21            "http://v8.1c.ru/8.3/MDClasses" => "md",
22            "http://v8.1c.ru/8.3/xcf/readable" => "readable",
23            "http://v8.1c.ru/8.1/data/core" => "core",
24            "http://v8.1c.ru/8.1/data/ui" => "ui",
25            "http://v8.1c.ru/8.2/managed-application/core" => "app",
26            "http://v8.1c.ru/8.3/xcf/predef" => "predef",
27            _ => return None,
28        };
29        if let Some(owner) = owner {
30            let contextual = format!(
31                "platform-property-{namespace}-{}-{}",
32                owner.as_str(),
33                key.name
34            );
35            if let Some(caption) = self.optional_text(&contextual) {
36                return Some(caption);
37            }
38        }
39        self.optional_text(&format!("platform-property-{namespace}-{}", key.name))
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46    use crate::localization::Locale;
47
48    /// Every audited `QName` and owner resolves in both locales, including newer additions.
49    #[test]
50    fn catalog_covers_the_audited_vocabulary() {
51        let catalog = include_str!("../../locales/platform-catalog.tsv");
52        for locale in [Locale::RuRu, Locale::EnUs] {
53            let localizer = Localizer::try_new(locale).unwrap();
54            for line in catalog.lines().skip(1) {
55                let columns: Vec<_> = line.split('\t').collect();
56                assert_eq!(columns.len(), 5);
57                let owner = MetadataKind::ALL
58                    .iter()
59                    .copied()
60                    .find(|kind| kind.as_str() == columns[3]);
61                assert!(columns[3].is_empty() || owner.is_some());
62                let caption = localizer.property_caption(
63                    owner,
64                    &PropertyKey {
65                        namespace: Some(columns[1].into()),
66                        name: columns[2].into(),
67                    },
68                );
69                assert_eq!(caption, localizer.optional_text(columns[0]), "{line}");
70                assert!(caption.is_some_and(|text| !text.trim().is_empty()));
71            }
72            for line in include_str!("../../locales/platform-coverage.tsv")
73                .lines()
74                .skip(1)
75            {
76                let columns: Vec<_> = line.split('\t').collect();
77                assert_eq!(columns.len(), 6);
78                assert!(localizer.optional_text(columns[5]).is_some(), "{line}");
79            }
80        }
81    }
82
83    /// Unknown namespaces and fields cannot accidentally borrow a familiar-looking caption.
84    #[test]
85    fn captions_respect_namespaces_and_owner_context() {
86        let localizer = Localizer::try_new(Locale::RuRu).unwrap();
87        let mut key = PropertyKey {
88            namespace: Some("http://v8.1c.ru/8.3/MDClasses".into()),
89            name: "Type".into(),
90        };
91        assert_eq!(
92            localizer.property_caption(None, &key).as_deref(),
93            Some("Тип")
94        );
95        assert_eq!(
96            localizer
97                .property_caption(Some(MetadataKind::StyleItem), &key)
98                .as_deref(),
99            Some("Вид")
100        );
101        key.namespace = Some("urn:vendor".into());
102        assert_eq!(
103            localizer.property_caption(Some(MetadataKind::StyleItem), &key),
104            None
105        );
106        key.namespace = None;
107        assert_eq!(localizer.property_caption(None, &key), None);
108        key.namespace = Some("http://v8.1c.ru/8.3/MDClasses".into());
109        key.name = "FutureProperty".into();
110        assert_eq!(localizer.property_caption(None, &key), None);
111        key.name = "sequence-RegisterRecords".into();
112        assert_eq!(localizer.property_caption(None, &key), None);
113    }
114}