mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-06 04:48:54 +08:00
Fix mulitiple languages support for scn script
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@
|
||||
/output
|
||||
/patched
|
||||
*.log
|
||||
.vscode/
|
||||
|
||||
@@ -207,6 +207,10 @@ pub struct Arg {
|
||||
/// Kirikiri chat message translation directory. All json files in this directory will be merged. (Only m3t files are supported.)
|
||||
pub kirikiri_chat_dir: Option<String>,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
#[arg(long, global = true, value_delimiter = ',')]
|
||||
/// Kirikiri language list. First language code is code for language index 1.
|
||||
pub kirikiri_languages: Option<Vec<String>>,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
#[arg(long, global = true, action = ArgAction::SetTrue, alias = "kr-no-empty-lines", alias = "kirikiri-no-empty-lines")]
|
||||
/// Remove empty lines in Kirikiri KS script.
|
||||
pub kirikiri_remove_empty_lines: bool,
|
||||
|
||||
@@ -1751,6 +1751,11 @@ fn main() {
|
||||
kirikiri_chat_json: args::load_kirikiri_chat_json(&arg)
|
||||
.expect("Failed to load Kirikiri chat JSON"),
|
||||
#[cfg(feature = "kirikiri")]
|
||||
kirikiri_languages: arg
|
||||
.kirikiri_languages
|
||||
.clone()
|
||||
.map(|s| std::sync::Arc::new(s)),
|
||||
#[cfg(feature = "kirikiri")]
|
||||
kirikiri_remove_empty_lines: arg.kirikiri_remove_empty_lines,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
kirikiri_name_commands: std::sync::Arc::new(std::collections::HashSet::from_iter(
|
||||
|
||||
@@ -110,6 +110,7 @@ impl ScriptBuilder for ScnScriptBuilder {
|
||||
pub struct ScnScript {
|
||||
psb: VirtualPsbFixed,
|
||||
language_index: usize,
|
||||
languages: Option<Arc<Vec<String>>>,
|
||||
export_chat: bool,
|
||||
filename: String,
|
||||
chat_key: Option<String>,
|
||||
@@ -145,6 +146,7 @@ impl ScnScript {
|
||||
Ok(Self {
|
||||
psb: psb.to_psb_fixed(),
|
||||
language_index: config.kirikiri_language_index.unwrap_or(0),
|
||||
languages: config.kirikiri_languages.clone(),
|
||||
export_chat: config.kirikiri_export_chat,
|
||||
filename: filename.to_string(),
|
||||
chat_key: config.kirikiri_chat_key.clone(),
|
||||
@@ -181,9 +183,36 @@ impl Script for ScnScript {
|
||||
PsbValueFixed::List(list) => list,
|
||||
_ => return Err(anyhow::anyhow!("scenes is not a list")),
|
||||
};
|
||||
let language = if self.language_index != 0 {
|
||||
let index = self.language_index - 1;
|
||||
if let Some(lang) = root["languages"][index].as_str() {
|
||||
Some(lang.to_owned())
|
||||
} else if let Some(languages) = self.languages.as_ref() {
|
||||
if index < languages.len() {
|
||||
eprintln!(
|
||||
"WARN: Language code not found in PSB, using from config. Chat messages may not be extracted correctly."
|
||||
);
|
||||
crate::COUNTER.inc_warning();
|
||||
Some(languages[index].to_owned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if self.language_index != 0 && language.is_none() {
|
||||
eprintln!(
|
||||
"WARN: Language index is set but language code not found in PSB. Chat messages may not be extracted correctly."
|
||||
);
|
||||
crate::COUNTER.inc_warning();
|
||||
}
|
||||
let mut comu = if self.export_chat {
|
||||
Some(ExportMes::new(
|
||||
self.chat_key.clone().unwrap_or("comumode".to_string()),
|
||||
language.clone(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
@@ -362,6 +391,29 @@ impl Script for ScnScript {
|
||||
let mut cur_mes = mes.next();
|
||||
let mut psb = self.psb.clone();
|
||||
let root = psb.root_mut();
|
||||
if let Some(lang) = &self.languages {
|
||||
let lang = (**lang).clone();
|
||||
root["languages"] = PsbValueFixed::List(PsbListFixed {
|
||||
values: lang
|
||||
.into_iter()
|
||||
.map(|s| PsbValueFixed::String(s.into()))
|
||||
.collect(),
|
||||
});
|
||||
}
|
||||
let language = if self.language_index != 0 {
|
||||
let index = self.language_index - 1;
|
||||
if let Some(lang) = root["languages"][index].as_str() {
|
||||
Some(lang.to_owned())
|
||||
} else {
|
||||
eprintln!(
|
||||
"WARN: language code not found in PSB. Some functions may not work correctly. Use --kirikiri-languages to specify language codes."
|
||||
);
|
||||
crate::COUNTER.inc_warning();
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let scenes = &mut root["scenes"];
|
||||
if !scenes.is_list() {
|
||||
return Err(anyhow::anyhow!("scenes is not an array"));
|
||||
@@ -371,6 +423,7 @@ impl Script for ScnScript {
|
||||
json,
|
||||
replacement,
|
||||
self.chat_key.clone().unwrap_or("comumode".to_string()),
|
||||
language.clone(),
|
||||
)
|
||||
});
|
||||
for (i, scene) in scenes.members_mut().enumerate() {
|
||||
@@ -421,7 +474,7 @@ impl Script for ScnScript {
|
||||
name = name.replace(key, value);
|
||||
}
|
||||
}
|
||||
if has_display_name {
|
||||
if has_display_name || self.language_index != 0 {
|
||||
text[1][self.language_index][0].set_string(name);
|
||||
} else {
|
||||
text[0].set_string(name);
|
||||
@@ -526,11 +579,15 @@ impl Script for ScnScript {
|
||||
name = name.replace(key, value);
|
||||
}
|
||||
}
|
||||
if has_display_name {
|
||||
if has_display_name || self.language_index != 0 {
|
||||
text[2][self.language_index][0]
|
||||
.set_string(name);
|
||||
} else {
|
||||
text[0].set_string(name);
|
||||
if text[1].is_string() {
|
||||
text[1].set_string(name);
|
||||
} else {
|
||||
text[0].set_string(name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
@@ -673,13 +730,15 @@ impl Script for ScnScript {
|
||||
struct ExportMes {
|
||||
pub messages: HashSet<String>,
|
||||
pub key: String,
|
||||
text_key: String,
|
||||
}
|
||||
|
||||
impl ExportMes {
|
||||
pub fn new(key: String) -> Self {
|
||||
pub fn new(key: String, language: Option<String>) -> Self {
|
||||
Self {
|
||||
messages: HashSet::new(),
|
||||
key: key,
|
||||
text_key: language.map_or_else(|| String::from("text"), |s| format!("text_{}", s)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,8 +750,10 @@ impl ExportMes {
|
||||
if let PsbValueFixed::List(list) = v {
|
||||
for item in list.iter() {
|
||||
if let PsbValueFixed::Object(obj) = item {
|
||||
if let Some(PsbValueFixed::String(s)) = obj.get_value("text") {
|
||||
self.messages.insert(s.string().replace("\\n", "\n"));
|
||||
if let Some(s) = obj[&self.text_key].as_str() {
|
||||
self.messages.insert(s.replace("\\n", "\n"));
|
||||
} else if let Some(s) = obj["text"].as_str() {
|
||||
self.messages.insert(s.replace("\\n", "\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -707,6 +768,19 @@ impl ExportMes {
|
||||
if list.len() > 1 {
|
||||
if let PsbValueFixed::String(s) = &list[0] {
|
||||
if s.string() == &self.key {
|
||||
for i in 1..list.len() {
|
||||
if let PsbValueFixed::String(s) = &list[i - 1] {
|
||||
if s.string() == &self.text_key {
|
||||
if let PsbValueFixed::String(text) = &list[i] {
|
||||
self.messages
|
||||
.insert(text.string().replace("\\n", "\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.text_key == "text" {
|
||||
return;
|
||||
}
|
||||
for i in 1..list.len() {
|
||||
if let PsbValueFixed::String(s) = &list[i - 1] {
|
||||
if s.string() == "text" {
|
||||
@@ -735,6 +809,7 @@ struct ImportMes<'a> {
|
||||
messages: &'a Arc<HashMap<String, String>>,
|
||||
replacement: Option<&'a ReplacementTable>,
|
||||
key: String,
|
||||
text_key: String,
|
||||
}
|
||||
|
||||
impl<'a> ImportMes<'a> {
|
||||
@@ -742,11 +817,13 @@ impl<'a> ImportMes<'a> {
|
||||
messages: &'a Arc<HashMap<String, String>>,
|
||||
replacement: Option<&'a ReplacementTable>,
|
||||
key: String,
|
||||
lang: Option<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
messages,
|
||||
replacement,
|
||||
key: key,
|
||||
text_key: lang.map_or_else(|| String::from("text"), |s| format!("text_{}", s)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,6 +833,23 @@ impl<'a> ImportMes<'a> {
|
||||
for (k, v) in obj.iter_mut() {
|
||||
if k == &self.key {
|
||||
for obj in v.members_mut() {
|
||||
if let Some(text) = obj[&self.text_key].as_str() {
|
||||
if let Some(replace_text) = self.messages.get(text) {
|
||||
let mut text = replace_text.clone();
|
||||
if let Some(replacement) = self.replacement {
|
||||
for (key, value) in replacement.map.iter() {
|
||||
text = text.replace(key, value);
|
||||
}
|
||||
}
|
||||
obj[&self.text_key].set_string(text.replace("\n", "\\n"));
|
||||
} else {
|
||||
eprintln!(
|
||||
"Warning: chat message '{}' not found in translation table.",
|
||||
text
|
||||
);
|
||||
crate::COUNTER.inc_warning();
|
||||
}
|
||||
}
|
||||
if let Some(text) = obj["text"].as_str() {
|
||||
if let Some(replace_text) = self.messages.get(text) {
|
||||
let mut text = replace_text.clone();
|
||||
@@ -764,7 +858,7 @@ impl<'a> ImportMes<'a> {
|
||||
text = text.replace(key, value);
|
||||
}
|
||||
}
|
||||
obj["text"].set_string(text.replace("\n", "\\n"));
|
||||
obj[&self.text_key].set_string(text.replace("\n", "\\n"));
|
||||
} else {
|
||||
eprintln!(
|
||||
"Warning: chat message '{}' not found in translation table.",
|
||||
@@ -783,7 +877,7 @@ impl<'a> ImportMes<'a> {
|
||||
if list.len() > 1 {
|
||||
if list[0] == self.key {
|
||||
for i in 1..list.len() {
|
||||
if list[i - 1] == "text" {
|
||||
if list[i - 1] == self.text_key {
|
||||
if let Some(text) = list[i].as_str() {
|
||||
if let Some(replace_text) = self.messages.get(text) {
|
||||
let mut text = replace_text.clone();
|
||||
@@ -803,6 +897,33 @@ impl<'a> ImportMes<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.text_key == "text" {
|
||||
return;
|
||||
}
|
||||
for i in 1..list.len() {
|
||||
if list[i - 1] == "text" {
|
||||
if let Some(text) = list[i].as_str() {
|
||||
if let Some(replace_text) = self.messages.get(text) {
|
||||
let mut text = replace_text.clone();
|
||||
if let Some(replacement) = self.replacement {
|
||||
for (key, value) in replacement.map.iter() {
|
||||
text = text.replace(key, value);
|
||||
}
|
||||
}
|
||||
let len = list.len();
|
||||
list[len].set_str(&self.text_key);
|
||||
list[len + 1].set_string(text.replace("\n", "\\n"));
|
||||
return;
|
||||
} else {
|
||||
eprintln!(
|
||||
"Warning: chat message '{}' not found in translation table.",
|
||||
text
|
||||
);
|
||||
crate::COUNTER.inc_warning();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,6 +274,9 @@ pub struct ExtraConfig {
|
||||
/// Kirikiri chat message translation. key is original text, value is translated text.
|
||||
pub kirikiri_chat_json: Option<std::sync::Arc<HashMap<String, String>>>,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
/// Kirikiri language list. First language code is code for language index 1.
|
||||
pub kirikiri_languages: Option<std::sync::Arc<Vec<String>>>,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
/// Remove empty lines in Kirikiri KS script.
|
||||
pub kirikiri_remove_empty_lines: bool,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
|
||||
Reference in New Issue
Block a user