You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
661 lines
24 KiB
661 lines
24 KiB
6 months ago
|
@tool
|
||
|
extends DialogicSettingsPage
|
||
|
|
||
|
## Settings tab that allows enabeling and updating translation csv-files.
|
||
|
|
||
|
|
||
|
enum TranslationModes {PER_PROJECT, PER_TIMELINE, NONE}
|
||
|
enum SaveLocationModes {INSIDE_TRANSLATION_FOLDER, NEXT_TO_TIMELINE, NONE}
|
||
|
|
||
|
var loading := false
|
||
|
@onready var settings_editor :Control = find_parent('Settings')
|
||
|
|
||
|
## The default CSV filename that contains the translations for character
|
||
|
## properties.
|
||
|
const DEFAULT_CHARACTER_CSV_NAME := "dialogic_character_translations.csv"
|
||
|
## The default CSV filename that contains the translations for timelines.
|
||
|
## Only used when all timelines are supposed to be translated in one file.
|
||
|
const DEFAULT_TIMELINE_CSV_NAME := "dialogic_timeline_translations.csv"
|
||
|
|
||
|
const DEFAULT_GLOSSARY_CSV_NAME := "dialogic_glossary_translations.csv"
|
||
|
|
||
|
const _USED_LOCALES_SETTING := "dialogic/translation/locales"
|
||
|
|
||
|
## Contains translation changes that were made during the last update.
|
||
|
|
||
|
## Unique locales that will be set after updating the CSV files.
|
||
|
var _unique_locales := []
|
||
|
|
||
|
func _get_icon() -> Texture2D:
|
||
|
return get_theme_icon("Translation", "EditorIcons")
|
||
|
|
||
|
|
||
|
func _is_feature_tab() -> bool:
|
||
|
return true
|
||
|
|
||
|
|
||
|
func _ready() -> void:
|
||
|
%TransEnabled.toggled.connect(store_changes)
|
||
|
%OrigLocale.get_suggestions_func = get_locales
|
||
|
%OrigLocale.resource_icon = get_theme_icon("Translation", "EditorIcons")
|
||
|
%OrigLocale.value_changed.connect(store_changes)
|
||
|
%TestingLocale.get_suggestions_func = get_locales
|
||
|
%TestingLocale.resource_icon = get_theme_icon("Translation", "EditorIcons")
|
||
|
%TestingLocale.value_changed.connect(store_changes)
|
||
|
%TransFolderPicker.value_changed.connect(store_changes)
|
||
|
%AddSeparatorEnabled.toggled.connect(store_changes)
|
||
|
|
||
|
%SaveLocationMode.item_selected.connect(store_changes)
|
||
|
%TransMode.item_selected.connect(store_changes)
|
||
|
|
||
|
%UpdateCsvFiles.pressed.connect(_on_update_translations_pressed)
|
||
|
%UpdateCsvFiles.icon = get_theme_icon("Add", "EditorIcons")
|
||
|
|
||
|
%CollectTranslations.pressed.connect(collect_translations)
|
||
|
%CollectTranslations.icon = get_theme_icon("File", "EditorIcons")
|
||
|
|
||
|
%TransRemove.pressed.connect(_on_erase_translations_pressed)
|
||
|
%TransRemove.icon = get_theme_icon("Remove", "EditorIcons")
|
||
|
|
||
|
%UpdateConfirmationDialog.add_button("Keep old & Generate new", false, "generate_new")
|
||
|
|
||
|
%UpdateConfirmationDialog.custom_action.connect(_on_custom_action)
|
||
|
|
||
|
_verify_translation_file()
|
||
|
|
||
|
|
||
|
func _on_custom_action(action: String) -> void:
|
||
|
if action == "generate_new":
|
||
|
update_csv_files()
|
||
|
|
||
|
|
||
|
func _refresh() -> void:
|
||
|
loading = true
|
||
|
|
||
|
%TransEnabled.button_pressed = ProjectSettings.get_setting('dialogic/translation/enabled', false)
|
||
|
%TranslationSettings.visible = %TransEnabled.button_pressed
|
||
|
%OrigLocale.set_value(ProjectSettings.get_setting('dialogic/translation/original_locale', TranslationServer.get_tool_locale()))
|
||
|
%TransMode.select(ProjectSettings.get_setting('dialogic/translation/file_mode', 1))
|
||
|
%TransFolderPicker.set_value(ProjectSettings.get_setting('dialogic/translation/translation_folder', ''))
|
||
|
%TestingLocale.set_value(ProjectSettings.get_setting('internationalization/locale/test', ''))
|
||
|
%AddSeparatorEnabled.button_pressed = ProjectSettings.get_setting('dialogic/translation/add_separator', false)
|
||
|
|
||
|
_verify_translation_file()
|
||
|
|
||
|
loading = false
|
||
|
|
||
|
|
||
|
func store_changes(_fake_arg: Variant = null, _fake_arg2: Variant = null) -> void:
|
||
|
if loading:
|
||
|
return
|
||
|
|
||
|
_verify_translation_file()
|
||
|
|
||
|
ProjectSettings.set_setting('dialogic/translation/enabled', %TransEnabled.button_pressed)
|
||
|
%TranslationSettings.visible = %TransEnabled.button_pressed
|
||
|
ProjectSettings.set_setting('dialogic/translation/original_locale', %OrigLocale.current_value)
|
||
|
ProjectSettings.set_setting('dialogic/translation/file_mode', %TransMode.selected)
|
||
|
ProjectSettings.set_setting('dialogic/translation/translation_folder', %TransFolderPicker.current_value)
|
||
|
ProjectSettings.set_setting('internationalization/locale/test', %TestingLocale.current_value)
|
||
|
ProjectSettings.set_setting('dialogic/translation/save_mode', %SaveLocationMode.selected)
|
||
|
ProjectSettings.set_setting('dialogic/translation/add_separator', %AddSeparatorEnabled.button_pressed)
|
||
|
ProjectSettings.save()
|
||
|
|
||
|
|
||
|
## Checks whether the translation folder path is required.
|
||
|
## If it is, disables the "Update CSV files" button and shows a warning.
|
||
|
##
|
||
|
## The translation folder path is required when either of the following is true:
|
||
|
## - The translation mode is set to "Per Project".
|
||
|
## - The save location mode is set to "Inside Translation Folder".
|
||
|
func _verify_translation_file() -> void:
|
||
|
var translation_folder: String = %TransFolderPicker.current_value
|
||
|
var file_mode: TranslationModes = %TransMode.selected
|
||
|
|
||
|
if file_mode == TranslationModes.PER_PROJECT:
|
||
|
%SaveLocationMode.disabled = true
|
||
|
else:
|
||
|
%SaveLocationMode.disabled = false
|
||
|
|
||
|
var valid_translation_folder := (!translation_folder.is_empty()
|
||
|
and DirAccess.dir_exists_absolute(translation_folder))
|
||
|
|
||
|
%UpdateCsvFiles.disabled = not valid_translation_folder
|
||
|
|
||
|
var status_message := ""
|
||
|
|
||
|
if not valid_translation_folder:
|
||
|
status_message += "⛔ Requires valid translation folder to translate character names"
|
||
|
|
||
|
if file_mode == TranslationModes.PER_PROJECT:
|
||
|
status_message += " and the project CSV file."
|
||
|
else:
|
||
|
status_message += "."
|
||
|
|
||
|
%StatusMessage.text = status_message
|
||
|
|
||
|
|
||
|
func get_locales(_filter: String) -> Dictionary:
|
||
|
var suggestions := {}
|
||
|
suggestions['Default'] = {'value':'', 'tooltip':"Will use the fallback locale set in the project settings."}
|
||
|
suggestions[TranslationServer.get_tool_locale()] = {'value':TranslationServer.get_tool_locale()}
|
||
|
|
||
|
var used_locales: Array = ProjectSettings.get_setting(_USED_LOCALES_SETTING, TranslationServer.get_all_languages())
|
||
|
|
||
|
for locale: String in used_locales:
|
||
|
var language_name := TranslationServer.get_language_name(locale)
|
||
|
|
||
|
# Invalid locales return an empty String.
|
||
|
if language_name.is_empty():
|
||
|
continue
|
||
|
|
||
|
suggestions[locale] = { 'value': locale, 'tooltip': language_name }
|
||
|
|
||
|
return suggestions
|
||
|
|
||
|
|
||
|
func _on_update_translations_pressed() -> void:
|
||
|
var save_mode: SaveLocationModes = %SaveLocationMode.selected
|
||
|
var file_mode: TranslationModes = %TransMode.selected
|
||
|
var translation_folder: String = %TransFolderPicker.current_value
|
||
|
|
||
|
var old_save_mode: SaveLocationModes = ProjectSettings.get_setting('dialogic/translation/intern/save_mode', save_mode)
|
||
|
var old_file_mode: TranslationModes = ProjectSettings.get_setting('dialogic/translation/intern/file_mode', file_mode)
|
||
|
var old_translation_folder: String = ProjectSettings.get_setting('dialogic/translation/intern/translation_folder', translation_folder)
|
||
|
|
||
|
if (old_save_mode == save_mode
|
||
|
and old_file_mode == file_mode
|
||
|
and old_translation_folder == translation_folder):
|
||
|
update_csv_files()
|
||
|
return
|
||
|
|
||
|
%UpdateConfirmationDialog.popup_centered()
|
||
|
|
||
|
|
||
|
## Used by the dialog to inform that the settings were changed.
|
||
|
func _delete_and_update() -> void:
|
||
|
erase_translations()
|
||
|
update_csv_files()
|
||
|
|
||
|
|
||
|
## Creates or updates the glossary CSV files.
|
||
|
func _handle_glossary_translation(
|
||
|
csv_data: CsvUpdateData,
|
||
|
save_location_mode: SaveLocationModes,
|
||
|
translation_mode: TranslationModes,
|
||
|
translation_folder_path: String,
|
||
|
orig_locale: String) -> void:
|
||
|
|
||
|
var glossary_csv: DialogicCsvFile = null
|
||
|
var glossary_paths: Array = ProjectSettings.get_setting('dialogic/glossary/glossary_files', [])
|
||
|
var add_separator_lines: bool = ProjectSettings.get_setting('dialogic/translation/add_separator', false)
|
||
|
|
||
|
for glossary_path: String in glossary_paths:
|
||
|
|
||
|
if glossary_csv == null:
|
||
|
var csv_name := ""
|
||
|
|
||
|
# Get glossary CSV file name.
|
||
|
match translation_mode:
|
||
|
TranslationModes.PER_PROJECT:
|
||
|
csv_name = DEFAULT_GLOSSARY_CSV_NAME
|
||
|
|
||
|
TranslationModes.PER_TIMELINE:
|
||
|
var glossary_name: String = glossary_path.trim_suffix('.tres')
|
||
|
var path_parts := glossary_name.split("/")
|
||
|
var file_name := path_parts[-1]
|
||
|
csv_name = "dialogic_" + file_name + '_translation.csv'
|
||
|
|
||
|
var glossary_csv_path := ""
|
||
|
# Get glossary CSV file path.
|
||
|
match save_location_mode:
|
||
|
SaveLocationModes.INSIDE_TRANSLATION_FOLDER:
|
||
|
glossary_csv_path = translation_folder_path.path_join(csv_name)
|
||
|
|
||
|
SaveLocationModes.NEXT_TO_TIMELINE:
|
||
|
glossary_csv_path = glossary_path.get_base_dir().path_join(csv_name)
|
||
|
|
||
|
# Create or update glossary CSV file.
|
||
|
glossary_csv = DialogicCsvFile.new(glossary_csv_path, orig_locale, add_separator_lines)
|
||
|
|
||
|
if (glossary_csv.is_new_file):
|
||
|
csv_data.new_glossaries += 1
|
||
|
else:
|
||
|
csv_data.updated_glossaries += 1
|
||
|
|
||
|
var glossary: DialogicGlossary = load(glossary_path)
|
||
|
glossary_csv.collect_lines_from_glossary(glossary)
|
||
|
glossary_csv.add_translation_keys_to_glossary(glossary)
|
||
|
ResourceSaver.save(glossary)
|
||
|
|
||
|
#If per-file mode is used, save this csv and begin a new one
|
||
|
if translation_mode == TranslationModes.PER_TIMELINE:
|
||
|
glossary_csv.update_csv_file_on_disk()
|
||
|
glossary_csv = null
|
||
|
|
||
|
# If a Per-Project glossary is still open, we need to save it.
|
||
|
if glossary_csv != null:
|
||
|
glossary_csv.update_csv_file_on_disk()
|
||
|
glossary_csv = null
|
||
|
|
||
|
|
||
|
## Keeps information about the amount of new and updated CSV rows and what
|
||
|
## resources were populated with translation IDs.
|
||
|
## The final data can be used to display a status message.
|
||
|
class CsvUpdateData:
|
||
|
var new_events := 0
|
||
|
var updated_events := 0
|
||
|
|
||
|
var new_timelines := 0
|
||
|
var updated_timelines := 0
|
||
|
|
||
|
var new_names := 0
|
||
|
var updated_names := 0
|
||
|
|
||
|
var new_glossaries := 0
|
||
|
var updated_glossaries := 0
|
||
|
|
||
|
var new_glossary_entries := 0
|
||
|
var updated_glossary_entries := 0
|
||
|
|
||
|
|
||
|
func update_csv_files() -> void:
|
||
|
_unique_locales = []
|
||
|
var orig_locale: String = ProjectSettings.get_setting('dialogic/translation/original_locale', '').strip_edges()
|
||
|
var save_location_mode: SaveLocationModes = ProjectSettings.get_setting('dialogic/translation/save_mode', SaveLocationModes.NEXT_TO_TIMELINE)
|
||
|
var translation_mode: TranslationModes = ProjectSettings.get_setting('dialogic/translation/file_mode', TranslationModes.PER_PROJECT)
|
||
|
var translation_folder_path: String = ProjectSettings.get_setting('dialogic/translation/translation_folder', 'res://')
|
||
|
var add_separator_lines: bool = ProjectSettings.get_setting('dialogic/translation/add_separator', false)
|
||
|
|
||
|
var csv_data := CsvUpdateData.new()
|
||
|
|
||
|
if orig_locale.is_empty():
|
||
|
orig_locale = ProjectSettings.get_setting('internationalization/locale/fallback')
|
||
|
|
||
|
ProjectSettings.set_setting('dialogic/translation/intern/save_mode', save_location_mode)
|
||
|
ProjectSettings.set_setting('dialogic/translation/intern/file_mode', translation_mode)
|
||
|
ProjectSettings.set_setting('dialogic/translation/intern/translation_folder', translation_folder_path)
|
||
|
|
||
|
var current_timeline := _close_active_timeline()
|
||
|
|
||
|
var csv_per_project: DialogicCsvFile = null
|
||
|
var per_project_csv_path := translation_folder_path.path_join(DEFAULT_TIMELINE_CSV_NAME)
|
||
|
|
||
|
if translation_mode == TranslationModes.PER_PROJECT:
|
||
|
csv_per_project = DialogicCsvFile.new(per_project_csv_path, orig_locale, add_separator_lines)
|
||
|
|
||
|
if (csv_per_project.is_new_file):
|
||
|
csv_data.new_timelines += 1
|
||
|
else:
|
||
|
csv_data.updated_timelines += 1
|
||
|
|
||
|
# Iterate over all timelines.
|
||
|
# Create or update CSV files.
|
||
|
# Transform the timeline into translatable lines and collect into the CSV file.
|
||
|
for timeline_path: String in DialogicResourceUtil.list_resources_of_type('.dtl'):
|
||
|
var csv_file: DialogicCsvFile = csv_per_project
|
||
|
|
||
|
# Swap the CSV file to the Per Timeline one.
|
||
|
if translation_mode == TranslationModes.PER_TIMELINE:
|
||
|
var per_timeline_path: String = timeline_path.trim_suffix('.dtl')
|
||
|
var path_parts := per_timeline_path.split("/")
|
||
|
var timeline_name: String = path_parts[-1]
|
||
|
|
||
|
# Adjust the file path to the translation location mode.
|
||
|
if save_location_mode == SaveLocationModes.INSIDE_TRANSLATION_FOLDER:
|
||
|
var prefixed_timeline_name := "dialogic_" + timeline_name
|
||
|
per_timeline_path = translation_folder_path.path_join(prefixed_timeline_name)
|
||
|
|
||
|
|
||
|
per_timeline_path += '_translation.csv'
|
||
|
csv_file = DialogicCsvFile.new(per_timeline_path, orig_locale, false)
|
||
|
csv_data.new_timelines += 1
|
||
|
|
||
|
# Load and process timeline, turn events into resources.
|
||
|
var timeline: DialogicTimeline = load(timeline_path)
|
||
|
|
||
|
if timeline.events.size() == 0:
|
||
|
print_rich("[color=yellow]Empty timeline, skipping: " + timeline_path + "[/color]")
|
||
|
continue
|
||
|
|
||
|
timeline.process()
|
||
|
|
||
|
# Collect timeline into CSV.
|
||
|
csv_file.collect_lines_from_timeline(timeline)
|
||
|
|
||
|
# in case new translation_id's were added, we save the timeline again
|
||
|
timeline.set_meta("timeline_not_saved", true)
|
||
|
ResourceSaver.save(timeline, timeline_path)
|
||
|
|
||
|
if translation_mode == TranslationModes.PER_TIMELINE:
|
||
|
csv_file.update_csv_file_on_disk()
|
||
|
|
||
|
csv_data.new_events += csv_file.new_rows
|
||
|
csv_data.updated_events += csv_file.updated_rows
|
||
|
|
||
|
_handle_glossary_translation(
|
||
|
csv_data,
|
||
|
save_location_mode,
|
||
|
translation_mode,
|
||
|
translation_folder_path,
|
||
|
orig_locale
|
||
|
)
|
||
|
|
||
|
_handle_character_names(
|
||
|
csv_data,
|
||
|
orig_locale,
|
||
|
translation_folder_path,
|
||
|
add_separator_lines
|
||
|
)
|
||
|
|
||
|
if translation_mode == TranslationModes.PER_PROJECT:
|
||
|
csv_per_project.update_csv_file_on_disk()
|
||
|
|
||
|
_silently_open_timeline(current_timeline)
|
||
|
|
||
|
# Trigger reimport.
|
||
|
find_parent('EditorView').plugin_reference.get_editor_interface().get_resource_filesystem().scan_sources()
|
||
|
|
||
|
var status_message := "Events created {new_events} found {updated_events}
|
||
|
Names created {new_names} found {updated_names}
|
||
|
CSVs created {new_timelines} found {updated_timelines}
|
||
|
Glossary created {new_glossaries} found {updated_glossaries}
|
||
|
Entries created {new_glossary_entries} found {updated_glossary_entries}"
|
||
|
|
||
|
var status_message_args := {
|
||
|
'new_events': csv_data.new_events,
|
||
|
'updated_events': csv_data.updated_events,
|
||
|
'new_timelines': csv_data.new_timelines,
|
||
|
'updated_timelines': csv_data.updated_timelines,
|
||
|
'new_glossaries': csv_data.new_glossaries,
|
||
|
'updated_glossaries': csv_data.updated_glossaries,
|
||
|
'new_names': csv_data.new_names,
|
||
|
'updated_names': csv_data.updated_names,
|
||
|
'new_glossary_entries': csv_data.new_glossary_entries,
|
||
|
'updated_glossary_entries': csv_data.updated_glossary_entries,
|
||
|
}
|
||
|
|
||
|
%StatusMessage.text = status_message.format(status_message_args)
|
||
|
ProjectSettings.set_setting(_USED_LOCALES_SETTING, _unique_locales)
|
||
|
|
||
|
|
||
|
## Iterates over all character resource files and creates or updates CSV files
|
||
|
## that contain the translations for character properties.
|
||
|
## This will save each character resource file to disk.
|
||
|
func _handle_character_names(
|
||
|
csv_data: CsvUpdateData,
|
||
|
original_locale: String,
|
||
|
translation_folder_path: String,
|
||
|
add_separator_lines: bool) -> void:
|
||
|
var names_csv_path := translation_folder_path.path_join(DEFAULT_CHARACTER_CSV_NAME)
|
||
|
var character_name_csv: DialogicCsvFile = DialogicCsvFile.new(names_csv_path,
|
||
|
original_locale,
|
||
|
add_separator_lines
|
||
|
)
|
||
|
|
||
|
var all_characters := {}
|
||
|
|
||
|
for character_path: String in DialogicResourceUtil.list_resources_of_type('.dch'):
|
||
|
var character: DialogicCharacter = load(character_path)
|
||
|
|
||
|
if character._translation_id.is_empty():
|
||
|
csv_data.new_names += 1
|
||
|
|
||
|
else:
|
||
|
csv_data.updated_names += 1
|
||
|
|
||
|
var translation_id := character.get_set_translation_id()
|
||
|
all_characters[translation_id] = character
|
||
|
|
||
|
ResourceSaver.save(character)
|
||
|
|
||
|
character_name_csv.collect_lines_from_characters(all_characters)
|
||
|
character_name_csv.update_csv_file_on_disk()
|
||
|
|
||
|
|
||
|
func collect_translations() -> void:
|
||
|
var translation_files := []
|
||
|
var translation_mode: TranslationModes = ProjectSettings.get_setting('dialogic/translation/file_mode', TranslationModes.PER_PROJECT)
|
||
|
|
||
|
if translation_mode == TranslationModes.PER_TIMELINE:
|
||
|
|
||
|
for timeline_path: String in DialogicResourceUtil.list_resources_of_type('.translation'):
|
||
|
|
||
|
for file: String in DialogicUtil.listdir(timeline_path.get_base_dir()):
|
||
|
file = timeline_path.get_base_dir().path_join(file)
|
||
|
|
||
|
if file.ends_with('.translation'):
|
||
|
|
||
|
if not file in translation_files:
|
||
|
translation_files.append(file)
|
||
|
|
||
|
if translation_mode == TranslationModes.PER_PROJECT:
|
||
|
var translation_folder: String = ProjectSettings.get_setting('dialogic/translation/translation_folder', 'res://')
|
||
|
|
||
|
for file: String in DialogicUtil.listdir(translation_folder):
|
||
|
file = translation_folder.path_join(file)
|
||
|
|
||
|
if file.ends_with('.translation'):
|
||
|
|
||
|
if not file in translation_files:
|
||
|
translation_files.append(file)
|
||
|
|
||
|
var all_translation_files: Array = ProjectSettings.get_setting('internationalization/locale/translations', [])
|
||
|
var orig_file_amount := len(all_translation_files)
|
||
|
|
||
|
# This array keeps track of valid translation file paths.
|
||
|
var found_file_paths := []
|
||
|
var removed_translation_files := 0
|
||
|
|
||
|
for file_path: String in translation_files:
|
||
|
# If the file path is not valid, we must clean it up.
|
||
|
if ResourceLoader.exists(file_path):
|
||
|
found_file_paths.append(file_path)
|
||
|
else:
|
||
|
removed_translation_files += 1
|
||
|
continue
|
||
|
|
||
|
if not file_path in all_translation_files:
|
||
|
all_translation_files.append(file_path)
|
||
|
|
||
|
var path_without_suffix := file_path.trim_suffix('.translation')
|
||
|
var locale_part := path_without_suffix.split(".")[-1]
|
||
|
_collect_locale(locale_part)
|
||
|
|
||
|
|
||
|
var valid_translation_files := PackedStringArray(all_translation_files)
|
||
|
ProjectSettings.set_setting('internationalization/locale/translations', valid_translation_files)
|
||
|
ProjectSettings.save()
|
||
|
|
||
|
%StatusMessage.text = (
|
||
|
"Added translation files: " + str(len(all_translation_files)-orig_file_amount)
|
||
|
+ "\nRemoved translation files: " + str(removed_translation_files)
|
||
|
+ "\nTotal translation files: " + str(len(all_translation_files)))
|
||
|
|
||
|
|
||
|
func _on_erase_translations_pressed() -> void:
|
||
|
%EraseConfirmationDialog.popup_centered()
|
||
|
|
||
|
|
||
|
## Deletes translation files generated by [param csv_name].
|
||
|
## The [param csv_name] may not contain the file extension (.csv).
|
||
|
##
|
||
|
## Returns a vector, value 1 is amount of deleted translation files.
|
||
|
## Value
|
||
|
func delete_translations_files(translation_files: Array, csv_name: String) -> int:
|
||
|
var deleted_files := 0
|
||
|
|
||
|
for file_path: String in DialogicResourceUtil.list_resources_of_type('.translation'):
|
||
|
var base_name: String = file_path.get_basename()
|
||
|
var path_parts := base_name.split("/")
|
||
|
var translation_name: String = path_parts[-1]
|
||
|
|
||
|
if translation_name.begins_with(csv_name):
|
||
|
|
||
|
if OK == DirAccess.remove_absolute(file_path):
|
||
|
var project_translation_file_index := translation_files.find(file_path)
|
||
|
|
||
|
if project_translation_file_index > -1:
|
||
|
translation_files.remove_at(project_translation_file_index)
|
||
|
|
||
|
deleted_files += 1
|
||
|
print_rich("[color=green]Deleted translation file: " + file_path + "[/color]")
|
||
|
else:
|
||
|
print_rich("[color=yellow]Failed to delete translation file: " + file_path + "[/color]")
|
||
|
|
||
|
|
||
|
return deleted_files
|
||
|
|
||
|
|
||
|
## Iterates over all timelines and deletes their CSVs and timeline
|
||
|
## translation IDs.
|
||
|
## Deletes the Per-Project CSV file and the character name CSV file.
|
||
|
func erase_translations() -> void:
|
||
|
var files: PackedStringArray = ProjectSettings.get_setting('internationalization/locale/translations', [])
|
||
|
var translation_files := Array(files)
|
||
|
ProjectSettings.set_setting(_USED_LOCALES_SETTING, [])
|
||
|
|
||
|
var deleted_csv_files := 0
|
||
|
var deleted_translation_files := 0
|
||
|
var cleaned_timelines := 0
|
||
|
var cleaned_characters := 0
|
||
|
var cleaned_events := 0
|
||
|
var cleaned_glossaries := 0
|
||
|
|
||
|
var current_timeline := _close_active_timeline()
|
||
|
|
||
|
# Delete all Dialogic CSV files and their translation files.
|
||
|
for csv_path: String in DialogicResourceUtil.list_resources_of_type(".csv"):
|
||
|
var csv_path_parts: PackedStringArray = csv_path.split("/")
|
||
|
var csv_name: String = csv_path_parts[-1].trim_suffix(".csv")
|
||
|
|
||
|
# Handle Dialogic CSVs only.
|
||
|
if not csv_name.begins_with("dialogic_"):
|
||
|
continue
|
||
|
|
||
|
# Delete the CSV file.
|
||
|
if OK == DirAccess.remove_absolute(csv_path):
|
||
|
deleted_csv_files += 1
|
||
|
print_rich("[color=green]Deleted CSV file: " + csv_path + "[/color]")
|
||
|
|
||
|
deleted_translation_files += delete_translations_files(translation_files, csv_name)
|
||
|
else:
|
||
|
print_rich("[color=yellow]Failed to delete CSV file: " + csv_path + "[/color]")
|
||
|
|
||
|
# Clean timelines.
|
||
|
for timeline_path: String in DialogicResourceUtil.list_resources_of_type(".dtl"):
|
||
|
|
||
|
# Process the timeline.
|
||
|
var timeline: DialogicTimeline = load(timeline_path)
|
||
|
timeline.process()
|
||
|
cleaned_timelines += 1
|
||
|
|
||
|
# Remove event translation IDs.
|
||
|
for event: DialogicEvent in timeline.events:
|
||
|
|
||
|
if event._translation_id and not event._translation_id.is_empty():
|
||
|
event.remove_translation_id()
|
||
|
event.update_text_version()
|
||
|
cleaned_events += 1
|
||
|
|
||
|
if "character" in event:
|
||
|
# Remove character translation IDs.
|
||
|
var character: DialogicCharacter = event.character
|
||
|
|
||
|
if character != null and not character._translation_id.is_empty():
|
||
|
character.remove_translation_id()
|
||
|
cleaned_characters += 1
|
||
|
|
||
|
timeline.set_meta("timeline_not_saved", true)
|
||
|
ResourceSaver.save(timeline, timeline_path)
|
||
|
|
||
|
_erase_glossary_translation_ids()
|
||
|
_erase_character_name_translation_ids()
|
||
|
|
||
|
ProjectSettings.set_setting('dialogic/translation/id_counter', 16)
|
||
|
ProjectSettings.set_setting('internationalization/locale/translations', PackedStringArray(translation_files))
|
||
|
ProjectSettings.save()
|
||
|
|
||
|
find_parent('EditorView').plugin_reference.get_editor_interface().get_resource_filesystem().scan_sources()
|
||
|
|
||
|
var status_message := "Timelines cleaned {cleaned_timelines}
|
||
|
Events cleaned {cleaned_events}
|
||
|
Characters cleaned {cleaned_characters}
|
||
|
Glossaries cleaned {cleaned_glossaries}
|
||
|
|
||
|
CSVs erased {erased_csv_files}
|
||
|
Translations erased {erased_translation_files}"
|
||
|
|
||
|
var status_message_args := {
|
||
|
'cleaned_timelines': cleaned_timelines,
|
||
|
'cleaned_characters': cleaned_characters,
|
||
|
'cleaned_events': cleaned_events,
|
||
|
'cleaned_glossaries': cleaned_glossaries,
|
||
|
'erased_csv_files': deleted_csv_files,
|
||
|
'erased_translation_files': deleted_translation_files,
|
||
|
}
|
||
|
|
||
|
_silently_open_timeline(current_timeline)
|
||
|
|
||
|
# Trigger reimport.
|
||
|
find_parent('EditorView').plugin_reference.get_editor_interface().get_resource_filesystem().scan_sources()
|
||
|
|
||
|
# Clear the internal settings.
|
||
|
ProjectSettings.clear('dialogic/translation/intern/save_mode')
|
||
|
ProjectSettings.clear('dialogic/translation/intern/file_mode')
|
||
|
ProjectSettings.clear('dialogic/translation/intern/translation_folder')
|
||
|
|
||
|
_verify_translation_file()
|
||
|
%StatusMessage.text = status_message.format(status_message_args)
|
||
|
|
||
|
|
||
|
func _erase_glossary_translation_ids() -> void:
|
||
|
# Clean glossary.
|
||
|
var glossary_paths: Array = ProjectSettings.get_setting('dialogic/glossary/glossary_files', [])
|
||
|
|
||
|
for glossary_path: String in glossary_paths:
|
||
|
var glossary: DialogicGlossary = load(glossary_path)
|
||
|
glossary.remove_translation_id()
|
||
|
glossary.remove_entry_translation_ids()
|
||
|
glossary.clear_translation_keys()
|
||
|
ResourceSaver.save(glossary, glossary_path)
|
||
|
print_rich("[color=green]Cleaned up glossary file: " + glossary_path + "[/color]")
|
||
|
|
||
|
|
||
|
func _erase_character_name_translation_ids() -> void:
|
||
|
for character_path: String in DialogicResourceUtil.list_resources_of_type('.dch'):
|
||
|
var character: DialogicCharacter = load(character_path)
|
||
|
|
||
|
character.remove_translation_id()
|
||
|
ResourceSaver.save(character)
|
||
|
|
||
|
|
||
|
## Closes the current timeline in the Dialogic Editor and returns the timeline
|
||
|
## as a resource.
|
||
|
## If no timeline has been opened, returns null.
|
||
|
func _close_active_timeline() -> Resource:
|
||
|
var timeline_node: DialogicEditor = settings_editor.editors_manager.editors['Timeline']['node']
|
||
|
# We will close this timeline to ensure it will properly update.
|
||
|
# By saving this reference, we can open it again.
|
||
|
var current_timeline := timeline_node.current_resource
|
||
|
# Clean the current editor, this will also close the timeline.
|
||
|
settings_editor.editors_manager.clear_editor(timeline_node)
|
||
|
|
||
|
return current_timeline
|
||
|
|
||
|
|
||
|
## Opens the timeline resource into the Dialogic Editor.
|
||
|
## If the timeline is null, does nothing.
|
||
|
func _silently_open_timeline(timeline_to_open: Resource) -> void:
|
||
|
if timeline_to_open != null:
|
||
|
settings_editor.editors_manager.edit_resource(timeline_to_open, true, true)
|
||
|
|
||
|
|
||
|
## Checks [param locale] for unique locales that have not been added
|
||
|
## to the [_unique_locales] array yet.
|
||
|
func _collect_locale(locale: String) -> void:
|
||
|
if _unique_locales.has(locale):
|
||
|
return
|
||
|
|
||
|
_unique_locales.append(locale)
|