Source code for gui.ui.locale.message_loader

# -*- coding: utf-8 -*-
"""
:File: EuljiroBible/gui/ui/locale/message_loader.py
:Author: Benjamin Jaedon Choi - https://github.com/saintbenjamin
:Affiliated Church: The Eulji-ro Presbyterian Church [대한예수교장로회(통합) 을지로교회]
:Address: The Eulji-ro Presbyterian Church, 24-10, Eulji-ro 20-gil, Jung-gu, Seoul 04549, South Korea
:Telephone: +82-2-2266-3070
:E-mail: euljirochurch [at] G.M.A.I.L. (replace [at] with @ and G.M.A.I.L as you understood.)
:License: MIT License with Attribution Requirement (see LICENSE file for details); Copyright (c) 2025 The Eulji-ro Presbyterian Church.

Provides multi-language UI message dictionaries and a function to load messages by language code for EuljiroBible.
"""

import os, json
from core.config import paths

# Multi-language message dictionary
HARDCODED_MESSAGES = {
    "ko": {
        "program_title": "을지로교회 성경말씀 v{0}",
        "footer_copyright": "ⓒ 대한예수교장로회(통합) 을지로교회. All rights reserved.",
        "about_title": "을지로교회 성경말씀",
        "about_message": "을지로교회 성경말씀 v{0}\n"
                        "제작: Benjamin J. Choi\n"
                        "소속: 대한예수교장로회(통합) 을지로교회\n"
                        "본 프로그램의 저작권은 을지로교회에 있으며,\n" 
                        "무단 수정 및 배포를 금합니다."
    },
    "en": {
        "program_title": "Euljiro Bible v{0}",
        "footer_copyright": "ⓒ The Eulji-ro Presbyterian Church (TongHap). All rights reserved.",
        "about_title": "Euljiro Bible",
        "about_message": "Euljiro Bible v{0}\n"
                        "Developer: Benjamin J. Choi\n"
                        "Affiliation: Eulji-ro Presbyterian Church\n"
                        "This program is copyrighted by Eulji-ro Presbyterian Church.\n"
                        "Unauthorized modification or distribution is prohibited."
    }
}

