Fix some more translation bugs

This commit is contained in:
Oliver Hamlet
2025-03-25 20:56:12 +00:00
parent 567998c159
commit 5e47e77ac5
4 changed files with 86 additions and 52 deletions
+6
View File
@@ -129,6 +129,7 @@ pub(super) enum MetadataParsingErrorReason {
UnexpectedType(ExpectedType, YamlObjectType),
UnexpectedValueType(&'static str, ExpectedType, YamlObjectType),
MissingPlaceholder(String, usize),
MissingSubstitution(String),
NonU32Number(i64),
DuplicateEntry(String, YamlObjectType),
Other(Box<saphyr::ScanError>),
@@ -164,6 +165,11 @@ impl std::fmt::Display for MetadataParsingErrorReason {
"failed to substitute \"{}\" into message, no placeholder {{{}}} was found",
sub, placeholder_index
),
Self::MissingSubstitution(placeholder) => write!(
f,
"failed to substitute a value into message, no substitution was given for the placeholder \"{}\"",
placeholder
),
Self::NonU32Number(i) => {
write!(f, "{} is not valid as a 32-bit unsigned integer", i)
}
+42
View File
@@ -1,5 +1,10 @@
use std::{borrow::Cow, sync::LazyLock};
use fancy_regex::{Captures, Regex};
use saphyr::{MarkedYaml, YamlData};
use crate::logging;
use super::{
error::{
ExpectedType, MetadataParsingErrorReason, MultilingualMessageContentsError,
@@ -308,9 +313,39 @@ impl TryFrom<&MarkedYaml> for Message {
let subs = get_strings_vec_value(hash, "subs", YamlObjectType::Message)?;
if !subs.is_empty() {
static FMT_REGEX: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"{(\d+)}").expect("hardcoded fmt placeholder regex should be valid")
});
for mc in &mut content {
if mc.text.contains("%1%") {
static BOOST_REGEX: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"%(\d+)%")
.expect("hardcoded Boost placeholder regex should be valid")
});
let result = BOOST_REGEX.replace_all(&mc.text, |captures: &Captures| {
match captures[1].parse::<u32>() {
Ok(i) if i > 0 => format!("{{{}}}", i - 1),
Ok(_) => {
logging::warn!("Found zero-indexed placeholder using Boost syntax in string \"{}\"", mc.text);
captures[0].to_string()
},
Err(e) => {
logging::error!("Unexpected failure to parse Boost placeholder index \"{}\": {}", &captures[1], e);
captures[0].to_string()
}
}
});
if let Cow::Owned(text) = result {
mc.text = text;
}
}
for (index, sub) in subs.iter().enumerate() {
let placeholder = format!("{{{}}}", index);
if !mc.text.contains(&placeholder) {
return Err(ParseMetadataError::new(
value.span.start,
@@ -320,6 +355,13 @@ impl TryFrom<&MarkedYaml> for Message {
mc.text = mc.text.replace(&placeholder, sub);
}
if let Ok(Some(m)) = FMT_REGEX.find(&mc.text) {
return Err(ParseMetadataError::new(
value.span.start,
MetadataParsingErrorReason::MissingSubstitution(m.as_str().to_string()),
));
}
}
}
+29 -29
View File
@@ -24,35 +24,6 @@ use error::{
PluginValidationErrorReason,
};
static VERSION_REGEXES: LazyLock<Box<[Regex]>> = LazyLock::new(|| {
// The string below matches the range of version strings supported by
// Pseudosem v1.0.1, excluding space separators, as they make version
// extraction from inside sentences very tricky and have not been seen "in
// the wild". The second non-capturing group prevents version numbers
// followed by a comma from matching.
let pseudosem_regex_str = r"(\d+(?:\.\d+)+(?:[-._:]?[A-Za-z0-9]+)*)(?!,)";
/* There are a few different version formats that can appear in strings
together, and in order to extract the correct one, they must be searched
for in order of priority. */
Box::new([
/* The string below matches timestamps that use forwardslashes for date
separators. However, Pseudosem v1.0.1 will only compare the first
two digits as it does not recognise forwardslashes as separators. */
Regex::new(r"(?i)(\d{1,2}/\d{1,2}/\d{1,4} \d{1,2}:\d{1,2}:\d{1,2})")
.expect("Hardcoded version timestamp regex should be valid"),
Regex::new(&format!(r"(?i)version:?\s{}", pseudosem_regex_str))
.expect("Hardcoded version-prefixed pseudosem version regex should be valid"),
Regex::new(&format!(r"(?i)(?:^|v|\s){}", pseudosem_regex_str))
.expect("Hardcoded pseudosem version regex should be valid"),
/* The string below matches a number containing one or more
digits found at the start of the search string or preceded by
'v' or 'version:. */
Regex::new(r"(?i)(?:^|v|version:\s*)(\d+)")
.expect("Hardcoded prefixed version number regex should be valid"),
])
});
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub(crate) enum LoadScope {
HeaderOnly,
@@ -462,6 +433,35 @@ fn extract_bash_tags(description: &str) -> Vec<String> {
}
fn extract_version(description: &str) -> Result<Option<String>, Box<fancy_regex::Error>> {
static VERSION_REGEXES: LazyLock<Box<[Regex]>> = LazyLock::new(|| {
// The string below matches the range of version strings supported by
// Pseudosem v1.0.1, excluding space separators, as they make version
// extraction from inside sentences very tricky and have not been seen "in
// the wild". The second non-capturing group prevents version numbers
// followed by a comma from matching.
let pseudosem_regex_str = r"(\d+(?:\.\d+)+(?:[-._:]?[A-Za-z0-9]+)*)(?!,)";
/* There are a few different version formats that can appear in strings
together, and in order to extract the correct one, they must be searched
for in order of priority. */
Box::new([
/* The string below matches timestamps that use forwardslashes for date
separators. However, Pseudosem v1.0.1 will only compare the first
two digits as it does not recognise forwardslashes as separators. */
Regex::new(r"(?i)(\d{1,2}/\d{1,2}/\d{1,4} \d{1,2}:\d{1,2}:\d{1,2})")
.expect("Hardcoded version timestamp regex should be valid"),
Regex::new(&format!(r"(?i)version:?\s{}", pseudosem_regex_str))
.expect("Hardcoded version-prefixed pseudosem version regex should be valid"),
Regex::new(&format!(r"(?i)(?:^|v|\s){}", pseudosem_regex_str))
.expect("Hardcoded pseudosem version regex should be valid"),
/* The string below matches a number containing one or more
digits found at the start of the search string or preceded by
'v' or 'version:. */
Regex::new(r"(?i)(?:^|v|version:\s*)(\d+)")
.expect("Hardcoded prefixed version number regex should be valid"),
])
});
for regex in &*VERSION_REGEXES {
let version = regex
.captures(description)?
+9 -23
View File
@@ -260,43 +260,29 @@ impl<'a, T: SortingPlugin> PluginsGraph<'a, T> {
return;
}
let mut early_loading_plugin_indices: HashMap<&str, NodeIndex> = HashMap::new();
let mut early_loader_indices = Vec::new();
let mut other_plugin_indices = Vec::new();
for node_index in self.node_indices() {
let plugin = &self[node_index];
if let Some(p) = early_loading_plugins
if let Some(i) = early_loading_plugins
.iter()
.find(|e| unicase::eq(e.as_str(), plugin.name()))
.position(|e| unicase::eq(e.as_str(), plugin.name()))
{
early_loading_plugin_indices.insert(p.as_str(), node_index);
early_loader_indices.push((i, node_index));
} else {
other_plugin_indices.push(node_index);
}
}
if early_loading_plugin_indices.is_empty() {
return;
}
early_loader_indices.sort_by_key(|e| e.0);
let mut last_early_loading_plugin_index = None;
for window in early_loading_plugins.windows(2) {
if let [from, to] = window {
let from_index = early_loading_plugin_indices.get(from.as_str());
let to_index = early_loading_plugin_indices.get(to.as_str());
if to_index.is_some() {
last_early_loading_plugin_index = to_index;
} else if from_index.is_some() {
last_early_loading_plugin_index = from_index;
}
if let (Some(from_index), Some(to_index)) = (from_index, to_index) {
self.add_edge(*from_index, *to_index, EdgeType::Hardcoded);
}
for window in early_loader_indices.windows(2) {
if let [(_, from_index), (_, to_index)] = window {
self.add_edge(*from_index, *to_index, EdgeType::Hardcoded);
}
}
if let Some(from_index) = last_early_loading_plugin_index {
if let Some((_, from_index)) = early_loader_indices.last() {
for to_index in other_plugin_indices {
self.add_edge(*from_index, to_index, EdgeType::Hardcoded);
}