Skip to content

feat: make glossary entries work in other languages #687

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions autoload/TranslationManager.gd
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func set_language(language_code: String) -> void:
TranslationServer.set_locale(current_language)
current_profile.language = current_language
current_profile.save()
emit_signal("translation_changed")
return

# Load order shouldn't be important, so we'll just load everything from the folder.
Expand Down Expand Up @@ -106,6 +107,7 @@ func set_language(language_code: String) -> void:
TranslationServer.set_locale(current_language)
current_profile.language = current_language
current_profile.save()
emit_signal("translation_changed")


func _reset_language() -> void:
Expand Down
12 changes: 7 additions & 5 deletions resources/Glossary.gd
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ var _glossary := {}
# and wrap glossary entries in rich text labels.
var _glossary_regex := RegEx.new()


func _init() -> void:
setup()

func setup() -> void:
_glossary = _parse_glossary_file(glossary_file)
var patterns := PoolStringArray()
for key in _glossary:
Expand All @@ -36,7 +38,7 @@ func get_match(keyword: String) -> Entry:

# Parses the input CSV file and returns a dictionary mapping keywords to
# glossary entries.
static func _parse_glossary_file(path: String) -> Dictionary:
func _parse_glossary_file(path: String) -> Dictionary:
var glossary := {}
var file := File.new()
file.open(path, file.READ)
Expand All @@ -47,8 +49,8 @@ static func _parse_glossary_file(path: String) -> Dictionary:
if not csv_line[0]:
break

var plural_form = csv_line[1]
var keyword = csv_line[0]
var plural_form = tr(csv_line[1])
var keyword = tr(csv_line[0])
assert(not keyword in glossary, "Duplicate key %s in glossary." % keyword)
assert(not plural_form in glossary, "Duplicate key %s in glossary." % keyword)
var entry := Entry.new(csv_line)
Expand All @@ -66,6 +68,6 @@ class Entry:
var explanation: String

func _init(csv_line: Array) -> void:
term = tr(csv_line[0].capitalize())
term = tr(csv_line[0]).capitalize()
plural_form = tr(csv_line[1])
explanation = tr(csv_line[2])
71 changes: 49 additions & 22 deletions ui/UILesson.gd
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ export var test_lesson: Resource

var _lesson: Lesson
# Resource used to highlight glossary entries in the lesson text.
var _glossary: Glossary = preload("res://course/glossary.tres")
var _glossary: Glossary
var _visible_index := -1
var _quizzes_done := -1 # Start with -1 because we will always autoincrement at least once.
var _quizzes_done := -1 # Start with -1 because we will always autoincrement at least once.
var _quizz_count := 0

var _base_text_font_size := preload("res://ui/theme/fonts/font_text.tres").size
Expand All @@ -30,12 +30,8 @@ onready var _scroll_content := $OuterMargin/ScrollContainer/InnerMargin as Contr
onready var _title := $OuterMargin/ScrollContainer/InnerMargin/Content/Title as Label
onready var _content_blocks := $OuterMargin/ScrollContainer/InnerMargin/Content/ContentBlocks as VBoxContainer
onready var _content_container := $OuterMargin/ScrollContainer/InnerMargin/Content as VBoxContainer
onready var _practices_visibility_container := (
$OuterMargin/ScrollContainer/InnerMargin/Content/PracticesContainer as VBoxContainer
)
onready var _practices_container := (
$OuterMargin/ScrollContainer/InnerMargin/Content/PracticesContainer/Practices as VBoxContainer
)
onready var _practices_visibility_container := $OuterMargin/ScrollContainer/InnerMargin/Content/PracticesContainer as VBoxContainer
onready var _practices_container := $OuterMargin/ScrollContainer/InnerMargin/Content/PracticesContainer/Practices as VBoxContainer
onready var _debounce_timer := $DebounceTimer as Timer
onready var _tweener := $Tween as Tween
onready var _glossary_popup := $GlossaryPopup
Expand All @@ -48,6 +44,9 @@ func _ready() -> void:
_update_content_container_width(UserProfiles.get_profile().font_size_scale)
_scroll_container.get_v_scrollbar().connect("value_changed", self, "_on_content_scrolled")
_debounce_timer.connect("timeout", self, "_emit_read_content")
TranslationManager.connect("translation_changed", self, "_on_translation_changed")

_glossary = load("res://course/glossary.tres")

if test_lesson and get_parent() == get_tree().root:
setup(test_lesson, null)
Expand Down Expand Up @@ -91,10 +90,16 @@ func setup(lesson: Lesson, course: Course) -> void:
# the position to the first unread block.

if is_returning:
restore_id = user_profile.get_last_visited_lesson_block(course.resource_path, lesson.resource_path)
restore_id = user_profile.get_last_visited_lesson_block(
course.resource_path, lesson.resource_path
)

