mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Fix some more translation bugs
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user