Skip to content

Commit a7ef08c

Browse files
committed
Add ability to generate IDs for nodes in a DS
1 parent 66ed849 commit a7ef08c

12 files changed

+334
-39
lines changed

addons/parley/constants.gd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ const DIALOGUE_BALLOON_PATH: StringName = &"parley/dialogue/dialogue_balloon_pat
3636
#region Internationalisation
3737
# Project settings
3838
const TRANSLATION_MODE: StringName = &"parley/translations/mode"
39+
const TRANSLATION_CSV_HEADER_KEY: StringName = &"parley/translations/csv_header_key"
3940
const TRANSLATION_FILES: StringName = &"internationalization/locale/translations"
4041
const TRANSLATIONS_POT_FILES: StringName = &"internationalization/locale/translations_pot_files"
42+
const TRANSLATION_LOCALE_TEST: StringName = &"internationalization/locale/test"
43+
const TRANSLATION_LOCALE_FALLBACK: StringName = &"internationalization/locale/fallback"
4144
#endregion
4245

4346

addons/parley/main_panel.gd

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const new_file_icon: CompressedTexture2D = preload("./assets/New.svg")
1212
const load_file_icon: CompressedTexture2D = preload("./assets/Load.svg")
1313
const export_icon: CompressedTexture2D = preload("./assets/Export.svg")
1414
const import_icon: CompressedTexture2D = preload("./assets/Import.svg")
15+
const generate_icon: CompressedTexture2D = preload("./assets/Generate.svg")
1516
const insert_after_icon: CompressedTexture2D = preload("./assets/InsertAfter.svg")
1617
const dialogue_icon: CompressedTexture2D = preload("./assets/Dialogue.svg")
1718
const dialogue_option_icon: CompressedTexture2D = preload("./assets/DialogueOption.svg")
@@ -235,27 +236,27 @@ func _setup(on_ready: bool = false) -> void:
235236
func _setup_file_menu() -> void:
236237
var popup: PopupMenu = file_menu.get_popup()
237238
popup.clear()
238-
popup.add_icon_item(new_file_icon, "New Dialogue Sequence...", 0)
239-
popup.add_icon_item(load_file_icon, "Open Dialogue Sequence...", 1)
240-
popup.add_separator("Export")
241-
popup.add_icon_item(export_icon, "Export to CSV...", 2)
239+
popup.add_icon_item(new_file_icon, &"New Dialogue Sequence...", 0)
240+
popup.add_icon_item(load_file_icon, &"Open Dialogue Sequence...", 1)
241+
popup.add_separator(&"Export")
242+
popup.add_icon_item(export_icon, &"Export to CSV...", 2)
242243
ParleyUtils.signals.safe_connect(popup.id_pressed, _on_file_id_pressed)
243244

244245

245246
## Set up the insert menu
246247
func _setup_insert_menu() -> void:
247248
var popup: PopupMenu = insert_menu.get_popup()
248249
popup.clear()
249-
popup.add_separator("Dialogue")
250+
popup.add_separator(&"Dialogue")
250251
popup.add_icon_item(dialogue_icon, ParleyDialogueSequenceAst.get_type_name(ParleyDialogueSequenceAst.Type.DIALOGUE), ParleyDialogueSequenceAst.Type.DIALOGUE)
251252
popup.add_icon_item(dialogue_option_icon, ParleyDialogueSequenceAst.get_type_name(ParleyDialogueSequenceAst.Type.DIALOGUE_OPTION), ParleyDialogueSequenceAst.Type.DIALOGUE_OPTION)
252-
popup.add_separator("Conditions")
253+
popup.add_separator(&"Conditions")
253254
popup.add_icon_item(condition_icon, ParleyDialogueSequenceAst.get_type_name(ParleyDialogueSequenceAst.Type.CONDITION), ParleyDialogueSequenceAst.Type.CONDITION)
254255
popup.add_icon_item(condition_icon, ParleyDialogueSequenceAst.get_type_name(ParleyDialogueSequenceAst.Type.MATCH), ParleyDialogueSequenceAst.Type.MATCH)
255-
popup.add_separator("Actions")
256+
popup.add_separator(&"Actions")
256257
popup.add_icon_item(action_icon, ParleyDialogueSequenceAst.get_type_name(ParleyDialogueSequenceAst.Type.ACTION), ParleyDialogueSequenceAst.Type.ACTION)
257258
popup.add_icon_item(jump_node_icon, ParleyDialogueSequenceAst.get_type_name(ParleyDialogueSequenceAst.Type.JUMP), ParleyDialogueSequenceAst.Type.JUMP)
258-
popup.add_separator("Misc")
259+
popup.add_separator(&"Misc")
259260
popup.add_icon_item(start_node_icon, ParleyDialogueSequenceAst.get_type_name(ParleyDialogueSequenceAst.Type.START), ParleyDialogueSequenceAst.Type.START)
260261
popup.add_icon_item(end_node_icon, ParleyDialogueSequenceAst.get_type_name(ParleyDialogueSequenceAst.Type.END), ParleyDialogueSequenceAst.Type.END)
261262
popup.add_icon_item(group_node_icon, ParleyDialogueSequenceAst.get_type_name(ParleyDialogueSequenceAst.Type.GROUP), ParleyDialogueSequenceAst.Type.GROUP)
@@ -266,14 +267,20 @@ func _render_translations_menu() -> void:
266267
var popup: PopupMenu = translations_menu.get_popup()
267268
popup.clear()
268269

