game: ensure overwritten subtitle lines have the merge flag disabled (#4352)

Fixes another long-standing subtitle translation bug.

There is a `merge` flag on each subtitle line, the idea being that we
would merge in the text from the base game if this was set. However in
jak 2 and beyond:
- The subtitles for english (base) are not predefined for the cutscenes,
only the hints. The rest are in the game files and we do not
simultaneously load both languages when the game is running so there is
no trivial fallback path.
- However, every subtitle language by default inherits the base games
metadata, where all `merge` flags are set to `true`

This means that all custom cutscene translations were being ignored
unless this flag was set to false in the metadata file for each line.
This is what finnish does since it changes the number of lines and their
timings, and is why it works fine.

This flag can probably be completely removed, as per the above, it
serves no actual purpose. All it does in our code is if it's set, we
skip the line when writing out the subtitle file.

But for now i simply just iterate through and flip these flags
automatically if the language overrode the cutscene. Tested on
english/finnish/pt-BR
<img width="648" height="467" alt="image"
src="https://github.com/user-attachments/assets/292e3dfe-df66-4d23-942a-b41f2b157bf8"
/>
This commit is contained in:
Tyler Wilding
2026-07-22 00:00:57 -04:00
committed by GitHub
parent 0935ce4ffa
commit 02e9579fb5
2 changed files with 21 additions and 0 deletions
@@ -186,6 +186,24 @@ GameSubtitlePackage read_json_files_v2(const GameSubtitleDefinitionFile& file_in
"subtitle_line_path");
lang_lines = package.combined_lines;
}
// Update any line metadata to `merge = false` if they've been defined
// otherwise, the lines get skipped
for (const auto [scene_name, scene_lines] : lang_lines.cutscenes) {
if (package.combined_meta.cutscenes.find(scene_name) !=
package.combined_meta.cutscenes.end()) {
for (int i = 0; i < package.combined_meta.cutscenes[scene_name].lines.size(); i++) {
package.combined_meta.cutscenes[scene_name].lines[i].merge = false;
}
}
}
for (const auto [scene_name, scene_lines] : lang_lines.other) {
if (package.combined_meta.other.find(scene_name) != package.combined_meta.other.end()) {
for (int i = 0; i < package.combined_meta.other[scene_name].lines.size(); i++) {
package.combined_meta.other[scene_name].lines[i].merge = false;
}
}
}
for (const auto& [scene_name, scene_info] : lang_lines.cutscenes) {
package.scenes_defined_in_lang.insert(scene_name);
}
@@ -10,6 +10,9 @@ struct SubtitleLineMetadata {
int frame_end;
bool offscreen;
std::string speaker;
// NOTE: merge is a bad name, as we don't actually merge anything (the game doesn't load the
// english subtitles as well) and all this does if set is it's ignored when being written out to
// the file
bool merge;
bool operator==(const SubtitleLineMetadata& other) const {