DEFAULT_MESSAGES = {
    "language_name": "English",
    "language": "English",
    "menu_help": "Help",
    "menu_lang": "Language",
    "menu_about": "About",
    "menu_tools": "Tools",
    "menu_memory": "Memory monitor",
    "menu_test": "Error test",
    "toggle_btn_poll_enabled": "Worship mode",
    "toggle_btn_poll_disabled": "Meditation mode",
    "tab_verse": "Search verse",
    "tab_search": "Search keyword",
    "tab_font": "Settings",
    "label_alias_full": "Version (full):",
    "label_alias_short": "Version (short):",
    "label_book": "Book",
    "label_chapter": "Chapter",
    "label_verse": "Verse",
    "verse_input_hint": "e.g., 1 or 1-3",
    "btn_prev": "Previous",
    "btn_search": "Search",
    "btn_output": "ON",
    "btn_next": "Next",
    "btn_clear": "OFF",
    "msg_no_word": "No verse",
    "msg_nothing": "(None)",
    "search_keyword_hint": "e.g., God so loved",
    "search_location": "Reference",
    "search_verse": "Verse text",
    "search_summary": "Search summary",
    "search_summary": "Search summary",
    "total_results_label": "Total verses found:",
    "setting_main": "Main settings",
    "label_font_family": "Font",
    "label_font_size": "Size",
    "label_font_weight": "Weight",
    "btn_theme_toggle": "Toggle theme",
    "checkbox_show_on_off": "Always show presentation options",
    "setting_overlay": "Presentation settings",
    "label_display_select": "Display",
    "label_display_font_color": "Font color",
    "label_display_bg_color": "Background color",
    "label_display_bg_alpha": "Background opacity",
    "fullscreen": "Fullscreen",
    "resizable": "Windowed",
    "label_poll_interval": "Polling interval (ms)",
    "btn_poll_interval_save": "Save interval",
    "label_path": "Save location",
    "btn_browse": "Browse",
    "dialog_path": "Choose where to save",
    "info_no_results_title": "No Results",
    "info_no_results_msg": "No matching verses found.",
    "warn_input_title": "Input Error",
    "warn_input_msg": "Please enter a keyword/keywords.",
    "warn_jump_title": "Jump Not Allowed",
    "warn_jump_msg": "Cannot jump while a verse range is entered.",
    "warn_verse_input_title": "Verse Input Error",
    "warn_verse_input_msg": "Invalid verse input.\n(e.g., 1 or 1-3)",
    "warn_no_chapter_title": "No Chapter",
    "warn_no_chapter_msg": "No verses found in {0} chapter {1}.",
    "warn_range_title": "Range Error",
    "warn_range_min": "Verse must be at least 1.",
    "warn_range_max": "Verse range: 1-{0}.",
    "warn_verse_format_msg": "Invalid verse format.\n(e.g., 1 or 1-3)",
    "warn_selection_title": "Selection Error",
    "warn_selection_msg": "Please select verses to save.",
    "warn_range_invalid_order": "Start verse must be less than or equal to end verse.",
    "warn_version_title": "Version Not Selected",
    "warn_version_msg": "Please select at least one Bible version.",
    "warn_common_book_title": "No Common Books",
    "warn_common_book_msg": "Selected versions have no common books.",
    "warning_single_display_title": "Single Display Detected",
    "warning_single_display_msg": "Only one display is detected. Do you still want to launch the overlay?", 
    "error_verse_not_found": "Verse not found: {0}",
    "error_verse_input": "Verse input error: {0}\n(e.g., 1 or 1-3)",
    "error_loading_title": "Loading Error",
    "error_loading_msg": "Error loading {0}:\n{1}",
    "error_saving_title": "Save Error",
    "error_saving_msg": "Error saving :File:\n{0}",
    "error_saving_msg_path": "Error saving file at {0}:\n{1}",
    "error_set_saving_title": "Settings Save Error",
    "error_set_saving_msg": "Error saving settings:\n{0}",
    "error_settings_title": "Settings Error",
    "error_settings_msg": "Invalid settings format. Resetting to default.",
    "error_unknown": "An unknown error occurred. Check logs.",
}

_cached_messages = {}
_available_languages = None # Cache to avoid re-reading directory repeatedly

[docs] def get_available_languages(): """ Returns a dict like ``{ "ko": "한국어", "en": "English" }`` for all JSON files in translation folder. """ global _available_languages if _available_languages is not None: return _available_languages langs = {} if not os.path.exists(paths.TRANSLATION_DIR): return langs for fname in os.listdir(paths.TRANSLATION_DIR): if fname.endswith(".json"): lang_code = os.path.splitext(fname)[0] path = os.path.join(paths.TRANSLATION_DIR, fname) try: with open(path, encoding="utf-8") as f: data = json.load(f) lang_name = data.get("language_name", lang_code) langs[lang_code] = lang_name # e.g., 'en': 'English' except Exception: continue # Skip malformed or unreadable files _available_languages = langs return langs
[docs] def load_messages(lang_code): """ Loads UI messages based on the selected language. Args: lang_code (str): Language code (e.g., 'ko', 'en'). Returns: dict: Dictionary of translated UI messages. """ if lang_code in _cached_messages: return _cached_messages[lang_code] path = os.path.join(paths.TRANSLATION_DIR, f"{lang_code}.json") try: with open(path, encoding="utf-8") as f: messages = json.load(f) except Exception: messages = {} if not messages: messages = DEFAULT_MESSAGES.copy() lang_for_hardcode = "ko" if lang_code == "ko" else "en" # Overlay hardcoded keys like about/program title, # even if translation JSON already has values for key, val in HARDCODED_MESSAGES[lang_for_hardcode].items(): messages[key] = val _cached_messages[lang_code] = messages return messages