269-
popup.add_icon_item(export_icon, "Export Dialogue to CSV...", 0)
270-
popup.set_item_tooltip(0, "Export Dialogue Text Translations to CSV")
270+
popup.add_separator(&"Exports")
271+
popup.add_icon_item(export_icon, &"Export Dialogue to CSV...", 0)
272+
popup.set_item_tooltip(0, &"Export Dialogue Text Translations to CSV")
271273

272-
popup.add_icon_item(export_icon, "Export Characters to CSV...", 1)
273-
popup.set_item_tooltip(1, "Export Character Translations to CSV")
274+
popup.add_icon_item(export_icon, &"Export Characters to CSV...", 1)
275+
popup.set_item_tooltip(1, &"Export Character Translations to CSV")
274276

275-
popup.add_icon_item(import_icon, "Import Dialogue from CSV...", 2)
276-
popup.set_item_tooltip(2, "Import Dialogue Text Translations from CSV")
277+
popup.add_separator(&"Imports")
278+
popup.add_icon_item(import_icon, &"Import Dialogue from CSV...", 2)
279+
popup.set_item_tooltip(2, &"Import Dialogue Text Translations from CSV")
280+
281+
popup.add_separator(&"Generators")
282+
popup.add_icon_item(generate_icon, &"Generate Text Translation keys...", 3)
283+
popup.set_item_tooltip(3, &"Generate Text Translation keys for Dialogue Sequence Nodes")
277284

278285
ParleyUtils.signals.safe_connect(popup.id_pressed, _on_translations_menu_id_pressed)
279286
#endregion
@@ -351,6 +358,20 @@ func _on_translations_menu_id_pressed(id: int) -> void:
351358
export_modal.render(ParleyExportModal.ExportType.CharacterNameTranslation, ParleyExportModal.FileType.Csv, dialogue_ast)
352359
2:
353360
import_modal.render(ParleyImportModal.ImportType.DialogueTextTranslation, ParleyImportModal.FileType.Csv, dialogue_ast)
361+
3:
362+
if dialogue_ast:
363+
var ast_changed: bool = dialogue_ast.generate_text_translation_keys()
364+
# TODO: This is currently to make sure that the currently open editor updates when the dialogue sequence updates.
365+
# However, to improve future maintainability and better software patterns, we should do this
366+
# generically by just noting that the Dialogue Sequence AST has changed and inferring everything from there
367+
if ast_changed and selected_node_ast and selected_node_id:
368+
node_selected.emit(selected_node_ast)
369+
if selected_node_id:
370+
var currently_selected_node_id: String = selected_node_id
371+
var currently_selected_node_ast: ParleyNodeAst = dialogue_ast.find_node_by_id(currently_selected_node_id)
372+
if currently_selected_node_ast:
373+
node_selected.emit(currently_selected_node_ast)
374+
print_rich(ParleyUtils.log.info_msg("Generated Text Translation Keys for Dialogue Sequence AST: {dialogue_ast}".format({'dialogue_ast': dialogue_ast})))
354375
_:
355376
print_rich(ParleyUtils.log.info_msg("Unknown option ID pressed: {id}".format({'id': id})))
356377

@@ -386,6 +407,7 @@ func _save_dialogue() -> int:
386407
EditorInterface.get_resource_filesystem().reimport_files([dialogue_ast.resource_path])
387408
return OK
388409

410+
389411
func _on_arrange_nodes_button_pressed() -> void:
390412
selected_node_id = null
391413
await refresh()
@@ -404,6 +426,7 @@ func _on_test_dialogue_from_start_button_pressed() -> void:
404426
if parley_manager:
405427
parley_manager.run_test_dialogue_from_start(dialogue_ast)
406428

