From 76f1d845b8db7958df1864d8159e6c4ef7cbbc16 Mon Sep 17 00:00:00 2001 From: "Giampiero L." <54741923+GLWine@users.noreply.github.com> Date: Thu, 14 May 2026 02:05:37 +0200 Subject: [PATCH 1/5] Use l10n translation helper and CR/LF formatting Import l10n translations earlier and replace hard-coded popup/notification strings with tr.tl(...) calls using CR/LF placeholders. Standardize message formatting across journal-lock, process-already-running, update notifications, provider reset, plugin errors and critical error dialogs, remove manual \"replace('\\n','\n').replace('\\r','\r')\" post-processing and the duplicate l10n import. This consolidates i18n handling and normalizes linebreak formatting for localized messages. --- EDMarketConnector.py | 58 ++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/EDMarketConnector.py b/EDMarketConnector.py index e8d28e54a3..c7cab2372d 100644 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -69,6 +69,7 @@ from journal_lock import JournalLock, JournalLockResult from update import check_for_datafile_updates, check_for_fdev_updates from common_utils import log_locale, SERVER_RETRY +from l10n import translations as tr if __name__ == '__main__': # noqa: C901 # Command-line arguments @@ -361,7 +362,10 @@ def enumwindowsproc(window_handle, l_param): # noqa: CCR001 def skip_journallock_popup(): """Create the "skipping Journal Lock" popup.""" from tkinter import messagebox - lockmsg = "Ignoring failed Journal Lock. Continuing at your own risk.\nConsider also using a debug sender." + lockmsg = tr.tl( + "Ignoring failed Journal Lock. Continuing at your own risk." + "{CR}Consider also using a debug sender." + ).format(CR="\n") # LANG: Popup message when user tries to start a second instance of the application with --skip-journallock, warning them of potential consequences messagebox.showwarning(title=appname, message=lockmsg) def already_running_popup(): @@ -371,7 +375,10 @@ def already_running_popup(): if args.suppress_dupe_process_popup: sys.exit(0) - messagebox.showerror(title=appname, message="An EDMarketConnector process was already running, exiting.") + messagebox.showerror( + title=appname, + message=tr.tl("An EDMarketConnector process was already running, exiting.") # LANG: Popup message when user tries to start a second instance of the application + ) sys.exit(0) journal_lock = JournalLock() @@ -441,7 +448,6 @@ def already_running_popup(): from dashboard import dashboard from edmc_data import ship_name_map from hotkey import hotkeymgr -from l10n import translations as tr from monitor import monitor from theme import theme from ttkHyperlinkLabel import HyperlinkLabel, SHIPYARD_HTML_TEMPLATE @@ -949,13 +955,12 @@ def postprefs(self, dologin: bool = True, **postargs): update_msg = tr.tl( # LANG: Inform User of Beta -> Stable Transition Risks 'Update track changed to Stable from Beta. ' 'You will no longer receive Beta updates. You will stay on your current Beta ' - r'version until the next Stable release.\r\n\r\n' + 'version until the next Stable release.{LF}{CR}{LF}{CR}' 'You can manually revert to the latest Stable version. To do so, you must download and install ' 'the latest Stable version manually. Note that this may introduce bugs or break completely' - r' if downgrading between major versions with significant changes.\r\n\r\n' + ' if downgrading between major versions with significant changes.{LF}{CR}{LF}{CR}' 'Do you want to open GitHub to download the latest release?' - ) - update_msg = update_msg.replace('\\n', '\n').replace('\\r', '\r') + ).format(CR="\n", LF="\r") stable_popup = tk.messagebox.askyesno(title=title, message=update_msg) if stable_popup: webbrowser.open("https://github.com/EDCD/eDMarketConnector/releases/latest") @@ -2198,16 +2203,20 @@ def validate_providers(): return # LANG: Popup-text about Reset Providers - popup_text = tr.tl(r'One or more of your URL Providers were invalid, and have been reset:\r\n\r\n') + popup_text = tr.tl( + 'One or more of your URL Providers were invalid, and have been reset:{LF}{CR}{LF}{CR}' + ).format(LF='{LF}', CR='{CR}') for provider, (old_prov, new_prov) in reset_providers.items(): # LANG: Text About What Provider Was Reset - popup_text += tr.tl(r'{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}\r\n').format( + popup_text += tr.tl( + '{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}{LF}{CR}' + ).format( PROVIDER=provider, OLDPROV=old_prov, - NEWPROV=new_prov + NEWPROV=new_prov, + LF='{LF}', # Line Feed + CR='{CR}' # Carriage Return ) - # And now we do need these to be actual \r\n - popup_text = popup_text.replace('\\n', '\n').replace('\\r', '\r') tk.messagebox.showinfo( # LANG: Popup window title for Reset Providers @@ -2373,13 +2382,14 @@ def test_prop(self): logger.exception(f"EDMC Critical Error: {err}") title = tr.tl("Error") # LANG: Generic error prefix message = tr.tl( # LANG: EDMC Critical Error Notification - "EDMC encountered a critical error, and cannot recover. EDMC is shutting down for its own protection!" + "EDMC encountered a critical error, and cannot recover. " + "EDMC is shutting down for its own protection!" ) err = f"{err.__class__.__name__}: {err}" # type: ignore # hijacking the existing exception detection detail = tr.tl( # LANG: EDMC Critical Error Details - r"Here's what EDMC Detected:\r\n\r\n{ERR}\r\n\r\nDo you want to file a Bug Report on GitHub?" - ).format(ERR=err) - detail = detail.replace('\\n', '\n').replace('\\r', '\r') + "Here's what EDMC Detected:{LF}{CR}{LF}{CR}" + "{ERR}{LF}{CR}{LF}{CR}Do you want to file a Bug Report on GitHub?" + ).format(ERR=err, CR="\n", LF="\r") msg = tk.messagebox.askyesno( title=title, message=message, detail=detail, icon=tkinter.messagebox.ERROR, type=tkinter.messagebox.YESNO, parent=root @@ -2398,7 +2408,7 @@ def messagebox_broken_plugins(): popup_text = tr.tl( "One or more of your enabled plugins failed to load. Please see the list on the '{PLUGINS}' " "tab of '{FILE}' > '{SETTINGS}'. This could be caused by a wrong folder structure. The load.py " - r"file should be located under plugins/PLUGIN_NAME/load.py.\r\n\r\nYou can disable a plugin by " + "file should be located under plugins/PLUGIN_NAME/load.py.{LF}{CR}{LF}{CR}You can disable a plugin by " "renaming its folder to have '{DISABLED}' on the end of the name." ) @@ -2407,10 +2417,10 @@ def messagebox_broken_plugins(): PLUGINS=tr.tl('Plugins'), # LANG: Settings > Plugins tab FILE=tr.tl('File'), # LANG: 'File' menu SETTINGS=tr.tl('Settings'), # LANG: File > Settings - DISABLED='.disabled' + DISABLED='.disabled', + LF='{LF}', # Line Feed + CR='{CR}' # Carriage Return ) - # And now we do need these to be actual \r\n - popup_text = popup_text.replace('\\n', '\n').replace('\\r', '\r') tk.messagebox.showinfo( # LANG: Popup window title for list of 'broken' plugins that failed to load @@ -2428,7 +2438,7 @@ def messagebox_not_py3(): "One or more of your enabled plugins do not yet have support for Python 3.x. Please see the " "list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. You should check if there is an " "updated version available, else alert the developer that they need to update the code for " - r"Python 3.x.\r\n\r\nYou can disable a plugin by renaming its folder to have '{DISABLED}' on " + "Python 3.x.{LF}{CR}{LF}{CR}You can disable a plugin by renaming its folder to have '{DISABLED}' on " "the end of the name." ) @@ -2437,10 +2447,10 @@ def messagebox_not_py3(): PLUGINS=tr.tl('Plugins'), # LANG: Settings > Plugins tab FILE=tr.tl('File'), # LANG: 'File' menu SETTINGS=tr.tl('Settings'), # LANG: File > Settings - DISABLED='.disabled' + DISABLED='.disabled', + LF='{LF}', # Line Feed + CR='{CR}' # Carriage Return ) - # And now we do need these to be actual \r\n - popup_text = popup_text.replace('\\n', '\n').replace('\\r', '\r') tk.messagebox.showinfo( # LANG: Popup window title for list of 'enabled' plugins that don't work with Python 3.x From e58d094a2b4b11bd52b9027de57526bc07d2afb2 Mon Sep 17 00:00:00 2001 From: "Giampiero L." <54741923+GLWine@users.noreply.github.com> Date: Thu, 14 May 2026 02:07:55 +0200 Subject: [PATCH 2/5] Use newline placeholders and add startup messages Update L10n/en.template to replace literal CRLF sequences in several localized popup strings with {LF}{CR} placeholders for consistent newline handling. Also add two new localization entries for journal-lock and duplicate-process startup warnings and adjust plugin, provider-reset, and update-track messages to use the new placeholders. --- L10n/en.template | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/L10n/en.template b/L10n/en.template index f9a97348b1..e4e622e667 100644 --- a/L10n/en.template +++ b/L10n/en.template @@ -37,7 +37,7 @@ "EDMC encountered a critical error, and cannot recover. EDMC is shutting down for its own protection!" = "EDMC encountered a critical error, and cannot recover. EDMC is shutting down for its own protection!"; /* EDMarketConnector.py: EDMC Critical Error Details; */ -"Here's what EDMC Detected:\r\n\r\n{ERR}\r\n\r\nDo you want to file a Bug Report on GitHub?" = "Here's what EDMC Detected:\r\n\r\n{ERR}\r\n\r\nDo you want to file a Bug Report on GitHub?"; +"Here's what EDMC Detected:{LF}{CR}{LF}{CR}{ERR}{LF}{CR}{LF}{CR}Do you want to file a Bug Report on GitHub?" = "Here's what EDMC Detected:{LF}{CR}{LF}{CR}{ERR}{LF}{CR}{LF}{CR}Do you want to file a Bug Report on GitHub?"; /* companion.py: Frontier CAPI returned 418, meaning down for maintenance; In files: companion.py:844; */ "Frontier CAPI down for maintenance" = "Frontier CAPI down for maintenance"; @@ -223,7 +223,7 @@ "Shutting down..." = "Shutting down..."; /* EDMarketConnector.py: Popup-text about 'active' plugins without Python 3.x support; In files: EDMarketConnector.py:2253:2259; */ -"One or more of your enabled plugins do not yet have support for Python 3.x. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. You should check if there is an updated version available, else alert the developer that they need to update the code for Python 3.x.\r\n\r\nYou can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name." = "One or more of your enabled plugins do not yet have support for Python 3.x. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. You should check if there is an updated version available, else alert the developer that they need to update the code for Python 3.x.\r\n\r\nYou can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name."; +"One or more of your enabled plugins do not yet have support for Python 3.x. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. You should check if there is an updated version available, else alert the developer that they need to update the code for Python 3.x.{LF}{CR}{LF}{CR}You can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name." = "One or more of your enabled plugins do not yet have support for Python 3.x. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. You should check if there is an updated version available, else alert the developer that they need to update the code for Python 3.x.{LF}{CR}{LF}{CR}You can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name."; /* EDMarketConnector.py: Settings > Plugins tab; prefs.py: Label on Settings > Plugins tab; In files: EDMarketConnector.py:2263; prefs.py:986; */ "Plugins" = "Plugins"; @@ -235,13 +235,13 @@ "EDMC: Broken Plugins" = "EDMC: Broken Plugins"; /* EDMarketConnector.py: Popup-text about 'broken' plugins that failed to load; In files: EDMarketConnector.py:2266; */ -"One or more of your enabled plugins failed to load. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. This could be caused by a wrong folder structure. The load.py file should be located under plugins/PLUGIN_NAME/load.py.\r\n\r\nYou can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name." = "One or more of your enabled plugins failed to load. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. This could be caused by a wrong folder structure. The load.py file should be located under plugins/PLUGIN_NAME/load.py.\r\n\r\nYou can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name."; +"One or more of your enabled plugins failed to load. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. This could be caused by a wrong folder structure. The load.py file should be located under plugins/PLUGIN_NAME/load.py.{LF}{CR}{LF}{CR}You can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name." = "One or more of your enabled plugins failed to load. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. This could be caused by a wrong folder structure. The load.py file should be located under plugins/PLUGIN_NAME/load.py.{LF}{CR}{LF}{CR}You can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name."; /* EDMarketConnector.py: Popup-text about Reset Providers; In files: EDMarketConnector.py:2146; */ -"One or more of your URL Providers were invalid, and have been reset:\r\n\r\n" = "One or more of your URL Providers were invalid, and have been reset:\r\n\r\n"; +"One or more of your URL Providers were invalid, and have been reset:{LF}{CR}{LF}{CR}" = "One or more of your URL Providers were invalid, and have been reset:{LF}{CR}{LF}{CR}"; /* EDMarketConnector.py: Text About What Provider Was Reset; In files: EDMarketConnector.py:2148; */ -"{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}\r\n" = "{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}\r\n"; +"{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}{LF}{CR}" = "{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}{LF}{CR}"; /* EDMarketConnector.py: Popup window title for Reset Providers; In files: EDMarketConnector.py:2161; */ "EDMC: Default Providers Reset" = "EDMC: Default Providers Reset"; @@ -813,11 +813,17 @@ /* prefs.py: Select the Update Track (Beta, Stable); */ "Update Track" = "Update Track"; +/* EDMarketConnector.py: Popup message when user tries to start a second instance of the application with --skip-journallock, warning them of potential consequences; In files: EDMarketConnector.py:364-367; */ +"Ignoring failed Journal Lock. Continuing at your own risk.{CR}Consider also using a debug sender." ="Ignoring failed Journal Lock. Continuing at your own risk.{CR}Consider also using a debug sender."; + +/* EDMarketConnector.py: Popup message when user tries to start a second instance of the application ; In files: EDMarketConnector.py:379; */ +"An EDMarketConnector process was already running, exiting." ="An EDMarketConnector process was already running, exiting."; + /* EDMarketConnector.py: Inform the user the Update Track has changed; */ "Update Track Changed to {TRACK}" = "Update Track Changed to {TRACK}"; /* EDMarketConnector.py: Inform User of Beta -> Stable Transition Risks; */ -"Update track changed to Stable from Beta. You will no longer receive Beta updates. You will stay on your current Beta version until the next Stable release.\r\n\r\nYou can manually revert to the latest Stable version. To do so, you must download and install the latest Stable version manually. Note that this may introduce bugs or break completely if downgrading between major versions with significant changes.\r\n\r\nDo you want to open GitHub to download the latest release?" = "Update track changed to Stable from Beta. You will no longer receive Beta updates. You will stay on your current Beta version until the next Stable release.\r\n\r\nYou can manually revert to the latest Stable version. To do so, you must download and install the latest Stable version manually. Note that this may introduce bugs or break completely if downgrading between major versions with significant changes.\r\n\r\nDo you want to open GitHub to download the latest release?"; +"Update track changed to Stable from Beta. You will no longer receive Beta updates. You will stay on your current Beta version until the next Stable release.{LF}{CR}{LF}{CR}You can manually revert to the latest Stable version. To do so, you must download and install the latest Stable version manually. Note that this may introduce bugs or break completely if downgrading between major versions with significant changes.{LF}{CR}{LF}{CR}Do you want to open GitHub to download the latest release?" = "Update track changed to Stable from Beta. You will no longer receive Beta updates. You will stay on your current Beta version until the next Stable release.{LF}{CR}{LF}{CR}You can manually revert to the latest Stable version. To do so, you must download and install the latest Stable version manually. Note that this may introduce bugs or break completely if downgrading between major versions with significant changes.{LF}{CR}{LF}{CR}Do you want to open GitHub to download the latest release?"; /* EDMarketConnector.py: Title of Notification Popup for EDMC Restart; */ "Restart Required" = "Restart Required"; From 4d354f9f99f2174763516772cb504d58ac2ca8f3 Mon Sep 17 00:00:00 2001 From: "Giampiero L." <54741923+GLWine@users.noreply.github.com> Date: Mon, 1 Jun 2026 23:39:45 +0200 Subject: [PATCH 3/5] Localize UI strings and unify EOL placeholders Wrap several user-facing messages and labels in the translation helper (tr.tl) and add LANG comments for clarity. Replace ad-hoc CR/LF placeholders with a single EOL replacement ("\r\n") for consistent end-of-line handling across popups and dialogs. Changes affect update-track prompts, killswitch popup text and title, provider-reset notifications, critical error details, and plugin-related warning popups, and make the OK button label translatable. --- EDMarketConnector.py | 61 ++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/EDMarketConnector.py b/EDMarketConnector.py index c7cab2372d..0250256a98 100644 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -952,15 +952,15 @@ def postprefs(self, dologin: bool = True, **postargs): if track == "Stable": # LANG: Inform the user the Update Track has changed title = tr.tl('Update Track Changed to {TRACK}').format(TRACK=track) - update_msg = tr.tl( # LANG: Inform User of Beta -> Stable Transition Risks + update_msg = tr.tl( # LANG: Inform User of Beta -> Stable Transition Risks, EOL: End of Line 'Update track changed to Stable from Beta. ' 'You will no longer receive Beta updates. You will stay on your current Beta ' - 'version until the next Stable release.{LF}{CR}{LF}{CR}' + 'version until the next Stable release.{EOL}{EOL}' 'You can manually revert to the latest Stable version. To do so, you must download and install ' 'the latest Stable version manually. Note that this may introduce bugs or break completely' - ' if downgrading between major versions with significant changes.{LF}{CR}{LF}{CR}' + ' if downgrading between major versions with significant changes.{EOL}{EOL}' 'Do you want to open GitHub to download the latest release?' - ).format(CR="\n", LF="\r") + ).format(EOL="\r\n") # Carriage Return + Line Feed = End of Line stable_popup = tk.messagebox.askyesno(title=title, message=update_msg) if stable_popup: webbrowser.open("https://github.com/EDCD/eDMarketConnector/releases/latest") @@ -2144,17 +2144,17 @@ def show_killswitch_poppup(root=None): if len(kills := killswitch.kills_for_version()) == 0: return - text = ( - "Some EDMC Features have been disabled due to known issues.\n" - "Please update EDMC as soon as possible to resolve any issues.\n" - ) + text = tr.tl( + "Some EDMC Features have been disabled due to known issues.{CR}" + "Please update EDMC as soon as possible to resolve any issues.{CR}" + ).format(CR="\n") # LANG: Body text of killswitch warning popup tl = tk.Toplevel(root) tl.wm_attributes('-topmost', True) tl.geometry(f'+{root.winfo_rootx()}+{root.winfo_rooty()}') tl.columnconfigure(1, weight=1) - tl.title("EDMC Features have been disabled") + tl.title(tr.tl("EDMC Features have been disabled")) # LANG: Title of killswitch warning popup frame = tk.Frame(tl) frame.grid() @@ -2163,7 +2163,10 @@ def show_killswitch_poppup(root=None): idx = 1 for version in kills: - tk.Label(frame, text=f'Version: {version.version}').grid(row=idx, sticky=tk.W) + tk.Label(frame, text=tr.tl( + "Version: {VERSION}" # LANG: Label prefix for killswitch version number + ).format(VERSION=version.version)).grid(row=idx, sticky=tk.W) + idx += 1 for id, kill in version.kills.items(): tk.Label(frame, text=id).grid(column=0, row=idx, sticky=tk.W, padx=(10, 0)) @@ -2171,7 +2174,7 @@ def show_killswitch_poppup(root=None): idx += 1 idx += 1 - ok_button = ttk.Button(frame, text="Ok", command=tl.destroy) + ok_button = ttk.Button(frame, text=tr.tl('OK'), command=tl.destroy) # LANG: Killswitch popup dismiss button ok_button.grid(columnspan=2, sticky=tk.EW) @@ -2202,20 +2205,20 @@ def validate_providers(): if not reset_providers: return - # LANG: Popup-text about Reset Providers + # LANG: Popup-text about Reset Providers, EOL: End of Line popup_text = tr.tl( - 'One or more of your URL Providers were invalid, and have been reset:{LF}{CR}{LF}{CR}' - ).format(LF='{LF}', CR='{CR}') + 'One or more of your URL Providers were invalid, and have been reset:{EOL}{EOL}' + ).format(EOL="\r\n") # Carriage Return + Line Feed = End of Line + for provider, (old_prov, new_prov) in reset_providers.items(): - # LANG: Text About What Provider Was Reset + # LANG: Text About What Provider Was Reset, EOL: End of Line popup_text += tr.tl( - '{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}{LF}{CR}' + '{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}{EOL}' ).format( PROVIDER=provider, OLDPROV=old_prov, NEWPROV=new_prov, - LF='{LF}', # Line Feed - CR='{CR}' # Carriage Return + EOL="\r\n" # Carriage Return + Line Feed = End of Line ) tk.messagebox.showinfo( @@ -2386,10 +2389,10 @@ def test_prop(self): "EDMC is shutting down for its own protection!" ) err = f"{err.__class__.__name__}: {err}" # type: ignore # hijacking the existing exception detection - detail = tr.tl( # LANG: EDMC Critical Error Details - "Here's what EDMC Detected:{LF}{CR}{LF}{CR}" - "{ERR}{LF}{CR}{LF}{CR}Do you want to file a Bug Report on GitHub?" - ).format(ERR=err, CR="\n", LF="\r") + detail = tr.tl( # LANG: EDMC Critical Error Details, EOL: End of Line + "Here's what EDMC Detected:{EOL}{EOL}" + "{ERR}{EOL}{EOL}Do you want to file a Bug Report on GitHub?" + ).format(ERR=err, EOL="\r\n") # Carriage Return + Line Feed = End of Line msg = tk.messagebox.askyesno( title=title, message=message, detail=detail, icon=tkinter.messagebox.ERROR, type=tkinter.messagebox.YESNO, parent=root @@ -2404,11 +2407,11 @@ def test_prop(self): def messagebox_broken_plugins(): """Display message about 'broken' plugins that failed to load.""" if plug.PLUGINS_broken: - # LANG: Popup-text about 'broken' plugins that failed to load + # LANG: Popup-text about 'broken' plugins that failed to load, EOL: End of Line popup_text = tr.tl( "One or more of your enabled plugins failed to load. Please see the list on the '{PLUGINS}' " "tab of '{FILE}' > '{SETTINGS}'. This could be caused by a wrong folder structure. The load.py " - "file should be located under plugins/PLUGIN_NAME/load.py.{LF}{CR}{LF}{CR}You can disable a plugin by " + "file should be located under plugins/PLUGIN_NAME/load.py.{EOL}{EOL}You can disable a plugin by " "renaming its folder to have '{DISABLED}' on the end of the name." ) @@ -2418,8 +2421,7 @@ def messagebox_broken_plugins(): FILE=tr.tl('File'), # LANG: 'File' menu SETTINGS=tr.tl('Settings'), # LANG: File > Settings DISABLED='.disabled', - LF='{LF}', # Line Feed - CR='{CR}' # Carriage Return + EOL="\r\n" # Carriage Return + Line Feed = End of Line ) tk.messagebox.showinfo( @@ -2433,12 +2435,12 @@ def messagebox_not_py3(): """Display message about plugins not updated for Python 3.x.""" plugins_not_py3_last = config.get_int('plugins_not_py3_last', default=0) if (plugins_not_py3_last + 86400) < int(time()) and plug.PLUGINS_not_py3: - # LANG: Popup-text about 'active' plugins without Python 3.x support + # LANG: Popup-text about 'active' plugins without Python 3.x support, EOL: End of Line popup_text = tr.tl( "One or more of your enabled plugins do not yet have support for Python 3.x. Please see the " "list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. You should check if there is an " "updated version available, else alert the developer that they need to update the code for " - "Python 3.x.{LF}{CR}{LF}{CR}You can disable a plugin by renaming its folder to have '{DISABLED}' on " + "Python 3.x.{EOL}{EOL}You can disable a plugin by renaming its folder to have '{DISABLED}' on " "the end of the name." ) @@ -2448,8 +2450,7 @@ def messagebox_not_py3(): FILE=tr.tl('File'), # LANG: 'File' menu SETTINGS=tr.tl('Settings'), # LANG: File > Settings DISABLED='.disabled', - LF='{LF}', # Line Feed - CR='{CR}' # Carriage Return + EOL="\r\n" # Carriage Return + Line Feed = End of Line ) tk.messagebox.showinfo( From 4c0e3a908b3c5f8e294513fcef6d6fc1d9115c85 Mon Sep 17 00:00:00 2001 From: "Giampiero L." <54741923+GLWine@users.noreply.github.com> Date: Mon, 1 Jun 2026 23:40:36 +0200 Subject: [PATCH 4/5] Replace CR/LF with {EOL}; add killswitch strings Normalize localization messages by replacing legacy {LF}{CR} sequences with the {EOL} token and updating comment metadata/line references across EDMarketConnector entries (critical error details, plugin warnings, broken plugin text, provider reset messages, Beta->Stable notice, etc.). Clarify OK button comment to include the killswitch dismiss button. Add new localization keys for the killswitch popup: body text, title "EDMC Features have been disabled", and the "Version: {VERSION}" label. --- L10n/en.template | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/L10n/en.template b/L10n/en.template index 7d435be44e..e2e1760fd9 100644 --- a/L10n/en.template +++ b/L10n/en.template @@ -42,8 +42,8 @@ /* EDMarketConnector.py: EDMC Critical Error Notification; */ "EDMC encountered a critical error, and cannot recover. EDMC is shutting down for its own protection!" = "EDMC encountered a critical error, and cannot recover. EDMC is shutting down for its own protection!"; -/* EDMarketConnector.py: EDMC Critical Error Details; */ -"Here's what EDMC Detected:{LF}{CR}{LF}{CR}{ERR}{LF}{CR}{LF}{CR}Do you want to file a Bug Report on GitHub?" = "Here's what EDMC Detected:{LF}{CR}{LF}{CR}{ERR}{LF}{CR}{LF}{CR}Do you want to file a Bug Report on GitHub?"; +/* EDMarketConnector.py: EDMC Critical Error Details, EOL: End of Line; In files: EDMarketConnector.py: 2393-2394; */ +"Here's what EDMC Detected:{EOL}{EOL}{ERR}{EOL}{EOL}Do you want to file a Bug Report on GitHub?" = "Here's what EDMC Detected:{EOL}{EOL}{ERR}{EOL}{EOL}Do you want to file a Bug Report on GitHub?"; /* companion.py: Frontier CAPI returned 418, meaning down for maintenance; In files: companion.py:844; */ "Frontier CAPI down for maintenance" = "Frontier CAPI down for maintenance"; @@ -222,14 +222,14 @@ /* EDMarketConnector.py: Cooldown on 'Update' button; In files: EDMarketConnector.py:1742; */ "cooldown {SS}s" = "cooldown {SS}s"; -/* EDMarketConnector.py: Generic 'OK' button label; prefs.py: 'OK' button on Settings/Preferences window; In files: EDMarketConnector.py:1864; prefs.py:292; */ +/* EDMarketConnector.py: Generic 'OK' button label; EDMarketConnector.py: Killswitch popup dismiss button; prefs.py: 'OK' button on Settings/Preferences window; In files: EDMarketConnector.py:1954; EDMarketConnector.py:2177; prefs.py:292; */ "OK" = "OK"; /* EDMarketConnector.py: The application is shutting down; In files: EDMarketConnector.py:1936; */ "Shutting down..." = "Shutting down..."; -/* EDMarketConnector.py: Popup-text about 'active' plugins without Python 3.x support; In files: EDMarketConnector.py:2253:2259; */ -"One or more of your enabled plugins do not yet have support for Python 3.x. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. You should check if there is an updated version available, else alert the developer that they need to update the code for Python 3.x.{LF}{CR}{LF}{CR}You can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name." = "One or more of your enabled plugins do not yet have support for Python 3.x. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. You should check if there is an updated version available, else alert the developer that they need to update the code for Python 3.x.{LF}{CR}{LF}{CR}You can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name."; +/* EDMarketConnector.py: Popup-text about 'active' plugins without Python 3.x support, EOL: End of Line; In files: EDMarketConnector.py:2253:2259; */ +"One or more of your enabled plugins do not yet have support for Python 3.x. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. You should check if there is an updated version available, else alert the developer that they need to update the code for Python 3.x.{EOL}{EOL}You can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name." = "One or more of your enabled plugins do not yet have support for Python 3.x. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. You should check if there is an updated version available, else alert the developer that they need to update the code for Python 3.x.{EOL}{EOL}You can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name."; /* EDMarketConnector.py: Settings > Plugins tab; prefs.py: Label on Settings > Plugins tab; In files: EDMarketConnector.py:2263; prefs.py:986; */ "Plugins" = "Plugins"; @@ -240,14 +240,14 @@ /* EDMarketConnector.py: Popup window title for list of 'broken' plugins that failed to load; In files: EDMarketConnector.py:2285; */ "EDMC: Broken Plugins" = "EDMC: Broken Plugins"; -/* EDMarketConnector.py: Popup-text about 'broken' plugins that failed to load; In files: EDMarketConnector.py:2266; */ -"One or more of your enabled plugins failed to load. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. This could be caused by a wrong folder structure. The load.py file should be located under plugins/PLUGIN_NAME/load.py.{LF}{CR}{LF}{CR}You can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name." = "One or more of your enabled plugins failed to load. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. This could be caused by a wrong folder structure. The load.py file should be located under plugins/PLUGIN_NAME/load.py.{LF}{CR}{LF}{CR}You can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name."; +/* EDMarketConnector.py: Popup-text about 'broken' plugins that failed to load, EOL: End of Line; In files: EDMarketConnector.py:2266; */ +"One or more of your enabled plugins failed to load. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. This could be caused by a wrong folder structure. The load.py file should be located under plugins/PLUGIN_NAME/load.py.{EOL}{EOL}You can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name." = "One or more of your enabled plugins failed to load. Please see the list on the '{PLUGINS}' tab of '{FILE}' > '{SETTINGS}'. This could be caused by a wrong folder structure. The load.py file should be located under plugins/PLUGIN_NAME/load.py.{EOL}{EOL}You can disable a plugin by renaming its folder to have '{DISABLED}' on the end of the name."; -/* EDMarketConnector.py: Popup-text about Reset Providers; In files: EDMarketConnector.py:2146; */ -"One or more of your URL Providers were invalid, and have been reset:{LF}{CR}{LF}{CR}" = "One or more of your URL Providers were invalid, and have been reset:{LF}{CR}{LF}{CR}"; +/* EDMarketConnector.py: Popup-text about Reset Providers, EOL: End of Line; In files: EDMarketConnector.py:2146; */ +"One or more of your URL Providers were invalid, and have been reset:{EOL}{EOL}" = "One or more of your URL Providers were invalid, and have been reset:{EOL}{EOL}"; -/* EDMarketConnector.py: Text About What Provider Was Reset; In files: EDMarketConnector.py:2148; */ -"{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}{LF}{CR}" = "{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}{LF}{CR}"; +/* EDMarketConnector.py: Text About What Provider Was Reset, EOL: End of Line; In files: EDMarketConnector.py:2148; */ +"{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}{EOL}" = "{PROVIDER} was set to {OLDPROV}, and has been reset to {NEWPROV}{EOL}"; /* EDMarketConnector.py: Popup window title for Reset Providers; In files: EDMarketConnector.py:2161; */ "EDMC: Default Providers Reset" = "EDMC: Default Providers Reset"; @@ -828,14 +828,23 @@ /* EDMarketConnector.py: Popup message when user tries to start a second instance of the application with --skip-journallock, warning them of potential consequences; In files: EDMarketConnector.py:364-367; */ "Ignoring failed Journal Lock. Continuing at your own risk.{CR}Consider also using a debug sender." ="Ignoring failed Journal Lock. Continuing at your own risk.{CR}Consider also using a debug sender."; -/* EDMarketConnector.py: Popup message when user tries to start a second instance of the application ; In files: EDMarketConnector.py:379; */ +/* EDMarketConnector.py: Popup message when user tries to start a second instance of the application; In files: EDMarketConnector.py:379; */ "An EDMarketConnector process was already running, exiting." ="An EDMarketConnector process was already running, exiting."; /* EDMarketConnector.py: Inform the user the Update Track has changed; */ "Update Track Changed to {TRACK}" = "Update Track Changed to {TRACK}"; -/* EDMarketConnector.py: Inform User of Beta -> Stable Transition Risks; */ -"Update track changed to Stable from Beta. You will no longer receive Beta updates. You will stay on your current Beta version until the next Stable release.{LF}{CR}{LF}{CR}You can manually revert to the latest Stable version. To do so, you must download and install the latest Stable version manually. Note that this may introduce bugs or break completely if downgrading between major versions with significant changes.{LF}{CR}{LF}{CR}Do you want to open GitHub to download the latest release?" = "Update track changed to Stable from Beta. You will no longer receive Beta updates. You will stay on your current Beta version until the next Stable release.{LF}{CR}{LF}{CR}You can manually revert to the latest Stable version. To do so, you must download and install the latest Stable version manually. Note that this may introduce bugs or break completely if downgrading between major versions with significant changes.{LF}{CR}{LF}{CR}Do you want to open GitHub to download the latest release?"; +/* EDMarketConnector.py: Inform User of Beta -> Stable Transition Risks, EOL: End of Line; In files: EDMarketConnector.py: 956-962; */ +"Update track changed to Stable from Beta. You will no longer receive Beta updates. You will stay on your current Beta version until the next Stable release.{EOL}{EOL}You can manually revert to the latest Stable version. To do so, you must download and install the latest Stable version manually. Note that this may introduce bugs or break completely if downgrading between major versions with significant changes.{EOL}{EOL}Do you want to open GitHub to download the latest release?" = "Update track changed to Stable from Beta. You will no longer receive Beta updates. You will stay on your current Beta version until the next Stable release.{EOL}{EOL}You can manually revert to the latest Stable version. To do so, you must download and install the latest Stable version manually. Note that this may introduce bugs or break completely if downgrading between major versions with significant changes.{EOL}{EOL}Do you want to open GitHub to download the latest release?"; + +/* EDMarketConnector.py: Body text of killswitch warning popup; In files: EDMarketConnector.py: 2147-2150; */ +"Some EDMC Features have been disabled due to known issues.{CR}Please update EDMC as soon as possible to resolve any issues.{CR}" = "Some EDMC Features have been disabled due to known issues.{CR}Please update EDMC as soon as possible to resolve any issues.{CR}" + +/* EDMarketConnector.py: Title of killswitch warning popup; In files: EDMarketConnector.py: 2157; */ +"EDMC Features have been disabled" = "EDMC Features have been disabled" + +/* EDMarketConnector.py: Label prefix for killswitch version number; In files: EDMarketConnector.py: 2167; */ +"Version: {VERSION}" = "Version: {VERSION}" /* EDMarketConnector.py: Title of Notification Popup for EDMC Restart; */ "Restart Required" = "Restart Required"; From 38727d243879ae4904e59ab2db966427a718e4b1 Mon Sep 17 00:00:00 2001 From: "Giampiero L." <54741923+GLWine@users.noreply.github.com> Date: Tue, 2 Jun 2026 00:03:54 +0200 Subject: [PATCH 5/5] Unify CR line break handling to l10n module Unify CR placeholder replacement in l10n module Remove .format(CR="\n") calls from EDMarketConnector.py and companion.py to centralize line break handling in the localization module. The l10n.py module already replaces {CR} placeholders during translation parsing. This simplifies the codebase by eliminating redundant format() calls and ensuring consistent behavior across all localized strings. --- EDMarketConnector.py | 4 ++-- companion.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/EDMarketConnector.py b/EDMarketConnector.py index 0250256a98..b6e23db248 100644 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -365,7 +365,7 @@ def skip_journallock_popup(): lockmsg = tr.tl( "Ignoring failed Journal Lock. Continuing at your own risk." "{CR}Consider also using a debug sender." - ).format(CR="\n") # LANG: Popup message when user tries to start a second instance of the application with --skip-journallock, warning them of potential consequences + ) # LANG: Popup message when user tries to start a second instance of the application with --skip-journallock, warning them of potential consequences messagebox.showwarning(title=appname, message=lockmsg) def already_running_popup(): @@ -2147,7 +2147,7 @@ def show_killswitch_poppup(root=None): text = tr.tl( "Some EDMC Features have been disabled due to known issues.{CR}" "Please update EDMC as soon as possible to resolve any issues.{CR}" - ).format(CR="\n") # LANG: Body text of killswitch warning popup + ) # LANG: Body text of killswitch warning popup tl = tk.Toplevel(root) tl.wm_attributes('-topmost', True) diff --git a/companion.py b/companion.py index f5641f010c..c74fe9aaa3 100644 --- a/companion.py +++ b/companion.py @@ -673,7 +673,7 @@ def auth_callback(self) -> None: message=tr.tl( # LANG: Messagebox body after successful CAPI authentication "Authentication with cAPI Successful.{CR}" "You may now close the Frontier login tab if it is still open." - ).format(CR="\n") + ) ) def close(self) -> None: