Invalid access to property or key

Godot Version

4.5.1

Question

I’m getting the following error twice every time I load my project:

ERROR: res://addons/dragonforge_curved_text/curved_text_2d.gd:29 - Invalid access to property or key 'locale_changed' on a base object of type 'Node (localization.gd)'.

The code in question:

func _ready() -> void:
	Localization.locale_changed.connect(_on_locale_changed)
Full File for curved_text_2d.gd
@icon("res://addons/dragonforge_curved_text/assets/textures/icons/curved_text.png")
@tool
## Creates curved text as a Node2D object. Note that if Label Settings is used
## to customize the font, the text will disappear until a font is assigned under
## Font. Changes to Shadow and Stacked Effects will not show as they are only
## supported by [Label] and [RichTextLabel] nodes. If you want this
## functionality, you will have to use a [CurvedTextLabel] node instead.
class_name CurvedText2D extends Path2D

@export var text: String:
	set(value):
		if text != value:
			text = value
			queue_redraw()
@export var label_settings: LabelSettings:
	set(value):
		if is_instance_valid(label_settings) and label_settings.changed.is_connected(queue_redraw):
			label_settings.changed.disconnect(queue_redraw)

		label_settings = value

		if is_instance_valid(label_settings):
			label_settings.changed.connect(queue_redraw)

var _line = TextLine.new()


func _ready() -> void:
	Localization.locale_changed.connect(_on_locale_changed)


func _draw() -> void:
	# Get the font, font size and color from the ThemeDB
	var font = ThemeDB.fallback_font
	var font_size = ThemeDB.fallback_font_size
	var font_color = Color.WHITE
	var outline_size = 0
	var outline_color = Color.WHITE

	# If the label_settings is valid, then use the values from it
	if is_instance_valid(label_settings):
		font = label_settings.font
		font_size = label_settings.font_size
		font_color = label_settings.font_color
		outline_size = label_settings.outline_size
		outline_color = label_settings.outline_color

	# Clear the line and add the new string
	_line.clear()
	var localized_text = tr(text)
	_line.add_string(localized_text, font, font_size)
	# Get the primary TextServer
	var text_server = TextServerManager.get_primary_interface()
	# And get the glyph information from the line
	var glyphs = text_server.shaped_text_get_glyphs(_line.get_rid())

	var offset = 0.0
	for glyph_data in glyphs:
		# Sample the curve with rotation at the offset
		var curve_transform = curve.sample_baked_with_rotation(offset)
		# set the draw matrix to that transform
		draw_set_transform_matrix(curve_transform)
		# draw the glyph
		text_server.font_draw_glyph(glyph_data["font_rid"], get_canvas_item(), font_size, Vector2.ZERO, glyph_data["index"], font_color)
		text_server.font_draw_glyph_outline(glyph_data["font_rid"], get_canvas_item(), font_size, outline_size, Vector2.ZERO, glyph_data["index"], outline_color)
		
		# add the advance to the offset
		offset += glyph_data.get("advance", 0.0)


func _on_locale_changed(_new_locale: String) -> void:
	queue_redraw()

The signal that it’s referencing is in an Autoload that is loaded by a plugin. The signal being referenced:

## Signal to use when changing localization by using TranslationServer.set_locale(new_locale)
signal locale_changed(new_locale: String)
Full Code for localization.gd
@icon("res://addons/dragonforge_localization/assets/textures/icons/localization.svg")
extends Node

## Signal to use when changing localization by using TranslationServer.set_locale(new_locale)
signal locale_changed(new_locale: String)

## The folder where the translations are stored.
@export_dir var localization_folder: String

## Contains all the available localizations once the game is running.
var available_localizations: Array[String]

func _ready() -> void:
	if not localization_folder:
		assert(false, "A Localization Folder has not been set in the Localization plugin. The Localization button will not work correctly without this value set. Open res://addons/dragonforge_localization/localization.tscn and set the folder in the Inspector.")
	var loaded_locale: Variant = Disk.load_setting("localization_language")
	if loaded_locale:
		TranslationServer.set_locale(loaded_locale)
	_load_localizations()


## Returns uppercase 2-letter country code of the passed locale if it exists,
## otherwise returns the language code.
func get_country_code(locale: String) -> String:
	return locale.substr(locale.length() - 2).to_upper()


## Returns lowercase 2-letter or 3-letter language code of the passed locale.
func get_language_code(locale: String) -> String:
	return locale.replace("-", "_").get_slice("_", 0).to_lower()


func _load_localizations() -> void:
	var dir: DirAccess = DirAccess.open(localization_folder)
	if not dir:
		return
	var file_list: PackedStringArray = dir.get_files()
	for file_name: String in file_list:
		if file_name.ends_with(".translation"):
			var translation: Translation = load(localization_folder + "/" + file_name)
			TranslationServer.add_translation(translation) # Add the translation
			var locale = file_name.trim_suffix(".translation") # Trim the file suffix
			locale = locale.substr(locale.rfind(".") + 1, locale.length()) # Get the full language and locale if available
			available_localizations.append(locale)

The Crazy Thing

Here’s the crazy thing: The code works fine! I do not know why the error is happening, but I have zero tolerance for errors and I’d like to make it go away.

Any thoughts?

Could it be the order in which the engine sets things up - some parts are missing at the earliest parts of the initial setup but eventually connect?

2 Likes

Turns out the solution was to wait for the Autoload to be ready.:

func _ready() -> void:
	if not Localization.is_node_ready():
		await Localization.ready
	Localization.locale_changed.connect(_on_locale_changed)

Thanks @baba. I was about to say no, because Autoloads load first, but then I realized that it was a tool script, and I didn’t know if that was the issue. I added the code to test the theory and also got a solution!

2 Likes