429+
407430
func _on_test_dialogue_from_selected_button_pressed() -> void:
408431
# TODO: dialogue is technically async so we should ideally wait here
409432
var result: int = _save_dialogue()
@@ -802,9 +825,9 @@ func _add_edge(from_node_name: StringName, from_slot: int, to_node_name: StringN
802825
if added_edge:
803826
graph_view.add_edge(added_edge, from_node_name, to_node_name)
804827

805-
func _is_selected_node(id: String) -> bool:
828+
func _is_selected_node(id: String, should_log: bool = true) -> bool:
806829
var is_selected_node: bool = selected_node_id == id
807-
if not is_selected_node:
830+
if not is_selected_node and should_log:
808831
push_warning(ParleyUtils.log.warn_msg("Node with ID %s is not selected" % id))
809832
return is_selected_node
810833
#endregion

addons/parley/models/dialogue_sequence_ast.gd

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,34 @@ func remove_edges(edges_to_remove: Array[ParleyEdgeAst], emit: bool = true) -> i
299299
if removed > 0 and emit:
300300
_emit_dialogue_updated()
301301
return removed
302+
303+
304+
## Generate text translation keys for all nodes
305+
## in the Dialogue Sequence AST.
306+
func generate_text_translation_keys() -> bool:
307+
var ast_changed: bool = false
308+
for node_ast: ParleyNodeAst in nodes:
309+
match node_ast.type:
310+
ParleyDialogueSequenceAst.Type.DIALOGUE:
311+
var dialogue_node_ast: ParleyDialogueNodeAst = node_ast
312+
var current_text_translation_key: String = ParleyUtils.translation.get_msg_ctx(dialogue_node_ast, &"text")
313+
if not current_text_translation_key and dialogue_node_ast.text:
314+
var text_translation_key: String = ParleyUtils.translation.generate_key(dialogue_node_ast.text, self, dialogue_node_ast, &"text")
315+
dialogue_node_ast.update(dialogue_node_ast.character, dialogue_node_ast.text, text_translation_key)
316+
ast_changed = true
317+
ParleyDialogueSequenceAst.Type.DIALOGUE_OPTION:
318+
var dialogue_option_node_ast: ParleyDialogueOptionNodeAst = node_ast
319+
var current_text_translation_key: String = ParleyUtils.translation.get_msg_ctx(dialogue_option_node_ast, &"text")
320+
if not current_text_translation_key and dialogue_option_node_ast.text:
321+
var text_translation_key: String = ParleyUtils.translation.generate_key(dialogue_option_node_ast.text, self, dialogue_option_node_ast, &"text")
322+
dialogue_option_node_ast.update(dialogue_option_node_ast.character, dialogue_option_node_ast.text, text_translation_key)
323+
ast_changed = true
324+
_:
325+
pass
326+
if ast_changed:
327+
emit_changed()
328+
dialogue_updated.emit(self)
329+
return ast_changed
302330
#endregion
303331

304332

addons/parley/parley_manager.gd

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,11 @@ func get_test_locale() -> String:
248248
test_locale = ParleySettings.get_setting(ParleyConstants.TEST_DEFAULT_LOCALE, "")
249249
if test_locale and is_instance_of(test_locale, TYPE_STRING):
250250
return test_locale
251-
# TODO: constant
252-
test_locale = ProjectSettings.get_setting("internationalization/locale/test", "")
251+
252+
test_locale = ProjectSettings.get_setting(ParleyConstants.TRANSLATION_LOCALE_TEST, "")
253253
if test_locale and is_instance_of(test_locale, TYPE_STRING):
254254
return test_locale
255+
255256
return TranslationServer.get_tool_locale()
256257

257258

addons/parley/settings.gd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ static var DEFAULT_SETTINGS: Dictionary = {
1616
ParleyConstants.FACT_STORE_PATH: "res://facts/fact_store.tres",
1717
# Internationalisation
1818
ParleyConstants.TRANSLATION_MODE: ParleyContext.TranslationMode.keys()[ParleyContext.TranslationMode.PO],
19+
ParleyConstants.TRANSLATION_CSV_HEADER_KEY: &"keys",
1920
# Test Dialogue Sequence
2021
# We can't preload this because of circular deps so let's
2122
# hardcode it for now but allow people to edit it in settings
@@ -59,6 +60,11 @@ static var TYPES: Dictionary = {
5960
"hint": PROPERTY_HINT_ENUM,
6061
"hint_string": ",".join(ParleyContext.TranslationMode.keys())
6162
},
63+
ParleyConstants.TRANSLATION_CSV_HEADER_KEY: {
64+
"name": ParleyConstants.TRANSLATION_CSV_HEADER_KEY,
65+
"description": "Defines the translation header key for use in CSV translation files. By default, this is 'keys'.",
66+
"type": TYPE_STRING_NAME,
67+
},
6268
# Testing
6369
ParleyConstants.TEST_DIALOGUE_SEQUENCE_TEST_SCENE_PATH: {
6470
"name": ParleyConstants.TEST_DIALOGUE_SEQUENCE_TEST_SCENE_PATH,
@@ -70,6 +76,7 @@ static var TYPES: Dictionary = {
7076
"name": ParleyConstants.TEST_DEFAULT_LOCALE,
7177
"description": "Defines the default locale that will be used when testing Dialogue Sequences.",
7278
"type": TYPE_STRING,
79+
"hint": PROPERTY_HINT_LOCALE_ID
7380
}
7481
}
7582

addons/parley/utils/parley_util.gd

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
@tool
44
class_name ParleyUtils
55

6+
const Constants = preload("res://addons/parley/constants.gd")
7+
const Settings = preload("res://addons/parley/settings.gd")
68

79
class signals:
810
## Connect safely to a signal and handle any errors accordingly
@@ -160,17 +162,19 @@ class translation:
160162

161163

162164
static func get_locale() -> StringName:
163-
# TODO: get locale_key from config but for now default to project-then-system locale
164-
var locale: StringName = ProjectSettings.get_setting("internationalization/locale/fallback")
165+
var locale: StringName = Settings.get_setting(Constants.TEST_DEFAULT_LOCALE)
166+
if locale:
167+
return locale
168+
169+
locale = ProjectSettings.get_setting(Constants.TRANSLATION_LOCALE_FALLBACK)
165170
if locale:
166171
return locale
167172

168173
return TranslationServer.get_tool_locale()
169-
174+
170175

171176
static func get_csv_key_name() -> StringName:
172-
# TODO: get from config
173-
return &"keys"
177+
return ParleySettings.get_setting(Constants.TRANSLATION_CSV_HEADER_KEY)
174178

175179

176180
class string:

project.godot

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,12 @@ enabled=PackedStringArray("res://addons/gut/plugin.cfg", "res://addons/parley/pl
5050

5151
locale/translation_remaps={}
5252
locale/translations=PackedStringArray("res://addons/parley/locale/tooltip_translations.en.translation", "res://locale/fr.po", "res://locale/all.en.translation", "res://locale/all.fr.translation")
53-
locale/translations_pot_files=PackedStringArray("res://dialogue_sequences/all.ds", "res://dialogue_sequences/next_dialogue.ds", "res://tests/fixtures/basic_pot_translations.ds", "res://tests/fixtures/basic_ast_node_generation_input.ds", "res://tests/fixtures/basic_match_input.ds", "res://tests/fixtures/from_jump_node_input.ds", "res://tests/fixtures/to_jump_node_input.ds", "res://tests/fixtures/basic_ast_node_generation_input_with_sorting_cases.ds", "res://tests/fixtures/basic_guard_input.ds", "res://examples/create-to-jump-node-basic.ds", "res://examples/create-match-basic.ds", "res://examples/create-group-basic.ds", "res://examples/create-from-jump-node-basic.ds", "res://examples/create-dialogue-option-basic.ds", "res://examples/create-dialogue-basic.ds", "res://examples/create-condition-basic.ds", "res://examples/create-action-basic.ds", "res://examples/all.ds", "res://tests/fixtures/basic_csv_translations.ds")
53+
locale/translations_pot_files=PackedStringArray("res://dialogue_sequences/all.ds", "res://dialogue_sequences/next_dialogue.ds", "res://tests/fixtures/basic_pot_translations.ds", "res://tests/fixtures/basic_ast_node_generation_input.ds", "res://tests/fixtures/basic_match_input.ds", "res://tests/fixtures/from_jump_node_input.ds", "res://tests/fixtures/to_jump_node_input.ds", "res://tests/fixtures/basic_ast_node_generation_input_with_sorting_cases.ds", "res://tests/fixtures/basic_guard_input.ds", "res://examples/create-to-jump-node-basic.ds", "res://examples/create-match-basic.ds", "res://examples/create-group-basic.ds", "res://examples/create-from-jump-node-basic.ds", "res://examples/create-dialogue-option-basic.ds", "res://examples/create-dialogue-basic.ds", "res://examples/create-condition-basic.ds", "res://examples/create-action-basic.ds", "res://examples/all.ds", "res://tests/fixtures/basic_csv_translations.ds", "res://tests/fixtures/generate_text_translation_keys_translations.ds")
5454
locale/locale_filter_mode=0
5555

5656
[parley]
5757

5858
stores/action_store_path="uid://bfwohwb0ftpuq"
5959
stores/fact_store_path="uid://c3c7k7lljjqv3"
6060
stores/character_store_path="uid://ceouii84qmu0w"
61+
test_dialogue_sequence/default_locale="en"

0 commit comments

Comments
 (0)