diff --git a/accessibility-rs/src/engine/audit/wcag.rs b/accessibility-rs/src/engine/audit/wcag.rs index 87abe91..81bcca4 100644 --- a/accessibility-rs/src/engine/audit/wcag.rs +++ b/accessibility-rs/src/engine/audit/wcag.rs @@ -22,7 +22,7 @@ impl WCAG3AA { match rules { Some(rules) => { for rule in rules { - let validation = (rule.validate)(&node.0, &node.1); + let validation = (rule.validate)(&node.1, &auditor.locale); let message = validation.message; if !validation.valid { diff --git a/accessibility-rs/src/engine/rules/rule.rs b/accessibility-rs/src/engine/rules/rule.rs index 14e8adf..18f2291 100644 --- a/accessibility-rs/src/engine/rules/rule.rs +++ b/accessibility-rs/src/engine/rules/rule.rs @@ -14,7 +14,7 @@ pub struct Validation { /// elements that match the issue pub elements: Vec, /// the message of the error - pub message: &'static str, + pub message: String, } impl Validation { @@ -23,7 +23,7 @@ impl Validation { valid: bool, id: &'static str, elements: Vec, - message: &'static str, + message: String, ) -> Self { Self { valid, @@ -50,7 +50,7 @@ pub struct Rule { /// the type of rule pub issue_type: IssueType, /// validate a test returns (valid, rule, selectors) - pub validate: fn(&str, &Vec<(ElementRef<'_>, Option)>) -> Validation, + pub validate: fn(&Vec<(ElementRef<'_>, Option)>, &str) -> Validation, /// the principle type pub principle: Principle, /// the guideline to follow @@ -67,7 +67,7 @@ impl Rule { principle: Principle, guideline: Guideline, success_criteria: &'static str, - validate: fn(&str, &Vec<(ElementRef<'_>, Option)>) -> Validation, + validate: fn(&Vec<(ElementRef<'_>, Option)>, &str) -> Validation, ) -> Rule { Rule { rule_id, diff --git a/accessibility-rs/src/engine/rules/utils/nodes.rs b/accessibility-rs/src/engine/rules/utils/nodes.rs index 0223f7a..a4b2ecc 100644 --- a/accessibility-rs/src/engine/rules/utils/nodes.rs +++ b/accessibility-rs/src/engine/rules/utils/nodes.rs @@ -1,6 +1,6 @@ use crate::engine::rules::rule::Validation; use crate::ElementRef; -use accessibility_scraper::{node, Selector}; +use accessibility_scraper::Selector; use selectors::Element; use slotmap::DefaultKey; @@ -44,7 +44,7 @@ pub fn is_empty(nodes: &ElementNodes) -> (bool, Vec) { /// elements empty with validation pub fn validate_empty_nodes(nodes: &ElementNodes, id: &'static str) -> Validation { let (valid, elements) = is_empty(&nodes); - Validation::new(valid, id, elements, "") + Validation::new(valid, id, elements, Default::default()) } /// check if the selector only exist for one element @@ -143,5 +143,5 @@ pub fn validate_missing_attr( } }); - Validation::new(valid, id, elements, "") + Validation::new(valid, id, elements, Default::default()) } diff --git a/accessibility-rs/src/engine/rules/wcag_rule_map.rs b/accessibility-rs/src/engine/rules/wcag_rule_map.rs index ff44acb..0d42435 100644 --- a/accessibility-rs/src/engine/rules/wcag_rule_map.rs +++ b/accessibility-rs/src/engine/rules/wcag_rule_map.rs @@ -4,6 +4,7 @@ use crate::engine::rules::utils::nodes::{ get_unique_selector, has_alt, validate_empty_nodes, validate_missing_attr, }; use crate::engine::rules::wcag_base::{Guideline, IssueType, Principle}; +use crate::i18n::locales::get_message_i18n_str_raw; use accessibility_scraper::{ElementRef, Selector}; use selectors::Element; use std::collections::BTreeMap; @@ -16,11 +17,11 @@ lazy_static! { pub static ref RULES_A: BTreeMap<&'static str, Vec> = vec![ ("html", Vec::from([ - Rule::new(Techniques::H57, IssueType::Error, Principle::Understandable, Guideline::Readable, "1", |_rule, nodes| { + Rule::new(Techniques::H57, IssueType::Error, Principle::Understandable, Guideline::Readable, "1", |nodes, _lang| { let n = nodes[0].0; Validation::new_issue(!n.attr("lang").unwrap_or_default().is_empty() || !n.attr("xml:lang").unwrap_or_default().is_empty(), "2") }), - Rule::new(Techniques::H57, IssueType::Error, Principle::Understandable, Guideline::Readable, "1", |_rule, nodes| { + Rule::new(Techniques::H57, IssueType::Error, Principle::Understandable, Guideline::Readable, "1", |nodes, _lang| { let lang = nodes[0].0.attr("lang").unwrap_or_default(); let alphabetic = lang.chars().all(|x| x.is_alphabetic()); // @@ -32,7 +33,7 @@ lazy_static! { alphabetic && lang.len() < 12 }, "3.Lang") }), - Rule::new(Techniques::H57, IssueType::Error, Principle::Understandable, Guideline::Readable, "1", |_rule, nodes| { + Rule::new(Techniques::H57, IssueType::Error, Principle::Understandable, Guideline::Readable, "1", |nodes, _lang| { let lang = nodes[0].0.attr("xml:lang").unwrap_or_default(); let alphabetic = lang.chars().all(|x| x == '_' || x.is_alphabetic()); // @@ -44,7 +45,7 @@ lazy_static! { alphabetic && lang.len() < 12 }, "3.XmlLang") }), - Rule::new(Techniques::F77, IssueType::Error, Principle::Robust, Guideline::Compatible, "1", |_rule, nodes| { + Rule::new(Techniques::F77, IssueType::Error, Principle::Robust, Guideline::Compatible, "1", |nodes, lang| { let mut id_map: HashMap<&str, u8> = HashMap::new(); let mut valid = true; @@ -77,15 +78,16 @@ lazy_static! { } } - let duplicate_ids = id_map.into_iter().filter_map(|(id, size)| if size >= 1 { Some(id.to_string()) } else { None }).collect(); + let duplicate_ids: Vec<_> = id_map.into_iter().filter_map(|(id, size)| if size >= 1 { Some(id.to_string()) } else { None }).collect(); + let message = t!(&get_message_i18n_str_raw( &Guideline::Compatible, Techniques::F77.as_str(), "1", ""), locale = lang, id = duplicate_ids.join(",")); - // let message = t!(&crate::i18n::locales::get_message_i18n_str(_rule, "")); + println!("{:?}", message); - Validation::new(valid, "", duplicate_ids, "") + Validation::new(valid, "", duplicate_ids, message) }), ])), ("meta", Vec::from([ - Rule::new(Techniques::F40, IssueType::Error, Principle::Operable, Guideline::EnoughTime, "1", |_rule, nodes| { + Rule::new(Techniques::F40, IssueType::Error, Principle::Operable, Guideline::EnoughTime, "1", |nodes, _lang| { let mut valid = true; for node in nodes { @@ -101,7 +103,7 @@ lazy_static! { Validation::new_issue(valid, "2") }), - Rule::new(Techniques::F41, IssueType::Error, Principle::Understandable, Guideline::EnoughTime, "1", |_rule, nodes| { + Rule::new(Techniques::F41, IssueType::Error, Principle::Understandable, Guideline::EnoughTime, "1", |nodes, _lang| { let mut valid = true; for node in nodes { @@ -119,30 +121,30 @@ lazy_static! { }), ])), ("title", Vec::from([ - Rule::new(Techniques::H25, IssueType::Error, Principle::Operable, Guideline::Navigable, "1", |_rule, nodes| { + Rule::new(Techniques::H25, IssueType::Error, Principle::Operable, Guideline::Navigable, "1", |nodes, _lang| { Validation::new_issue(!nodes.is_empty(), "1.NoTitleEl") }), - Rule::new(Techniques::H25, IssueType::Error, Principle::Operable, Guideline::Navigable, "1", |_rule, nodes| { + Rule::new(Techniques::H25, IssueType::Error, Principle::Operable, Guideline::Navigable, "1", |nodes, _lang| { Validation::new_issue(nodes.is_empty() || nodes[0].0.html().is_empty(), "1.EmptyTitle") }), ])), ("blink", Vec::from([ - Rule::new(Techniques::F47, IssueType::Error, Principle::Operable, Guideline::EnoughTime, "2", |_rule, nodes| { + Rule::new(Techniques::F47, IssueType::Error, Principle::Operable, Guideline::EnoughTime, "2", |nodes, _lang| { Validation::new_issue(nodes.is_empty(), "") }), ])), ("iframe", Vec::from([ - Rule::new(Techniques::H64, IssueType::Error, Principle::Operable, Guideline::Navigable, "1", |_rule, nodes| { + Rule::new(Techniques::H64, IssueType::Error, Principle::Operable, Guideline::Navigable, "1", |nodes, _lang| { validate_missing_attr(nodes, "title", "1") }), ])), ("frame", Vec::from([ - Rule::new(Techniques::H64, IssueType::Error, Principle::Operable, Guideline::Navigable, "1", |_rule, nodes| { + Rule::new(Techniques::H64, IssueType::Error, Principle::Operable, Guideline::Navigable, "1", |nodes, _lang| { validate_missing_attr(nodes, "title", "1") }), ])), ("form", Vec::from([ - Rule::new(Techniques::H32, IssueType::Error, Principle::Operable, Guideline::Predictable, "2", |_rule, nodes| { + Rule::new(Techniques::H32, IssueType::Error, Principle::Operable, Guideline::Predictable, "2", |nodes, _lang| { let mut valid = false; let mut elements = Vec::new(); let selector = unsafe { Selector::parse("button[type=submit]").unwrap_unchecked() }; @@ -160,9 +162,9 @@ lazy_static! { } } - Validation::new(valid, "2", elements, "") + Validation::new(valid, "2", elements, Default::default()) }), - Rule::new(Techniques::H36, IssueType::Error, Principle::Perceivable, Guideline::TextAlternatives, "1", |_rule, nodes| { + Rule::new(Techniques::H36, IssueType::Error, Principle::Perceivable, Guideline::TextAlternatives, "1", |nodes, _lang| { let mut valid = false; let mut elements = Vec::new(); let selector = unsafe { Selector::parse("input[type=image][name=submit]").unwrap_unchecked() }; @@ -180,11 +182,11 @@ lazy_static! { } } - Validation::new(valid, "", elements, "") + Validation::new(valid, "", elements, Default::default()) }), ])), ("a", Vec::from([ - Rule::new(Techniques::H30, IssueType::Error, Principle::Perceivable, Guideline::TextAlternatives, "1", |_rule, nodes| { + Rule::new(Techniques::H30, IssueType::Error, Principle::Perceivable, Guideline::TextAlternatives, "1", |nodes, _lang| { let mut valid = true; let selector = unsafe { Selector::parse("img").unwrap_unchecked() }; let mut elements = Vec::new(); @@ -202,9 +204,9 @@ lazy_static! { } } - Validation::new(valid, "2", elements, "") + Validation::new(valid, "2", elements, Default::default()) }), - Rule::new(Techniques::H91, IssueType::Error, Principle::Robust, Guideline::Compatible, "2", |_rule, nodes| { + Rule::new(Techniques::H91, IssueType::Error, Principle::Robust, Guideline::Compatible, "2", |nodes, _lang| { let mut valid = true; let mut elements = Vec::new(); @@ -221,9 +223,9 @@ lazy_static! { _ => () } } - Validation::new(valid, "A.NoContent", elements, "") + Validation::new(valid, "A.NoContent", elements, Default::default()) }), - Rule::new(Techniques::H91, IssueType::Error, Principle::Robust, Guideline::Compatible, "2", |_rule, nodes| { + Rule::new(Techniques::H91, IssueType::Error, Principle::Robust, Guideline::Compatible, "2", |nodes, _lang| { let mut valid = true; let mut elements = Vec::new(); for ele in nodes { @@ -234,11 +236,11 @@ lazy_static! { } valid = v; } - Validation::new(valid, "A.EmptyNoId", elements, "") + Validation::new(valid, "A.EmptyNoId", elements, Default::default()) }), ])), ("img", Vec::from([ - Rule::new(Techniques::H37, IssueType::Error, Principle::Perceivable, Guideline::TextAlternatives, "1", |_rule, nodes| { + Rule::new(Techniques::H37, IssueType::Error, Principle::Perceivable, Guideline::TextAlternatives, "1", |nodes, _lang| { let mut valid = true; let mut elements = Vec::new(); @@ -251,36 +253,36 @@ lazy_static! { valid = alt; } - Validation::new(valid, "", elements, "") + Validation::new(valid, "", elements, Default::default()) }), ])), ("h1", Vec::from([ - Rule::new(Techniques::H42, IssueType::Error, Principle::Perceivable, Guideline::Adaptable, "1", |_rule, nodes| { + Rule::new(Techniques::H42, IssueType::Error, Principle::Perceivable, Guideline::Adaptable, "1", |nodes, _lang| { validate_empty_nodes(nodes, "2") }), ])), ("h2", Vec::from([ - Rule::new(Techniques::H42, IssueType::Error, Principle::Perceivable, Guideline::Adaptable, "1", |_rule, nodes| { + Rule::new(Techniques::H42, IssueType::Error, Principle::Perceivable, Guideline::Adaptable, "1", |nodes, _lang| { validate_empty_nodes(nodes, "2") }), ])), ("h3", Vec::from([ - Rule::new(Techniques::H42, IssueType::Error, Principle::Perceivable, Guideline::Adaptable, "1", |_rule, nodes| { + Rule::new(Techniques::H42, IssueType::Error, Principle::Perceivable, Guideline::Adaptable, "1", |nodes, _lang| { validate_empty_nodes(nodes, "2") }), ])), ("h4", Vec::from([ - Rule::new(Techniques::H42, IssueType::Error, Principle::Perceivable, Guideline::Adaptable, "1", |_rule, nodes| { + Rule::new(Techniques::H42, IssueType::Error, Principle::Perceivable, Guideline::Adaptable, "1", |nodes, _lang| { validate_empty_nodes(nodes, "2") }), ])), ("h5", Vec::from([ - Rule::new(Techniques::H42, IssueType::Error, Principle::Perceivable, Guideline::Adaptable, "1", |_rule, nodes| { + Rule::new(Techniques::H42, IssueType::Error, Principle::Perceivable, Guideline::Adaptable, "1", |nodes, _lang| { validate_empty_nodes(nodes, "2") }), ])), ("h6", Vec::from([ - Rule::new(Techniques::H42, IssueType::Error, Principle::Perceivable, Guideline::Adaptable, "1", |_rule, nodes| { + Rule::new(Techniques::H42, IssueType::Error, Principle::Perceivable, Guideline::Adaptable, "1", |nodes, _lang| { validate_empty_nodes(nodes, "2") }), ])), diff --git a/accessibility-rs/src/i18n/locales.rs b/accessibility-rs/src/i18n/locales.rs index 8e0e90d..a2011ba 100644 --- a/accessibility-rs/src/i18n/locales.rs +++ b/accessibility-rs/src/i18n/locales.rs @@ -1,4 +1,4 @@ -use crate::engine::rules::rule::Rule; +use crate::engine::rules::{rule::Rule, wcag_base::Guideline}; type M = &'static str; @@ -63,21 +63,23 @@ impl Langs { } } -/// get message config type -pub fn get_message_i18n_str(rule: &Rule, section: &str) -> String { - // todo: add criteria handling fix - let base = [rule.guideline.as_index(), rule.success_criteria].join("_") + "_"; +/// get message config type raw +pub fn get_message_i18n_str_raw(guideline: &Guideline, rule_id: &str, success_criteria: &str, section: &str) -> String { + let base = [guideline.as_index(), success_criteria].join("_") + "_"; let message = if section.is_empty() { - [rule.rule_id.as_str()].join(".").to_string() + [rule_id].join(".").to_string() } else { - [rule.rule_id.as_str(), section].join(".").to_string() + [rule_id, section].join(".").to_string() }; - let message = [base.as_str(), message.as_str()].join("").to_string(); - - message + [base.as_str(), message.as_str()].join("").to_string() } /// get message config type +pub fn get_message_i18n_str(rule: &Rule, section: &str) -> String { + get_message_i18n_str_raw(&rule.guideline, rule.rule_id.as_str(), rule.success_criteria, section) +} + +/// get message pub fn get_message_i18n(rule: &Rule, section: &str, lang: &str) -> String { let message = get_message_i18n_str(rule, section); diff --git a/accessibility-rs/tests/unit/html.rs b/accessibility-rs/tests/unit/html.rs index c5b1211..00bcae5 100644 --- a/accessibility-rs/tests/unit/html.rs +++ b/accessibility-rs/tests/unit/html.rs @@ -18,6 +18,7 @@ fn _audit_duplicate_element_id() { let mut valid = true; for x in &audit { + println!("{:?}", x); if x.code == "WCAGAAA.Principle4.Guideline4_1.F77" { valid = false; break;