var reading_done := user_profile.is_lesson_reading_completed(course.resource_path, lesson.resource_path)
var reading_started := user_profile.has_lesson_blocks_read(course.resource_path, lesson.resource_path)
var reading_done := user_profile.is_lesson_reading_completed(
course.resource_path, lesson.resource_path
)
var reading_started := user_profile.has_lesson_blocks_read(
course.resource_path, lesson.resource_path
)
if restore_id.empty() and not reading_done and reading_started:
for block in lesson.content_blocks:
var block_id := ""
Expand All @@ -103,7 +108,9 @@ func setup(lesson: Lesson, course: Course) -> void:
else:
block_id = block.content_id

if user_profile.is_lesson_block_read(course.resource_path, lesson.resource_path, block_id):
if user_profile.is_lesson_block_read(
course.resource_path, lesson.resource_path, block_id
):
continue

restore_id = block_id
Expand All @@ -130,7 +137,9 @@ func setup(lesson: Lesson, course: Course) -> void:

var completed_before := false
if course:
completed_before = user_profile.is_lesson_quiz_completed(course.resource_path, lesson.resource_path, block.quiz_id)
completed_before = user_profile.is_lesson_quiz_completed(
course.resource_path, lesson.resource_path, block.quiz_id
)
if completed_before:
_quizzes_done += 1
instance.completed_before = completed_before
Expand All @@ -148,7 +157,9 @@ func setup(lesson: Lesson, course: Course) -> void:
var button: UIPracticeButton = PracticeButtonScene.instance()
button.setup(practice, practice_index)
if course:
button.completed_before = user_profile.is_lesson_practice_completed(course.resource_path, lesson.resource_path, practice.practice_id)
button.completed_before = user_profile.is_lesson_practice_completed(
course.resource_path, lesson.resource_path, practice.practice_id
)
if not highlighted_next and not button.completed_before:
highlighted_next = true
button.is_highlighted = true
Expand All @@ -163,12 +174,14 @@ func setup(lesson: Lesson, course: Course) -> void:
# the scroll container and its content.
yield(Events, "lesson_started")
if restore_node and restore_node.is_visible_in_tree():
var scroll_offset = abs(_scroll_content.rect_global_position.y - _content_blocks.rect_global_position.y)
var scroll_offset = abs(
_scroll_content.rect_global_position.y - _content_blocks.rect_global_position.y
)
var scroll_target = restore_node.rect_position.y + scroll_offset - AUTOSCROLL_PADDING
_tweener.stop_all()
_tweener.interpolate_method(
_scroll_container,
"set_v_scroll", # So it plays nice with our smooth scroller
"set_v_scroll", # So it plays nice with our smooth scroller
_scroll_container.scroll_vertical,
scroll_target,
AUTOSCROLL_DURATION,
Expand All @@ -177,19 +190,24 @@ func setup(lesson: Lesson, course: Course) -> void:
)
_tweener.start()

_underline_glossary_entries()

# Call this immediately to update for the blocks that are already visible.
_emit_read_content()


func _underline_glossary_entries() -> void:
_glossary.setup()
# Underline glossary entries
for rtl in get_tree().get_nodes_in_group("rich_text_label"):
rtl.bbcode_text = _glossary.replace_matching_terms(rtl.bbcode_text)
rtl.connect("meta_clicked", self, "_open_glossary_popup")

# Call this immediately to update for the blocks that are already visible.
_emit_read_content()


func _update_labels() -> void:
if not _lesson:
return

_title.text = tr(_lesson.title)


Expand Down Expand Up @@ -219,7 +237,9 @@ func _on_content_scrolled(_value: float) -> void:


func _emit_read_content() -> void:
var scroll_offset = abs(_scroll_content.rect_global_position.y - _content_blocks.rect_global_position.y)
var scroll_offset = abs(
_scroll_content.rect_global_position.y - _content_blocks.rect_global_position.y
)
var scroll_distance = _scroll_container.scroll_vertical - scroll_offset - AUTOSCROLL_PADDING

var content_index := 0
Expand Down Expand Up @@ -248,10 +268,17 @@ func _emit_read_content() -> void:


func _update_content_container_width(new_font_scale: int) -> void:
var font_size_multiplier := float(_base_text_font_size + new_font_scale * 2) / _base_text_font_size
var font_size_multiplier := (
float(_base_text_font_size + new_font_scale * 2)
/ _base_text_font_size
)
_content_container.rect_min_size.x = _start_content_width * font_size_multiplier


func _on_translation_changed() -> void:
_underline_glossary_entries()


func _open_glossary_popup(meta: String) -> void:
var entry: Glossary.Entry = _glossary.get_match(meta)
_glossary_popup.setup(entry.term, entry.explanation)
Expand Down