From 8b3ef230f55a1a8cd93890f4ce9cbef21e453d2f Mon Sep 17 00:00:00 2001 From: Phoebe <40956085+C1701D@users.noreply.github.com> Date: Sat, 23 Mar 2024 16:32:21 +0100 Subject: [PATCH 01/49] Merge pull request #2181 from HullSeals/fix/2176/TCE-reported-split-issue [2176] Fix Outfitting Split LGTM --- outfitting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/outfitting.py b/outfitting.py index 2bb47c6d..a5ccb4be 100644 --- a/outfitting.py +++ b/outfitting.py @@ -69,7 +69,7 @@ def lookup(module, ship_map, entitled=False) -> dict | None: # noqa: C901, CCR0 # Armour - e.g. Federation_Dropship_Armour_Grade2 if name[-2] == 'armour': # Armour is ship-specific, and ship names can have underscores - ship_name, armour_grade = module["name"].lower().rsplit("_", 2)[0:2] + ship_name, armour, armour_grade = module["name"].lower().rsplit("_", 2)[0:3] if ship_name not in ship_map: raise AssertionError(f"Unknown ship: {ship_name}") new['category'] = 'standard' From 3cd6b57d5f1e90f38a9a3c182363a141d0871fc2 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Sat, 23 Mar 2024 11:39:29 -0400 Subject: [PATCH 02/49] [Lang] Update French --- L10n/fr.strings | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/L10n/fr.strings b/L10n/fr.strings index 93e09777..5d53fd24 100644 --- a/L10n/fr.strings +++ b/L10n/fr.strings @@ -1,21 +1,59 @@ +/* edsm.py:Settings>EDSM - Label on checkbox for 'send data'; In files: edsm.py:316; */ +"Send flight log and CMDR status to EDSM" = "Envoyer les données de vol et le status de CMDR à EDSM"; + +/* prefs.py:Label on button used to open a filesystem folder; In files: prefs.py:706; */ +"Open Log Folder" = "Ouvrir le dossier de log"; + +/* inara.py:Text Inara Show API key; In files: inara.py:305; */ +"Show API Key" = "Afficher la clé API"; /* Language name */ "!Language" = "Français"; +/* companion.py: Frontier CAPI didn't respond; In files: companion.py:226; */ +"Error: Frontier CAPI didn't respond" = "L'API Compagnon de Frontier ne répond pas"; + /* companion.py: Frontier CAPI data doesn't agree with latest Journal game location; In files: companion.py:245; */ "Error: Frontier server is lagging" = "Erreur : Le serveur Frontier ne répond pas"; +/* companion.py: Commander is docked at an EDO settlement, got out and back in, we forgot the station; In files: companion.py:261; */ +"Docked but unknown station: EDO Settlement?" = "Amarré, mais station inconnue : colonie EDO ?"; + /* companion.py: Generic "something went wrong with Frontier Auth" error; In files: companion.py:271; */ "Error: Invalid Credentials" = "Erreur : Identifiants invalides"; /* companion.py: Frontier CAPI authorisation not for currently game-active commander; In files: companion.py:296; */ "Error: Wrong Cmdr" = "Erreur : Cmdr incorrect"; +/* companion.py: Generic error prefix - following text is from Frontier auth service; In files: companion.py:432; companion.py:517; */ +"Error" = "Erreur"; + +/* companion.py: Frontier auth, no 'usr' section in returned data; companion.py: Frontier auth, no 'customer_id' in 'usr' section in returned data; In files: companion.py:475; companion.py:480; */ +"Error: Couldn't check token customer_id" = "Erreur : Impossible de vérifier le jeton customer_id"; + +/* companion.py: Frontier auth customer_id doesn't match game session FID; In files: companion.py:486; */ +"Error: customer_id doesn't match!" = "Erreur : customer_id ne correspond pas !"; + +/* companion.py: Failed to get Access Token from Frontier Auth service; In files: companion.py:508; */ +"Error: unable to get token" = "Erreur : impossible d'obtenir le jeton"; + +/* companion.py: Frontier CAPI returned 418, meaning down for maintenance; In files: companion.py:844; */ +"Frontier CAPI down for maintenance" = "L'API Compagnon de Frontier est en panne pour maintenance"; + +/* companion.py: Frontier CAPI data retrieval failed; In files: companion.py:856; */ +"Frontier CAPI query failure" = "Échec de la requête à l'API Compagnon Frontier"; + /* EDMarketConnector.py: Main UI Update button; EDMarketConnector.py: Update button in main window; In files: EDMarketConnector.py:601; EDMarketConnector.py:919; EDMarketConnector.py:1748; */ "Update" = "Mettre à jour"; /* EDMarketConnector.py: Appearance - Label for checkbox to select if application always on top; prefs.py: Appearance - Label for checkbox to select if application always on top; In files: EDMarketConnector.py:710; prefs.py:875; */ "Always on top" = "Toujours visible"; +/* EDMarketConnector.py: Unknown suit; In files: EDMarketConnector.py:837; */ +"Unknown" = "Inconnue"; + +/* EDMarketConnector.py: ED Journal file location appears to be in error; In files: EDMarketConnector.py:906; */ +"Error: Check E:D journal file location" = "Erreur : Vérifier l'emplacement du fichier de journal Elite : Dangerous"; + /* EDMarketConnector.py: Label for commander name in main window; edsm.py: Game Commander name label in EDSM settings; stats.py: Cmdr stats; theme.py: Label for commander name in main window; In files: EDMarketConnector.py:913; edsm.py:332; stats.py:57; theme.py:290; */ "Cmdr" = "Cmd"; @@ -64,6 +102,12 @@ /* EDMarketConnector.py: Help > Documentation; In files: EDMarketConnector.py:933; EDMarketConnector.py:953; */ "Documentation" = "Documentation"; +/* EDMarketConnector.py: Help > Troubleshooting; In files: EDMarketConnector.py:934; EDMarketConnector.py:954; */ +"Troubleshooting" = "Résolution de problème"; + +/* EDMarketConnector.py: Help > Report A Bug; In files: EDMarketConnector.py:935; EDMarketConnector.py:955; */ +"Report A Bug" = "Signaler un bug"; + /* EDMarketConnector.py: Help > Privacy Policy; In files: EDMarketConnector.py:936; EDMarketConnector.py:956; */ "Privacy Policy" = "Politique de Confidentialité"; From b9f22f0f3a433159cb349a9ffaf6045e63c24f75 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Sat, 23 Mar 2024 12:01:54 -0400 Subject: [PATCH 03/49] [5.10.3] Update Changelog and Version String --- ChangeLog.md | 19 +++++++++++++++++++ config/__init__.py | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 480d80a0..6ee5749f 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -6,6 +6,25 @@ This is the master changelog for Elite Dangerous Market Connector. Entries are in the source (not distributed with the Windows installer) for the currently used version. --- +Release 5.10.3 +=== +This release contains a bugfix for the shipyard outfitting parsing system and an update to the French translations. + +We now sign our code! This does mean that built EXEs are now slightly modified on our developer's machines. +For information on what this means, and opt-out options, please visit https://github.com/EDCD/EDMarketConnector/wiki/Code-Signing-and-EDMC + +**Changes and Enhancements** +* Updated French Translations + +**Bug Fixes** +* Fixed a bug that crashed the outfitting system when encountering armor. (Thanks TCE team for identifying this one!) + +**Plugin Developers** +* modules.p and ships.p are deprecated, and slated +for removal in the next major release! Please look for that change coming soon. +* Note to plugin developers: The `openurl()` function in ttkHyperlinkLabel has been deprecated, +and slated for removal in the next major release! Please migrate to `webbrowser.open()`. + Release 5.10.2 === This release contains updated dependencies, some bug fixes, a few minor enhancements to some supporting files, diff --git a/config/__init__.py b/config/__init__.py index 0d16693c..3acb2edd 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -54,7 +54,7 @@ appcmdname = 'EDMC' # <https://semver.org/#semantic-versioning-specification-semver> # Major.Minor.Patch(-prerelease)(+buildmetadata) # NB: Do *not* import this, use the functions appversion() and appversion_nobuild() -_static_appversion = '5.10.2' +_static_appversion = '5.10.3' _cached_version: semantic_version.Version | None = None copyright = '© 2015-2019 Jonathan Harris, 2020-2024 EDCD' From 813cf92521045cbe121c5215e4e2d56859738ce5 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Sat, 23 Mar 2024 16:54:13 -0400 Subject: [PATCH 04/49] [1133] Add ContextMenu Globally --- monitor.py | 2 ++ myNotebook.py | 54 +++++++++++++++++++++++++++++++++++++++++--- requirements-dev.txt | 14 ++++++------ 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/monitor.py b/monitor.py index 8364f95b..e7f99543 100644 --- a/monitor.py +++ b/monitor.py @@ -63,6 +63,8 @@ elif sys.platform == 'win32': GetWindowText = ctypes.windll.user32.GetWindowTextW GetWindowText.argtypes = [HWND, LPWSTR, ctypes.c_int] GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW + GetWindowTextLength.argtypes = [ctypes.wintypes.HWND] + GetWindowTextLength.restype = ctypes.c_int GetProcessHandleFromHwnd = ctypes.windll.oleacc.GetProcessHandleFromHwnd diff --git a/myNotebook.py b/myNotebook.py index 6fa35774..02b1eb45 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -77,7 +77,7 @@ class Label(tk.Label): """Custom tk.Label class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): - # This format chosen over `sys.platform in (...)` as mypy and friends dont understand that + # This format chosen over `sys.platform in (...)` as mypy and friends don't understand that if sys.platform in ('darwin', 'win32'): kw['foreground'] = kw.pop('foreground', PAGEFG) kw['background'] = kw.pop('background', PAGEBG) @@ -87,7 +87,55 @@ class Label(tk.Label): tk.Label.__init__(self, master, **kw) # Just use tk.Label on all platforms -class Entry(sys.platform == 'darwin' and tk.Entry or ttk.Entry): # type: ignore +class EntryMenu(ttk.Entry): + """Extended entry widget that includes a context menu with Copy, Cut-and-Paste commands.""" + + def __init__(self, *args: ttk.Frame | None, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.menu = tk.Menu(self, tearoff=False) + self.menu.add_command(label="Copy", command=self.copy) + self.menu.add_command(label="Cut", command=self.cut) + self.menu.add_separator() + self.menu.add_command(label="Paste", command=self.paste) + self.menu.add_separator() + self.menu.add_command(label="Select All", command=self.select_all) + + self.bind("<Button-3>", self.display_popup) + + def display_popup(self, event: tk.Event) -> None: + """Display the menu popup.""" + self.menu.post(event.x_root, event.y_root) + + def select_all(self) -> None: + """Select all the text within the Entry.""" + self.selection_range(0, tk.END) + self.focus_set() + + def copy(self) -> None: + """Copy the selected Entry text.""" + if self.selection_present(): + self.clipboard_clear() + self.clipboard_append(self.selection_get()) + + def cut(self) -> None: + """Cut the selected Entry text.""" + if self.selection_present(): + self.copy() + self.delete(tk.SEL_FIRST, tk.SEL_LAST) + + def paste(self) -> None: + """Paste the selected Entry text.""" + if self.selection_present(): + self.delete(tk.SEL_FIRST, tk.SEL_LAST) + try: + text = self.clipboard_get() + self.insert(tk.INSERT, text) + except tk.TclError: + pass # No text in clipboard or clipboard is not text + + +class Entry(sys.platform == 'darwin' and tk.Entry or EntryMenu or ttk.Entry): # type: ignore """Custom t(t)k.Entry class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): @@ -95,7 +143,7 @@ class Entry(sys.platform == 'darwin' and tk.Entry or ttk.Entry): # type: ignore kw['highlightbackground'] = kw.pop('highlightbackground', PAGEBG) tk.Entry.__init__(self, master, **kw) else: - ttk.Entry.__init__(self, master, **kw) + EntryMenu.__init__(self, master, **kw) class Button(sys.platform == 'darwin' and tk.Button or ttk.Button): # type: ignore diff --git a/requirements-dev.txt b/requirements-dev.txt index 73ab5465..41c3a928 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,7 +5,7 @@ wheel # We can't rely on just picking this up from either the base (not venv), # or venv-init-time version. Specify here so that dependabot will prod us # about new versions. -setuptools==69.1.1 +setuptools==69.2.0 # Static analysis tools flake8==7.0.0 @@ -18,14 +18,14 @@ flake8-noqa==1.4.0 flake8-polyfill==1.0.2 flake8-use-fstring==1.4 -mypy==1.8.0 +mypy==1.9.0 pep8-naming==0.13.3 -safety==2.3.5 -types-requests==2.31.0.20240125 +safety==3.0.1 +types-requests==2.31.0.20240311 types-pkg-resources==0.1.3 # Code formatting tools -autopep8==2.0.4 +autopep8==2.1.0 # Git pre-commit checking pre-commit==3.6.2 @@ -38,9 +38,9 @@ grip==4.6.2 py2exe==0.13.0.1; sys_platform == 'win32' # Testing -pytest==8.0.2 +pytest==8.1.1 pytest-cov==4.1.0 # Pytest code coverage support -coverage[toml]==7.4.1 # pytest-cov dep. This is here to ensure that it includes TOML support for pyproject.toml configs +coverage[toml]==7.4.4 # pytest-cov dep. This is here to ensure that it includes TOML support for pyproject.toml configs coverage-conditional-plugin==0.9.0 # For manipulating folder permissions and the like. pywin32==306; sys_platform == 'win32' From ccda74c8f103cff0d63d3d605a0de076f53a77d9 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Sat, 23 Mar 2024 17:05:14 -0400 Subject: [PATCH 05/49] [Minor] Remove Crappy Type Hint --- myNotebook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/myNotebook.py b/myNotebook.py index 02b1eb45..63bb7dc8 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -90,7 +90,7 @@ class Label(tk.Label): class EntryMenu(ttk.Entry): """Extended entry widget that includes a context menu with Copy, Cut-and-Paste commands.""" - def __init__(self, *args: ttk.Frame | None, **kwargs) -> None: + def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.menu = tk.Menu(self, tearoff=False) From 791a0c80c2c0b202d27a636c36302229af88c328 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 18:36:03 -0400 Subject: [PATCH 06/49] [Minor] Remove Deprecated Files and Functions --- build.py | 2 -- modules.p | Bin 44802 -> 0 bytes ships.p | Bin 920 -> 0 bytes ttkHyperlinkLabel.py | 41 ----------------------------------------- 4 files changed, 43 deletions(-) delete mode 100644 modules.p delete mode 100644 ships.p diff --git a/build.py b/build.py index 1bc96765..904c4c5b 100644 --- a/build.py +++ b/build.py @@ -76,10 +76,8 @@ def generate_data_files( "ChangeLog.md", "snd_good.wav", "snd_bad.wav", - "modules.p", # TODO: Remove in 6.0 "modules.json", "ships.json", - "ships.p", # TODO: Remove in 6.0 f"{app_name}.ico", f"resources/{appcmdname}.ico", "EDMarketConnector - TRACE.bat", diff --git a/modules.p b/modules.p deleted file mode 100644 index c48f76c4894fdb061e0a1967f388afe819e679c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44802 zcmbVVO{^SOR(2f6`I!tP*p3}LKQI4ICIgvd@-t#2KMAC#(UT#9k%Cz8RIj_=du{ih zy1E^EMnPU6VDWb234)b3NU#~PMzfeTg3YX13}S`E27v&fS#av!ulm-h^K);<o6)4c z^WE>9bMLw5R@JM%f9}Ws^OG~--|5!|^T}j1SdHhi`oZbfes?(>El0!O9uHOze)Qn& z-+OTV^g=bH|8`I<r}Opl;CNXLN8ftz#e>sx)2gl??4PMM#QTIeIlup?dhvsJ@v-{! z662nZm&-YgZd_iDD$;ppw7L9THLC{m*{~AgXlT-<Ux&1ptm{zs-TL%OpPviV5L_c6 zo~`PIAx~U_vP+5;M7`6*GZAt<y^CB5UA){_)`R(aWe73=NtOXf;+_{n2#FFRgg$>b znyinj$#|yByO>%N0<phepPCTJ{p<Slnlca<Y=F3A0$mx*50};S_INxtf@>il_*ZNW z=)G2-UX`P8xjKfcCCufP=Z+!P03@vjAW3~*3?Y<Ch!A>luwJdqNuXVYL|Wb2Rp_I2 z`5b5F;^cL%jIKXF99L7SJ%`ocwh=@V0*zmHSRnK&%~53_uGRo?$vx2Bi6Oc>Tn_}< zm${}M2*Q7(K7FwxJb{FC9md5I+oj=rvN##f4B6^s2;MQQA@v5WhaNc>sQ|b<0$dnX z$CHsEPPqta=Tu7wdxCT`S}sdm=A!8G3!~{`yc``+$zP7mRpg<POb?axzNC*Rgc~^F z!Bz0FFl<_oxE0u#q~69P?X8DwETLRQ3EkJAd)0JHvUiHY9T1dL6>~t4PQ~a&bvUlw zgmLi%d*x_EqN}DQq^YyKGolh~%<L>QIg*7YcV2S@2&X)->)LQRU(_dKt2^uJRiSY0 zT^=wM3fDfXPrGXSQ0`g=%v~e!o1LI-n45;gNL?8|Ia!8Jo?g%C5$<L!gwH#jF^<<W zC!0BB@-v4_9=>XiE_`#a!mBGsBRYjms@cF=b`}C&T%cak;DGu!sh5-pu3E=%wS>8N zQmrRujnl3|<s-T+6rQCPjWcs~@;X;W*IzkV&`D=_rwQb6HD4|k_a;=*j>dOK!-Gk+ zJjO|qcFI>h=yWt3ucz_UNgK9HTTiRWBtl8S3xRgF8n0)!XY<c#g05FX`rm`qcy=$K z_HO*wKQ{mVspVY_*VDrz+O?<Sx*k(YVaqk3J-N{}fnBYa%h9SAhS!2#3)>@pF@mS- z$!a{PW-}wSFIli2oq|&}zAX8G>k;lWz{9E@4-m>_)2eIX3>h_$TafbHUkSsHs_CSv zX?etPPuA_Edxn~S4Z-K-RSnXUq|$ILA-0D-Edg?HGOAXa`P!p89#0Re$pI7HQv?WC zeT}OIrYBn`;<|enbw2b4)8~Rt#0R_7sAdzHIsTlu%$>e0uJ;_41bqDNbuIGU0o1UE z83zaSm@5=qLl>Y%yE}#+YK4N25$eW(%I~~x#M0WR$3GaocQBxZQa5)NPtJF$qKl3@ zNhvz+ET!mgZ>8kJK01`CLA9=_IPy}iPK%T3=x9={XM+=phqgP!I85g2VR_UHv=KD} zZA8sL8&NaRB5Kjg<#;+O_tHQcUK(h_O9O3qX`qFdVZRwJsVR^<Q*U;J9l6&MnETl4 zO$oBWJ?d|kpf~+f+#{&{d8f#%S<CZ{O~wmeAKvu`2;iQqw%HpsPcoMC*?2&=JZ5y` za5}2$HQfQxR#ezHXwluC&X=pI-JyFy3LRVrq}ROAV;#}pC(T)TvyS7Q-(w81kXW7g zjV2by>uO2&(q;$8R8GRW*tA+b?l1uyI1lt&jC?^Uqvo}(L0X@5J#WwxR4@eB<PM?k zNN;<h^r)5$!e#Nm)+dw@)+z8-fM-pjdqK*Pb162t8lE><c)D8j*ktLsn$To7J!Cze z-QG+dP;09$RQM@9+1Y^ART9>n0^_5H$XTd^@pQ4C)Hvi(i3nRVp~ti1gX(a3IH_0d zs^_%9sXh=sab$=tko9O>PX{N<<Ik(*$q)^HFV$f^=y*LHVXC$U>q9DLN5gTwpnYR= zH1vkhEw~S10a-(Q1yyRG+I&*%yXT><cFIsF$x%ud#r3vH?@<Mi+!xyUwm~Z%wI}uN z$f_4n-?A!cP8_UgO&qLfOdPCeOB}3dO2QFI9_HB@DDq_v{4v!6)J-+D5uwh=;UcP+ zMuHn7YcoTPY|M<XX-fqWO{HNzJB|&^W@2`jwF8=PTs@`52`Q<1@v+Fb#{z|E%l9KO zq_PGm#ugbLG8D(yEL4L5bzJnMVBXeIHd{iQYazM9&{Vq6-jrzX*;zKdXog%z>|#Ei zt%jqcQFD70f#_^hzliU};C5UzsZZvE+s=O9VVBUJl1@-0mPgv4RcBS`Dy3TeHh@oD zBto5Mh6sJO86p7YBEo&Cu$gza1vc42`4SL5%R&(mm|lWHVKP7mwD&I83!3knqm4c; zm*2-|#iOrH&2m_w9c_Ag4Jxjw4^k7_A5YJuLB+=lw;+@B!}YRWX*WeflcwW%GGiTT z8oV$kx`e%qI+R>v=+5-91CU;xs+!kPHrs;AtYudftEM>Chn`z{o;_0Tn2J<0t`4uK z-6Q40hnt4WYCNH5bb4PLW`~A22zlMCws3Qi<M>d4h@JzECd0$|yl&ndQtmEpio6ex zecC=fsPb{KN86`9!N<k^ta&NY$DuddeY)L?LI7)eCyus^cGd9J5D68;!LpjQ&m3se z43)IU)LSmvU_8j2M4iT=<ZZ^$=dViRjik<4K9W9F`AER<kpj)#(QI>5Iy?_jZybeo zsso+gem_2EQqeo(*>JQN(Oass)q(pyNDhhV_;h`mLt;YGn_92hqx0vfK9)aQCG7Lm zMA6zjKE8KY-3v?X{q7C?eG+Lx;Kz9l@@>X)(Sd;FDGl-wV|mqqfaO_w9^QBq9!rG# zt4-DT7NemTiWLlZTgQA*z{4Hac|I)Q;jZgE9~ba^(#Kp6@tM;b+BLlxv{=sPN114q zS|A6cHESWF^m3zWI9k!>G8#5_N2<Z*(ZQyxZ{7ueApoh5ryBu-Io%lwua)BEfVjU{ zsCre=>RsZs^j0RlV>27k+vjvpoX~4h?Mw7wEwG8RcVn~N1pf*QV?@4!p}1R6IwH0v z+QLdL;wIH>dRYrT|F^Kf%-F&Lm5=_kpi~t+r@gV%0-l#x@D;m-1w7xv0-jUJ%=!UU z@O-D-0-l#x@EWs)1w7xv0-k?b;0IK}^ZVr%@SH5Z845{v@ee~8sOautd}mT@9i2zc zW!7TBl$r6_Ml+$zjHilRd`Gx=v>r{UcbV1n(wJ7^HZL)in~EA&ZYru=xoN6%<u)<* zog@~R@(fZrDz`~RuiPe;y>gpW_{wdt49ffw)3IP2*rf7TZj%aNxlJm8<u-@`Ew2I_ zzP6}DmD{93SZ<R_VYy8zhUGShfm(8@HLMr(9G-3pdzDb`Qo5n26QzctN|YL=8c}K? zDn!;$)Q3`wR2@n!Qf(-;NR^?~BGrYgg{TUp7O5tbTBM3lYLV(esYR*=Sqo7MN-a_) zD78p+pwuE&fl`Z916~vT!m??J+~x1t@WnyhzXulc$piBgP^<I0B7ISf{nAxpB+6Ea zktkUuMyXttphc;2jd&(#+b=<<5><ju<*5XnN>d3sl_eJ~rcenwm7@}LDn%veREA2> zsRX%bKKE(sE<vZ#Q-V%qrv#l!P6;}dn|GBpThpI7(w(32;v`ddwlNlKcpGD}mbWoZ zYkC_iv9^nh#TwtnDy{WxtkRm_#wxA-ZLCraD6$f@U>mDc6SlERwP72pR3o;rO0}ZM zO4N*PtWxdR#wyj2ZLCr)*~Ti>6naiV_mR7Ib?EKvJENMOE-y#*s9FwA!cF4NU4YAt z$!K;=?=pr?hdl|{+dbDlyfbi!4n15n04N|?BDhX3@EAlW3yCP)3zy12JUFWARdh3f z`=p{=7=Tn63_vOZ1^|xHJx~LXmUiDGi0pW@Pt8l8hCfZ9CrJhXt|$=(16;8g;L0=R z5O76d5Cy3(5&(!)q6Gj%(tQhq0U~!y07NPb{HfD*$p8REDscb+B5ekU+%<=QNQFTZ zvwj=^fJh|{06-+QPzD1;()q#wK%~OJpSwMj3;;l+5(fYv(q@PvZ=O*q5GbIMD6TcN z?r3~`LQl=w2fkurY9KK&G!Rb=eSsi6)jO((G%EcmG<}OIb1x}_kFn}JPRrn9=sKl7 zgGajQpqc^3fEEy2dx^ylJSGKYGy{Z(smf>Y@Q^BC1_%%H#9|w<hyjFaPK*J>yr*)X zVT4aqFf%|b1BX#;Bo-rpaK;Iz*jO@*aE1zN1_)<pqX{oFG!J&@lVEfDFqrwmgNlI* zXFMLH!o@(ii-Bex!<I_(q+juiFAo>vY6g$185mbHpZvNWKJQ(Os~J45W?)>+e2(jS z`1E!$u4eGKnt^dO^DRo(!`mkp<7x(vs~H$qGv6_FJ-nN8F|KCtxSD}+HS-Nz*Tb7D z7vpLMkE<CNS2J(4bUnP+axt!E@VJ_J&qZT}_vgZc_iA>#Tb|QU5`yaEL9p082-cPd z!BqAjm^mH<iSi(bOM-;6Ui(L`)FgJ_^KCvKaJ}>WfYT>$t*48Cc(8wN9p3^oY?~de zYkTV&9pU%S`$ml{VYIjVay<O|w#{@<Y+t<}jD6c?YAd#HwBv?Hxviro>j~Y(7|)L8 zbdPj8qE=pR_S9IF+hFsjKC{3EQ!;+pVV`=QavO|OrVaBN<4{{yFb-@mPMJ0=4va$` zSHU>2!8m2wu);9TPSH59!8oKX+zo5z!E`=sKGl?;3ENm<ESd{NR$?}6V}-G3J``Dr z8L^EO#-ce<WF=<BHdYvm=0%Z}m>JtxVJw;(;htwZHx~2Ho1-@U-Q)Ohy*Y1Fm1(N! ze;<W^B_@%cZhy9)waSkYOZ(pLrC7X5Mu|J=-Y)80i3yqk`nYml(MQ4W{dY>RA4lx> zOR%3r?BC#ZWEOk+<2@8+gz(1yw((#)UPx2|x50b-gYeI1Zo_u@FPndV<%46u_IBTD zlkdrh5!>7SxC9(Swzs=i0**1;+x@Hsv&kO+)Mwk0ma)PT>6bLi$}eddD~#1IX_l2= z(lS;Ut6$PAE5D>=tT0x;q*+#eNy}JathS^TwmYE=xLEMgJaDig`*|#QDd!GWWIB%p zFXh+4imc|b;H6wTSdqaz7QB?Va98-`-h#HEC4J$)|2(bfblY2sr;pDUtN7Cc@0~tA zt?o8Qqz8L9{xufB)5n|tPk+`=|LITv>>FpF{@&l8KH2=IP&Xg!pIv){HHv7k{YP#+ zXqx|zZvB}4XTyE#%kcmH<Olz<_mhi1y!96i#OG^|2d(%>`(2gx{^8A^|Ht3{vV;~V zhy8PrZy$XB7R&nfGTYMxm-&aF{r9+)gZ9sVwEF3-KmI>gW@qj;(R?h*{1klu88Zbw zBq{Li?LHE(=}7`@o20Xmww1|gyGbgeMXp-4Lse}zNoBNcuAYc$zW^;ZcO_S4v`AU2 z_Dj(I(#%zcwo?|Glsy&H-n{Zi;N3r~ChKh6lJ#VPuuWE+syBbLN66DuLfEDW3je4_ z$P-jT*e2+i;PT$?5C0(aT`{1W6(N`Y-fjtdn<vQq`q>!JN0rr-A?y^`CPNovhTe;W zd%I7?WT=UHG!_OuQQ&P873b;AJ324VR|#*MFX;WL&dbwQ!rP{8C&uCSqe$2@EDqc2 zZ4(B)SI@<SJ*Fni6^i>`%>lki*!3v%XRXjnP8r1MNlzGf+l0k=d-Ibhl#Wr1mj|GP zw@n!I{+-Ut6IR08CTusx;h!Hv!mc_AE8%Su2E9)_9uxM2nlP6TcO%<`eHw*6Y=yoO z&tvKeJ0Gv<2?KANFwEHRpGN>VFHcwrZ<{daMF948IWJFG32&RQ`!Npx@C5X};Y_d+ z-Zo*-d-@c3-)8Mgx6jzyb$M}%xXs(cpm+aFoCjyreBrpP=L>vozT$-K^YJ{D@U?l; z_3`|a@F73+28ZhK_5$0)=mL2{HUh(4fywx2RIe8c`jV!+x7>N(!2>tpZf-XHA}%G| zoG_T1Sa$C7``{)}RDkKc<&EEXpQmKUz0IM-U<NpP)_g}q9UmyT)OH*`7%tIK&!dD( z8Olz#PEn%Q98}6q^X<eEsOU?M3r^6v(i<^4VRCgESJFlAHK<&jZj?|~*nooi3>VbX z>D3z%>MgELQ%Ab!%{rB<)1nc|iWg8&pW%XfdaU4$2=x|Mr^6v#*A1>tzd|T0UO+*8 zh70O<{Sl$w;_7Vor0Y|ItFw6%%8D0IP@my~`uqNfP;YT{Ha*hy(BSH9WrVWg1r*e0 zxT5;--k>^lKnD3l_KoJ{!6|*CgMJ!ge$Tz*hKF5Lskbmfc`Y<z1-z*QB_r`dUN{o3 ztF&rMM&f0*P#&*=w8Bb8;w7<A9<NtBWh3$OMe@Sm`xHNoEJ3F&)<uitm!Q-9a?v8) zC1`L{o?Wy^a0wdRlvx)oQd)urH|6r}u)3S?nX*5hps!)jmv%xk$OA)PhAK8eL88qw ze90nwtd)&2r#r^sqZ@U1q_1d(viz&2K>ACN!8+cY=F5~qZ1^NilDP07OZv2)(H-z* zO+UQSyrsc6mM`#xxX=nU__RKKOV3jC6*E0@g$5~R;l0xZefFRJuw=9xREP9ijg13r z$#oiL3(sdu`_ipK%v0b1`Qo9;WDU(LVjh@MX)*G(MQv0Dh-H-rV(2^&337m<iL*5F zKJL2hjA-RDjL=Ao;m;+ShuhRGEa-a>)!?LFk5~AH`x*KwZ!?eecNMxHEbAOOvlcPt zopWc_A_jk(G2kIJ4q5WJW{b$JrDc!7`xrWqW})yk9U-$8@Rhc-EEK+$kc+Zllk>vh z#vD+rCaNJ>R(MAhKMO_mby-DivRQd`a>ENK+@eC3WrbU`pJ$<P%ViaH&t~P#p&M5~ z;TDy&EGyiiJ~a!4TP~|8l{PCcmTp`{xy-V{tzFM8u)-~>tv0JT2xp<#r`)*m&gIhr z0dVVn0Tgbztm1@hyCsgvStusqLr*JMqg&y?oTY_dL>pd-=)LS^6?_MaOi`(KK+&1b zp5tJVBr2;8D7uj$6eV3F6vf;D!Hu+?I9RwrWz+$|4WCeyaE(wDZwG{_Mf-*Wf_|!( z4hXZ!U=l@IV-n@r0YNzJ3=RmwsUkWc2sfBS8P=FY0d_zTPPN|wK{(Ys2L#~;lPI(r z6F{lNIv@zA>h6FbeAfj*xWOb!sWzM_q7DecseU^k2*2-wAe@-OU&Aa%NAy94W&9>J z`wnmOw}B=E(e@ya>_H&dgFvndVdY(y%Nux)#ghvbPc9&yTwcFbExdYr5Kk^xJh^~) za(SIrweTwKK|Hx&@#F#`<Tjrk)4s6UnG6yl=B|VYxe_AeN{A=dn!6nqYwk*jC)b+0 zlEss2&D{=*HFqV%lWWag$>Pbi=5B|@n!6I>$+hOLWbx$k&LXX&4h!!qJcuV3EZ*D& z#FNYW2~`X4COn8I7c8D!Ks>p;i%_-j9>Rloa>3%s1;mrfdk0ku?;JdcCl@T9TtJfC zE6x2xx@BF@m+=t-YZ*ER7z-GSZ|Clz1&qoI7@?mISQb^3?@_U8+_~v47<o;mQ=)}{ z{B#tufRIlID+>Yn4i&G?bbJw1yf|yI0s<4p;ecQ|Nm-*{x@a7{Fw=QOaPYdUg#`#G zbvU4uj!xDnP^xk8noI{2!NE(i77rkx)Zu{A9eWfg)i`)LrW1)!%B!&!4<Mk_;egUz zdlV?uICv$dBZyGS3$YdtAfVLYfYST+C{U_#@FM(B;ovn`iw6);>TpD*;f9w82(Q3I z5}pmkKk%Yolbjs(K6Vh_2<g<i3|`dZ3_f~O&W|im#mNxIWE2ovwc6qrB|8IzhpF6V z@bHi-RR#zT^TeW@Tg0NOXMmWBRG2eB_(U}=1H=+?7)8am7)9aF0O1VP?hFvlP}$1> z;f%v5HU*1O><t+poT2ib0m7M`ED+8(jAGxgh8EjL1_)<p2gm^73>D7|5Y9M^Vr#J& z#SW7J!Wr5mGC(+UKMRC24x`w8tf9pwlmWsSXBz=ybS7*`8A^CVly8KyLHI4n;}P9c z48L>S`Etq!o$saI*!%(x{Wc$+C~T|9-`N+!n>L=oLFdP)JH5O)khP)Y3~(Qb4goo2 z40}h587gS$hAQnBxnVE^X(!4d5!6I&1{H!n>;|=Yx7-{-Y+gAe!blxL4vE=Iqnq(- zPcdn#m54>)XuHcvz-%W8X2c+YM~wCqlUnSMIV2+H<yoAO%!swfPQ(htB4V_s=ENdm z#A!wh5_rUD<1(qmHk?BuVqSv9S<Q@Ci|j<KKrAA*lXnXdBTh47kia8GyQ3KgvDfF2 zh?tjPab`3l)*?F*D-er_?dIJ=#E8?37$oqB(H3mRK{OOOBqHV|Se#wWh_%R0#0tbB zV)yfIA!5X7Mhp^o#2z}-qH8fDCfb%9GW9KH#K76vIh#N7$Pvegg+3<-MaYQM3>h@A zkloy+1|j@L5dFILgnotka6Y_8AC4N#>8<5^^b6@TYLyNu_RFfY7lxOeJqv1^M$6`> zsH^sMPqNC6!+)EVEG~uiYfbNk50>jOeYwA`>7!Qh4*<{51K`{A>*1?|N%JY|gK9aY zpA9)UURJ{q{_@0wU_o4USdiBb>4~*65dXzx1H^x7nLt+})AaUuY$&!65d6B$0lmLP zU(J=HaJf2$t0l~ZX*E5p457+JXuP0WLf)H{Rz}N}iOXCRUH&!t@S&wiUV|k1Qkc93 zMW5BD7rUHXQ2#2|(_CHLTQxsaqfbEXYMOi6)imv%<IG$aO{U&;uB@4C^>{e?y!p{^ zTEpt{un<sqwq9R1S)h{|y{mE@u2siyy@a{2qK^iBWJpymLM8nXigFS1=;zHZF<P!n zT;`(aa-ja$6U8q=)Q)NiQ8yrJW64E{%Ul#)4x+x}iQ*R_YG1X4s4pREW64E{%Ul#) zexZr;cMhiG$#_-KOFR0M^H52qhe~>1(nl1+4V>^G%#^za?;Fz9%g{{ioq8E!e~11Y zq7mC6=PDHdmq!2$@PRLnUl#KCWg%~K*^;*b2zg;r-ZjK27n3yQViE?gF`I-eep!mT zGp6>z5+yG}6rG_j$cqs5B&C8~<f6o7E{ZN+iPqEw+%c3{h$PQKB#l?)C_<=$5o#~p mp+5**FGq${^)hrm+eAvShRD}wRrD@%g$jVnd#zso`u_u+#+$AH diff --git a/ships.p b/ships.p deleted file mode 100644 index d289497c9540f529b38d01a580f36eaafcd68c26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 920 zcmZXSzmC&D5XON^LP$am4hrZjXrKrJ3J@J8zT+aty3^&95@}=a#jD%wT08556i5`5 zi-d%s;SH!L5G4hVz!OmM1XNUvy|$ABSJwRI&o?{YtH%2`8)u5obVJEG4K<SjGSl5t z5mhwuSg5mi+3kbumT9^X#<G{0X~!w&0RhPTn_#ZEoHHUq>I`FoJ;c1oid(_=vtYK? zD5FQ3Fo7))zD0O>1yu^fwnz3GS=$vPlp-Rl^qvcev;89BQdJ|aVdjNAJPBp0i&Xyu znBEi0(>Za*OjMa)H^6j<a;AtA9FImLoBIV!rw&eS><5^u9wQ4JJ|p4rKNB0d?sdF2 z`4gD)p5#efF6kRE&22L0)ONm)op&g%Nx0(zkd$j@60@YB!B6abslr34PN>$lFnEpP zYvd`JKwagX1G8CGJx#@F(%YeG5YfRnKadsi2TW@hN0$%d_p$Y8kx<1@)sV9Uf32YW zL~BT<id98;_svyNibBhpaRW@hCZ~6A`;_whNv)9l?R`a<E)HTxKE{z3ZE!y(Ld%7X z_c7iK$YN&g;NudFJr$PbxPi2_ztpiT&Gifeoe7KRb0#WR`PXrq!(~DT_wG6#J)$)U zKBMTZ0zGgJ6%mj~Rc+*dtk}c<Sdh=@6@`zST}n=tR_#IVwJF1gT=yDYzf%WGuYE(u POwk6ZDzEbk(mQ_vKH60e diff --git a/ttkHyperlinkLabel.py b/ttkHyperlinkLabel.py index 0cc19b4e..0ca87fc7 100644 --- a/ttkHyperlinkLabel.py +++ b/ttkHyperlinkLabel.py @@ -146,44 +146,3 @@ class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label): # typ """Copy the current text to the clipboard.""" self.clipboard_clear() self.clipboard_append(self['text']) - - -def openurl(url: str) -> None: - r""" - Open the given URL in appropriate browser. - - 2022-12-06: - Firefox itself will gladly attempt to use very long URLs in its URL - input. Up to 16384 was attempted, but the Apache instance this was - tested against only allowed up to 8207 total URL length to pass, that - being 8190 octets of REQUEST_URI (path + GET params). - - Testing from Windows 10 Home 21H2 cmd.exe with: - - "<path to>\firefox.exe" -osint -url "<test url>" - - only allowed 8115 octest of REQUEST_URI to pass through. - - Microsoft Edge yielded 8092 octets. Google Chrome yielded 8093 octets. - - However, this is actually the limit of how long a CMD.EXE command-line - can be. The URL was being cut off *there*. - - The 8207 octet URL makes it through `webbrowser.open(<url>)` to: - - Firefox 107.0.1 - Microsoft Edge 108.0.1462.42 - Google Chrome 108.0.5359.95 - - This was also tested as working *with* the old winreg/subprocess code, - so it wasn't even suffering from the same limit as CMD.EXE. - - Conclusion: No reason to not just use `webbrowser.open()`, as prior - to e280d6c2833c25867b8139490e68ddf056477917 there was a bug, introduced - in 5989acd0d3263e54429ff99769ff73a20476d863, which meant the code always - ended up using `webbrowser.open()` *anyway*. - :param url: URL to open. - """ - warnings.warn("This function is deprecated. " - "Please use `webbrowser.open() instead.", DeprecationWarning, stacklevel=2) - webbrowser.open(url) From 57b6ecd88ea9bd989518ddc676db13753ba74973 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 19:16:45 -0400 Subject: [PATCH 07/49] [2186] Remove Config and Hotkey --- config/__init__.py | 3 - config/darwin.py | 191 ------------------------------- hotkey/__init__.py | 4 - hotkey/darwin.py | 276 --------------------------------------------- 4 files changed, 474 deletions(-) delete mode 100644 config/darwin.py delete mode 100644 hotkey/darwin.py diff --git a/config/__init__.py b/config/__init__.py index 3acb2edd..992710a0 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -468,9 +468,6 @@ def get_config(*args, **kwargs) -> AbstractConfig: :param kwargs: Args to be passed through to implementation. :return: Instance of the implementation. """ - if sys.platform == "darwin": # pragma: sys-platform-darwin - from .darwin import MacConfig - return MacConfig(*args, **kwargs) if sys.platform == "win32": # pragma: sys-platform-win32 from .windows import WinConfig diff --git a/config/darwin.py b/config/darwin.py deleted file mode 100644 index 9c15ec32..00000000 --- a/config/darwin.py +++ /dev/null @@ -1,191 +0,0 @@ -""" -darwin.py - Darwin/macOS implementation of AbstractConfig. - -Copyright (c) EDCD, All Rights Reserved -Licensed under the GNU General Public License. -See LICENSE file. -""" -from __future__ import annotations - -import pathlib -import sys -from typing import Any -from Foundation import ( # type: ignore - NSApplicationSupportDirectory, NSBundle, NSDocumentDirectory, NSSearchPathForDirectoriesInDomains, NSUserDefaults, - NSUserDomainMask -) -from config import AbstractConfig, appname, logger - -assert sys.platform == 'darwin' - - -class MacConfig(AbstractConfig): - """MacConfig is the implementation of AbstractConfig for Darwin based OSes.""" - - def __init__(self) -> None: - super().__init__() - support_path = pathlib.Path( - NSSearchPathForDirectoriesInDomains( - NSApplicationSupportDirectory, NSUserDomainMask, True - )[0] - ) - - self.app_dir_path = support_path / appname - self.app_dir_path.mkdir(exist_ok=True) - - self.plugin_dir_path = self.app_dir_path / 'plugins' - self.plugin_dir_path.mkdir(exist_ok=True) - - # Bundle IDs identify a singled app though out a system - - if getattr(sys, 'frozen', False): - exe_dir = pathlib.Path(sys.executable).parent - self.internal_plugin_dir_path = exe_dir.parent / 'Library' / 'plugins' - self.respath_path = exe_dir.parent / 'Resources' - self.identifier = NSBundle.mainBundle().bundleIdentifier() - - else: - file_dir = pathlib.Path(__file__).parent.parent - self.internal_plugin_dir_path = file_dir / 'plugins' - self.respath_path = file_dir - - self.identifier = f'uk.org.marginal.{appname.lower()}' - NSBundle.mainBundle().infoDictionary()['CFBundleIdentifier'] = self.identifier - - self.default_journal_dir_path = support_path / 'Frontier Developments' / 'Elite Dangerous' - self._defaults: Any = NSUserDefaults.standardUserDefaults() - self._settings: dict[str, int | str | list] = dict( - self._defaults.persistentDomainForName_(self.identifier) or {} - ) # make writeable - - if (out_dir := self.get_str('out_dir')) is None or not pathlib.Path(out_dir).exists(): - self.set('outdir', NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, True)[0]) - - def __raw_get(self, key: str) -> None | list | str | int: - """ - Retrieve the raw data for the given key. - - :param str: str - The key data is being requested for. - :return: The requested data. - """ - res = self._settings.get(key) - # On MacOS Catalina, with python.org python 3.9.2 any 'list' - # has type __NSCFArray so a simple `isinstance(res, list)` is - # False. So, check it's not-None, and not the other types. - # - # If we can find where to import the definition of NSCFArray - # then we could possibly test against that. - if res is not None and not isinstance(res, str) and not isinstance(res, int): - return list(res) - - return res - - def get_str(self, key: str, *, default: str = None) -> str: - """ - Return the string referred to by the given key if it exists, or the default. - - Implements :meth:`AbstractConfig.get_str`. - """ - res = self.__raw_get(key) - if res is None: - return default # Yes it could be None, but we're _assuming_ that people gave us a default - - if not isinstance(res, str): - raise ValueError(f'unexpected data returned from __raw_get: {type(res)=} {res}') - - return res - - def get_list(self, key: str, *, default: list = None) -> list: - """ - Return the list referred to by the given key if it exists, or the default. - - Implements :meth:`AbstractConfig.get_list`. - """ - res = self.__raw_get(key) - if res is None: - return default # Yes it could be None, but we're _assuming_ that people gave us a default - - if not isinstance(res, list): - raise ValueError(f'__raw_get returned unexpected type {type(res)=} {res!r}') - - return res - - def get_int(self, key: str, *, default: int = 0) -> int: - """ - Return the int referred to by key if it exists in the config. - - Implements :meth:`AbstractConfig.get_int`. - """ - res = self.__raw_get(key) - if res is None: - return default - - if not isinstance(res, (str, int)): - raise ValueError(f'__raw_get returned unexpected type {type(res)=} {res!r}') - - try: - return int(res) - - except ValueError as e: - logger.error(f'__raw_get returned {res!r} which cannot be parsed to an int: {e}') - return default # Yes it could be None, but we're _assuming_ that people gave us a default - - def get_bool(self, key: str, *, default: bool = None) -> bool: - """ - Return the bool referred to by the given key if it exists, or the default. - - Implements :meth:`AbstractConfig.get_bool`. - """ - res = self.__raw_get(key) - if res is None: - return default # Yes it could be None, but we're _assuming_ that people gave us a default - - if not isinstance(res, bool): - raise ValueError(f'__raw_get returned unexpected type {type(res)=} {res!r}') - - return res - - def set(self, key: str, val: int | str | list[str] | bool) -> None: - """ - Set the given key's data to the given value. - - Implements :meth:`AbstractConfig.set`. - """ - if self._settings is None: - raise ValueError('attempt to use a closed _settings') - - if not isinstance(val, (bool, str, int, list)): - raise ValueError(f'Unexpected type for value {type(val)=}') - - self._settings[key] = val - - def delete(self, key: str, *, suppress=False) -> None: - """ - Delete the given key from the config. - - Implements :meth:`AbstractConfig.delete`. - """ - try: - del self._settings[key] - - except Exception: - if suppress: - pass - - def save(self) -> None: - """ - Save the current configuration. - - Implements :meth:`AbstractConfig.save`. - """ - self._defaults.setPersistentDomain_forName_(self._settings, self.identifier) - self._defaults.synchronize() - - def close(self) -> None: - """ - Close this config and release any associated resources. - - Implements :meth:`AbstractConfig.close`. - """ - self.save() - self._defaults = None diff --git a/hotkey/__init__.py b/hotkey/__init__.py index e7515807..313415f9 100644 --- a/hotkey/__init__.py +++ b/hotkey/__init__.py @@ -76,10 +76,6 @@ def get_hotkeymgr() -> AbstractHotkeyMgr: :return: Appropriate class instance. :raises ValueError: If unsupported platform. """ - if sys.platform == 'darwin': - from hotkey.darwin import MacHotkeyMgr - return MacHotkeyMgr() - if sys.platform == 'win32': from hotkey.windows import WindowsHotkeyMgr return WindowsHotkeyMgr() diff --git a/hotkey/darwin.py b/hotkey/darwin.py deleted file mode 100644 index 6afd0239..00000000 --- a/hotkey/darwin.py +++ /dev/null @@ -1,276 +0,0 @@ -"""darwin/macOS implementation of hotkey.AbstractHotkeyMgr.""" -from __future__ import annotations - -import pathlib -import sys -import tkinter as tk -from typing import Callable -assert sys.platform == 'darwin' - -import objc -from AppKit import ( - NSAlternateKeyMask, NSApplication, NSBeep, NSClearLineFunctionKey, NSCommandKeyMask, NSControlKeyMask, - NSDeleteFunctionKey, NSDeviceIndependentModifierFlagsMask, NSEvent, NSF1FunctionKey, NSF35FunctionKey, - NSFlagsChanged, NSKeyDown, NSKeyDownMask, NSKeyUp, NSNumericPadKeyMask, NSShiftKeyMask, NSSound, NSWorkspace -) - -from config import config -from EDMCLogging import get_main_logger -from hotkey import AbstractHotkeyMgr - -logger = get_main_logger() - - -class MacHotkeyMgr(AbstractHotkeyMgr): - """Hot key management.""" - - POLL = 250 - # https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSEvent_Class/#//apple_ref/doc/constant_group/Function_Key_Unicodes - DISPLAY = { - 0x03: u'⌅', 0x09: u'⇥', 0xd: u'↩', 0x19: u'⇤', 0x1b: u'esc', 0x20: u'⏘', 0x7f: u'⌫', - 0xf700: u'↑', 0xf701: u'↓', 0xf702: u'←', 0xf703: u'→', - 0xf727: u'Ins', - 0xf728: u'⌦', 0xf729: u'↖', 0xf72a: u'Fn', 0xf72b: u'↘', - 0xf72c: u'⇞', 0xf72d: u'⇟', 0xf72e: u'PrtScr', 0xf72f: u'ScrollLock', - 0xf730: u'Pause', 0xf731: u'SysReq', 0xf732: u'Break', 0xf733: u'Reset', - 0xf739: u'⌧', - } - (ACQUIRE_INACTIVE, ACQUIRE_ACTIVE, ACQUIRE_NEW) = range(3) - - def __init__(self): - self.MODIFIERMASK = NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask \ - | NSNumericPadKeyMask - self.root: tk.Tk - - self.keycode = 0 - self.modifiers = 0 - self.activated = False - self.observer = None - - self.acquire_key = 0 - self.acquire_state = MacHotkeyMgr.ACQUIRE_INACTIVE - - self.tkProcessKeyEvent_old: Callable - - self.snd_good = NSSound.alloc().initWithContentsOfFile_byReference_( - pathlib.Path(config.respath_path) / 'snd_good.wav', False - ) - self.snd_bad = NSSound.alloc().initWithContentsOfFile_byReference_( - pathlib.Path(config.respath_path) / 'snd_bad.wav', False - ) - - def register(self, root: tk.Tk, keycode: int, modifiers: int) -> None: - """ - Register current hotkey for monitoring. - - :param root: parent window. - :param keycode: Key to monitor. - :param modifiers: Any modifiers to take into account. - """ - self.root = root - self.keycode = keycode - self.modifiers = modifiers - self.activated = False - - if keycode: - if not self.observer: - self.root.after_idle(self._observe) - self.root.after(MacHotkeyMgr.POLL, self._poll) - - # Monkey-patch tk (tkMacOSXKeyEvent.c) - if not callable(self.tkProcessKeyEvent_old): - sel = b'tkProcessKeyEvent:' - cls = NSApplication.sharedApplication().class__() # type: ignore - self.tkProcessKeyEvent_old = NSApplication.sharedApplication().methodForSelector_(sel) # type: ignore - newmethod = objc.selector( # type: ignore - self.tkProcessKeyEvent, - selector=self.tkProcessKeyEvent_old.selector, - signature=self.tkProcessKeyEvent_old.signature - ) - objc.classAddMethod(cls, sel, newmethod) # type: ignore - - def tkProcessKeyEvent(self, cls, the_event): # noqa: N802 - """ - Monkey-patch tk (tkMacOSXKeyEvent.c). - - - workaround crash on OSX 10.9 & 10.10 on seeing a composing character - - notice when modifier key state changes - - keep a copy of NSEvent.charactersIgnoringModifiers, which is what we need for the hotkey - - (Would like to use a decorator but need to ensure the application is created before this is installed) - :param cls: ??? - :param the_event: tk event - :return: ??? - """ - if self.acquire_state: - if the_event.type() == NSFlagsChanged: - self.acquire_key = the_event.modifierFlags() & NSDeviceIndependentModifierFlagsMask - self.acquire_state = MacHotkeyMgr.ACQUIRE_NEW - # suppress the event by not chaining the old function - return the_event - - if the_event.type() in (NSKeyDown, NSKeyUp): - c = the_event.charactersIgnoringModifiers() - self.acquire_key = (c and ord(c[0]) or 0) | \ - (the_event.modifierFlags() & NSDeviceIndependentModifierFlagsMask) - self.acquire_state = MacHotkeyMgr.ACQUIRE_NEW - # suppress the event by not chaining the old function - return the_event - - # replace empty characters with charactersIgnoringModifiers to avoid crash - elif the_event.type() in (NSKeyDown, NSKeyUp) and not the_event.characters(): - the_event = NSEvent.keyEventWithType_location_modifierFlags_timestamp_windowNumber_context_characters_charactersIgnoringModifiers_isARepeat_keyCode_( # noqa: E501 - # noqa: E501 - the_event.type(), - the_event.locationInWindow(), - the_event.modifierFlags(), - the_event.timestamp(), - the_event.windowNumber(), - the_event.context(), - the_event.charactersIgnoringModifiers(), - the_event.charactersIgnoringModifiers(), - the_event.isARepeat(), - the_event.keyCode() - ) - return self.tkProcessKeyEvent_old(cls, the_event) - - def _observe(self): - # Must be called after root.mainloop() so that the app's message loop has been created - self.observer = NSEvent.addGlobalMonitorForEventsMatchingMask_handler_(NSKeyDownMask, self._handler) - - def _poll(self): - if config.shutting_down: - return - - # No way of signalling to Tkinter from within the callback handler block that doesn't - # cause Python to crash, so poll. - if self.activated: - self.activated = False - self.root.event_generate('<<Invoke>>', when="tail") - - if self.keycode or self.modifiers: - self.root.after(MacHotkeyMgr.POLL, self._poll) - - def unregister(self) -> None: - """Remove hotkey registration.""" - self.keycode = 0 - self.modifiers = 0 - - @objc.callbackFor(NSEvent.addGlobalMonitorForEventsMatchingMask_handler_) - def _handler(self, event) -> None: - # use event.charactersIgnoringModifiers to handle composing characters like Alt-e - if ( - (event.modifierFlags() & self.MODIFIERMASK) == self.modifiers - and ord(event.charactersIgnoringModifiers()[0]) == self.keycode - ): - if config.get_int('hotkey_always'): - self.activated = True - - else: # Only trigger if game client is front process - front = NSWorkspace.sharedWorkspace().frontmostApplication() - if front and front.bundleIdentifier() == 'uk.co.frontier.EliteDangerous': - self.activated = True - - def acquire_start(self) -> None: - """Start acquiring hotkey state via polling.""" - self.acquire_state = MacHotkeyMgr.ACQUIRE_ACTIVE - self.root.after_idle(self._acquire_poll) - - def acquire_stop(self) -> None: - """Stop acquiring hotkey state.""" - self.acquire_state = MacHotkeyMgr.ACQUIRE_INACTIVE - - def _acquire_poll(self) -> None: - """Perform a poll of current hotkey state.""" - if config.shutting_down: - return - - # No way of signalling to Tkinter from within the monkey-patched event handler that doesn't - # cause Python to crash, so poll. - if self.acquire_state: - if self.acquire_state == MacHotkeyMgr.ACQUIRE_NEW: - # Abuse tkEvent's keycode field to hold our acquired key & modifier - self.root.event_generate('<KeyPress>', keycode=self.acquire_key) - self.acquire_state = MacHotkeyMgr.ACQUIRE_ACTIVE - self.root.after(50, self._acquire_poll) - - def fromevent(self, event) -> bool | tuple | None: - """ - Return configuration (keycode, modifiers) or None=clear or False=retain previous. - - :param event: tk event ? - :return: False to retain previous, None to not use, else (keycode, modifiers) - """ - (keycode, modifiers) = (event.keycode & 0xffff, event.keycode & 0xffff0000) # Set by _acquire_poll() - if ( - keycode - and not (modifiers & (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask)) - ): - if keycode == 0x1b: # Esc = retain previous - self.acquire_state = MacHotkeyMgr.ACQUIRE_INACTIVE - return False - - # BkSp, Del, Clear = clear hotkey - if keycode in (0x7f, ord(NSDeleteFunctionKey), ord(NSClearLineFunctionKey)): - self.acquire_state = MacHotkeyMgr.ACQUIRE_INACTIVE - return None - - # don't allow keys needed for typing in System Map - if keycode in (0x13, 0x20, 0x2d) or 0x61 <= keycode <= 0x7a: - NSBeep() - self.acquire_state = MacHotkeyMgr.ACQUIRE_INACTIVE - return None - - return keycode, modifiers - - def display(self, keycode, modifiers) -> str: - """ - Return displayable form of given hotkey + modifiers. - - :param keycode: - :param modifiers: - :return: string form - """ - text = '' - if modifiers & NSControlKeyMask: - text += u'⌃' - - if modifiers & NSAlternateKeyMask: - text += u'⌥' - - if modifiers & NSShiftKeyMask: - text += u'⇧' - - if modifiers & NSCommandKeyMask: - text += u'⌘' - - if (modifiers & NSNumericPadKeyMask) and keycode <= 0x7f: - text += u'№' - - if not keycode: - pass - - elif ord(NSF1FunctionKey) <= keycode <= ord(NSF35FunctionKey): - text += f'F{keycode + 1 - ord(NSF1FunctionKey)}' - - elif keycode in MacHotkeyMgr.DISPLAY: # specials - text += MacHotkeyMgr.DISPLAY[keycode] - - elif keycode < 0x20: # control keys - text += chr(keycode + 0x40) - - elif keycode < 0xf700: # key char - text += chr(keycode).upper() - - else: - text += u'⁈' - - return text - - def play_good(self): - """Play the 'good' sound.""" - self.snd_good.play() - - def play_bad(self): - """Play the 'bad' sound.""" - self.snd_bad.play() From 93d26e07e057d1b70f3144898ecf34e35c4cdae2 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 19:19:15 -0400 Subject: [PATCH 08/49] [2186] Remove Monitor, L10n References --- l10n.py | 50 +++++--------------------------------------------- monitor.py | 23 ++--------------------- 2 files changed, 7 insertions(+), 66 deletions(-) diff --git a/l10n.py b/l10n.py index a2b5185a..183d902a 100755 --- a/l10n.py +++ b/l10n.py @@ -17,8 +17,8 @@ import re import sys import warnings from contextlib import suppress -from os import pardir, listdir, sep, makedirs -from os.path import basename, dirname, isdir, isfile, join, abspath, exists +from os import listdir, sep, makedirs +from os.path import basename, dirname, isdir, join, abspath, exists from typing import TYPE_CHECKING, Iterable, TextIO, cast from config import config from EDMCLogging import get_main_logger @@ -39,12 +39,7 @@ logger = get_main_logger() LANGUAGE_ID = '!Language' LOCALISATION_DIR = 'L10n' -if sys.platform == 'darwin': - from Foundation import ( # type: ignore # exists on Darwin - NSLocale, NSNumberFormatter, NSNumberFormatterDecimalStyle - ) - -elif sys.platform == 'win32': +if sys.platform == 'win32': import ctypes from ctypes.wintypes import BOOL, DWORD, LPCVOID, LPCWSTR, LPWSTR if TYPE_CHECKING: @@ -178,14 +173,8 @@ class _Translations: def available(self) -> set[str]: """Return a list of available language codes.""" path = self.respath() - if getattr(sys, 'frozen', False) and sys.platform == 'darwin': - available = { - x[:-len('.lproj')] for x in listdir(path) - if x.endswith('.lproj') and isfile(join(x, 'Localizable.strings')) - } - else: - available = {x[:-len('.strings')] for x in listdir(path) if x.endswith('.strings')} + available = {x[:-len('.strings')] for x in listdir(path) if x.endswith('.strings')} return available @@ -206,9 +195,6 @@ class _Translations: def respath(self) -> str: """Path to localisation files.""" if getattr(sys, 'frozen', False): - if sys.platform == 'darwin': - return abspath(join(dirname(sys.executable), pardir, 'Resources')) - return abspath(join(dirname(sys.executable), LOCALISATION_DIR)) if __file__: @@ -234,10 +220,6 @@ class _Translations: except OSError: logger.exception(f'could not open {file_path}') - elif getattr(sys, 'frozen', False) and sys.platform == 'darwin': - res_path = join(self.respath(), f'{lang}.lproj', 'Localizable.strings') - return open(res_path, encoding='utf-16') - res_path = join(self.respath(), f'{lang}.strings') return open(res_path, encoding='utf-8') @@ -245,15 +227,6 @@ class _Translations: class _Locale: """Locale holds a few utility methods to convert data to and from localized versions.""" - def __init__(self) -> None: - if sys.platform == 'darwin': - self.int_formatter = NSNumberFormatter.alloc().init() - self.int_formatter.setNumberStyle_(NSNumberFormatterDecimalStyle) - self.float_formatter = NSNumberFormatter.alloc().init() - self.float_formatter.setNumberStyle_(NSNumberFormatterDecimalStyle) - self.float_formatter.setMinimumFractionDigits_(5) - self.float_formatter.setMaximumFractionDigits_(5) - def stringFromNumber(self, number: float | int, decimals: int | None = None) -> str: # noqa: N802 warnings.warn(DeprecationWarning('use _Locale.string_from_number instead.')) return self.string_from_number(number, decimals) # type: ignore @@ -279,14 +252,6 @@ class _Locale: if decimals == 0 and not isinstance(number, numbers.Integral): number = int(round(number)) - if sys.platform == 'darwin': - if not decimals and isinstance(number, numbers.Integral): - return self.int_formatter.stringFromNumber_(number) - - self.float_formatter.setMinimumFractionDigits_(decimals) - self.float_formatter.setMaximumFractionDigits_(decimals) - return self.float_formatter.stringFromNumber_(number) - if not decimals and isinstance(number, numbers.Integral): return locale.format_string('%d', number, True) return locale.format_string('%.*f', (decimals, number), True) @@ -299,9 +264,6 @@ class _Locale: :param string: The string to convert :return: None if the string cannot be parsed, otherwise an int or float dependant on input data. """ - if sys.platform == 'darwin': - return self.float_formatter.numberFromString_(string) - with suppress(ValueError): return locale.atoi(string) @@ -332,10 +294,8 @@ class _Locale: :return: The preferred language list """ languages: Iterable[str] - if sys.platform == 'darwin': - languages = NSLocale.preferredLanguages() - elif sys.platform != 'win32': + if sys.platform != 'win32': # POSIX lang = locale.getlocale()[0] languages = [lang.replace('_', '-')] if lang else [] diff --git a/monitor.py b/monitor.py index 8364f95b..d549e533 100644 --- a/monitor.py +++ b/monitor.py @@ -38,16 +38,7 @@ if TYPE_CHECKING: def _(x: str) -> str: return x -if sys.platform == 'darwin': - from fcntl import fcntl - - from AppKit import NSWorkspace - from watchdog.events import FileSystemEventHandler - from watchdog.observers import Observer - from watchdog.observers.api import BaseObserver - F_GLOBAL_NOCACHE = 55 - -elif sys.platform == 'win32': +if sys.platform == 'win32': import ctypes from ctypes.wintypes import BOOL, HWND, LPARAM, LPWSTR @@ -382,8 +373,6 @@ class EDLogs(FileSystemEventHandler): logfile = self.logfile if logfile: loghandle: BinaryIO = open(logfile, 'rb', 0) # unbuffered - if sys.platform == 'darwin': - fcntl(loghandle, F_GLOBAL_NOCACHE, -1) # required to avoid corruption on macOS over SMB self.catching_up = True for line in loghandle: @@ -483,9 +472,6 @@ class EDLogs(FileSystemEventHandler): if logfile: loghandle = open(logfile, 'rb', 0) # unbuffered - if sys.platform == 'darwin': - fcntl(loghandle, F_GLOBAL_NOCACHE, -1) # required to avoid corruption on macOS over SMB - log_pos = 0 sleep(self._POLL) @@ -2144,12 +2130,7 @@ class EDLogs(FileSystemEventHandler): :return: bool - True if the game is running. """ - if sys.platform == 'darwin': - for app in NSWorkspace.sharedWorkspace().runningApplications(): - if app.bundleIdentifier() == 'uk.co.frontier.EliteDangerous': - return True - - elif sys.platform == 'win32': + if sys.platform == 'win32': def WindowTitle(h): # noqa: N802 if h: length = GetWindowTextLength(h) + 1 From 27093d88620ed760600b0e1df672160e25dffc7c Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 19:26:25 -0400 Subject: [PATCH 09/49] [2186] Main, Dashboard, Prefs --- EDMarketConnector.py | 342 ++++++++++++++++--------------------------- dashboard.py | 2 +- myNotebook.py | 2 +- prefs.py | 177 ++++------------------ 4 files changed, 161 insertions(+), 362 deletions(-) diff --git a/EDMarketConnector.py b/EDMarketConnector.py index 6debf4e9..967488e0 100755 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -496,21 +496,20 @@ class AppWindow: plug.load_plugins(master) - if sys.platform != 'darwin': - if sys.platform == 'win32': - self.w.wm_iconbitmap(default='EDMarketConnector.ico') + if sys.platform == 'win32': + self.w.wm_iconbitmap(default='EDMarketConnector.ico') - else: - self.w.tk.call('wm', 'iconphoto', self.w, '-default', - tk.PhotoImage(file=path.join(config.respath_path, 'io.edcd.EDMarketConnector.png'))) + else: + self.w.tk.call('wm', 'iconphoto', self.w, '-default', + tk.PhotoImage(file=path.join(config.respath_path, 'io.edcd.EDMarketConnector.png'))) - # TODO: Export to files and merge from them in future ? - self.theme_icon = tk.PhotoImage( - data='R0lGODlhFAAQAMZQAAoKCQoKCgsKCQwKCQsLCgwLCg4LCQ4LCg0MCg8MCRAMCRANChINCREOChIOChQPChgQChgRCxwTCyYVCSoXCS0YCTkdCTseCT0fCTsjDU0jB0EnDU8lB1ElB1MnCFIoCFMoCEkrDlkqCFwrCGEuCWIuCGQvCFs0D1w1D2wyCG0yCF82D182EHE0CHM0CHQ1CGQ5EHU2CHc3CHs4CH45CIA6CIE7CJdECIdLEolMEohQE5BQE41SFJBTE5lUE5pVE5RXFKNaFKVbFLVjFbZkFrxnFr9oFsNqFsVrF8RsFshtF89xF9NzGNh1GNl2GP+KG////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yH5BAEKAH8ALAAAAAAUABAAAAeegAGCgiGDhoeIRDiIjIZGKzmNiAQBQxkRTU6am0tPCJSGShuSAUcLoIIbRYMFra4FAUgQAQCGJz6CDQ67vAFJJBi0hjBBD0w9PMnJOkAiJhaIKEI7HRoc19ceNAolwbWDLD8uAQnl5ga1I9CHEjEBAvDxAoMtFIYCBy+kFDKHAgM3ZtgYSLAGgwkp3pEyBOJCC2ELB31QATGioAoVAwEAOw==') # noqa: E501 - self.theme_minimize = tk.BitmapImage( - data='#define im_width 16\n#define im_height 16\nstatic unsigned char im_bits[] = {\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f,\n 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };\n') # noqa: E501 - self.theme_close = tk.BitmapImage( - data='#define im_width 16\n#define im_height 16\nstatic unsigned char im_bits[] = {\n 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x1c, 0x38, 0x38, 0x1c, 0x70, 0x0e,\n 0xe0, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x07, 0x70, 0x0e, 0x38, 0x1c,\n 0x1c, 0x38, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00 };\n') # noqa: E501 + # TODO: Export to files and merge from them in future ? + self.theme_icon = tk.PhotoImage( + data='R0lGODlhFAAQAMZQAAoKCQoKCgsKCQwKCQsLCgwLCg4LCQ4LCg0MCg8MCRAMCRANChINCREOChIOChQPChgQChgRCxwTCyYVCSoXCS0YCTkdCTseCT0fCTsjDU0jB0EnDU8lB1ElB1MnCFIoCFMoCEkrDlkqCFwrCGEuCWIuCGQvCFs0D1w1D2wyCG0yCF82D182EHE0CHM0CHQ1CGQ5EHU2CHc3CHs4CH45CIA6CIE7CJdECIdLEolMEohQE5BQE41SFJBTE5lUE5pVE5RXFKNaFKVbFLVjFbZkFrxnFr9oFsNqFsVrF8RsFshtF89xF9NzGNh1GNl2GP+KG////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////yH5BAEKAH8ALAAAAAAUABAAAAeegAGCgiGDhoeIRDiIjIZGKzmNiAQBQxkRTU6am0tPCJSGShuSAUcLoIIbRYMFra4FAUgQAQCGJz6CDQ67vAFJJBi0hjBBD0w9PMnJOkAiJhaIKEI7HRoc19ceNAolwbWDLD8uAQnl5ga1I9CHEjEBAvDxAoMtFIYCBy+kFDKHAgM3ZtgYSLAGgwkp3pEyBOJCC2ELB31QATGioAoVAwEAOw==') # noqa: E501 + self.theme_minimize = tk.BitmapImage( + data='#define im_width 16\n#define im_height 16\nstatic unsigned char im_bits[] = {\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f,\n 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };\n') # noqa: E501 + self.theme_close = tk.BitmapImage( + data='#define im_width 16\n#define im_height 16\nstatic unsigned char im_bits[] = {\n 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x1c, 0x38, 0x38, 0x1c, 0x70, 0x0e,\n 0xe0, 0x07, 0xc0, 0x03, 0xc0, 0x03, 0xe0, 0x07, 0x70, 0x0e, 0x38, 0x1c,\n 0x1c, 0x38, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00 };\n') # noqa: E501 frame = tk.Frame(self.w, name=appname.lower()) frame.grid(sticky=tk.NSEW) @@ -599,7 +598,7 @@ class AppWindow: self.theme_button = tk.Label( frame, name='themed_update_button', - width=32 if sys.platform == 'darwin' else 28, + width=28, state=tk.DISABLED ) @@ -633,148 +632,104 @@ class AppWindow: self.updater = update.Updater(tkroot=self.w) self.updater.check_for_updates() # Sparkle / WinSparkle does this automatically for packaged apps - if sys.platform == 'darwin': - # Can't handle (de)iconify if topmost is set, so suppress iconify button - # http://wiki.tcl.tk/13428 and p15 of - # https://developer.apple.com/legacy/library/documentation/Carbon/Conceptual/HandlingWindowsControls/windowscontrols.pdf - root.call('tk::unsupported::MacWindowStyle', 'style', root, 'document', 'closeBox resizable') + self.file_menu = self.view_menu = tk.Menu(self.menubar, tearoff=tk.FALSE) + self.file_menu.add_command(command=lambda: stats.StatsDialog(self.w, self.status)) + self.file_menu.add_command(command=self.save_raw) + self.file_menu.add_command(command=lambda: prefs.PreferencesDialog(self.w, self.postprefs)) + self.file_menu.add_separator() + self.file_menu.add_command(command=self.onexit) + self.menubar.add_cascade(menu=self.file_menu) + self.edit_menu = tk.Menu(self.menubar, tearoff=tk.FALSE) + self.edit_menu.add_command(accelerator='Ctrl+C', state=tk.DISABLED, command=self.copy) + self.menubar.add_cascade(menu=self.edit_menu) + self.help_menu = tk.Menu(self.menubar, tearoff=tk.FALSE) # type: ignore + self.help_menu.add_command(command=self.help_general) # Documentation + self.help_menu.add_command(command=self.help_troubleshooting) # Troubleshooting + self.help_menu.add_command(command=self.help_report_a_bug) # Report A Bug + self.help_menu.add_command(command=self.help_privacy) # Privacy Policy + self.help_menu.add_command(command=self.help_releases) # Release Notes + self.help_menu.add_command(command=lambda: self.updater.check_for_updates()) # Check for Updates... + # About E:D Market Connector + self.help_menu.add_command(command=lambda: not self.HelpAbout.showing and self.HelpAbout(self.w)) + self.help_menu.add_command(command=prefs.help_open_log_folder) # Open Log Folder - # https://www.tcl.tk/man/tcl/TkCmd/menu.htm - self.system_menu = tk.Menu(self.menubar, name='apple') - self.system_menu.add_command(command=lambda: self.w.call('tk::mac::standardAboutPanel')) - self.system_menu.add_command(command=lambda: self.updater.check_for_updates()) + self.menubar.add_cascade(menu=self.help_menu) + if sys.platform == 'win32': + # Must be added after at least one "real" menu entry + self.always_ontop = tk.BooleanVar(value=bool(config.get_int('always_ontop'))) + self.system_menu = tk.Menu(self.menubar, name='system', tearoff=tk.FALSE) + self.system_menu.add_separator() + # LANG: Appearance - Label for checkbox to select if application always on top + self.system_menu.add_checkbutton(label=_('Always on top'), + variable=self.always_ontop, + command=self.ontop_changed) # Appearance setting self.menubar.add_cascade(menu=self.system_menu) - self.file_menu = tk.Menu(self.menubar, name='file') - self.file_menu.add_command(command=self.save_raw) - self.menubar.add_cascade(menu=self.file_menu) - self.edit_menu = tk.Menu(self.menubar, name='edit') - self.edit_menu.add_command(accelerator='Command-c', state=tk.DISABLED, command=self.copy) - self.menubar.add_cascade(menu=self.edit_menu) - self.w.bind('<Command-c>', self.copy) - self.view_menu = tk.Menu(self.menubar, name='view') - self.view_menu.add_command(command=lambda: stats.StatsDialog(self.w, self.status)) - self.menubar.add_cascade(menu=self.view_menu) - window_menu = tk.Menu(self.menubar, name='window') - self.menubar.add_cascade(menu=window_menu) - self.help_menu = tk.Menu(self.menubar, name='help') - self.w.createcommand("::tk::mac::ShowHelp", self.help_general) - self.help_menu.add_command(command=self.help_troubleshooting) - self.help_menu.add_command(command=self.help_report_a_bug) - self.help_menu.add_command(command=self.help_privacy) - self.help_menu.add_command(command=self.help_releases) - self.menubar.add_cascade(menu=self.help_menu) - self.w['menu'] = self.menubar - # https://www.tcl.tk/man/tcl/TkCmd/tk_mac.htm - self.w.call('set', 'tk::mac::useCompatibilityMetrics', '0') - self.w.createcommand('tkAboutDialog', lambda: self.w.call('tk::mac::standardAboutPanel')) - self.w.createcommand("::tk::mac::Quit", self.onexit) - self.w.createcommand("::tk::mac::ShowPreferences", lambda: prefs.PreferencesDialog(self.w, self.postprefs)) - self.w.createcommand("::tk::mac::ReopenApplication", self.w.deiconify) # click on app in dock = restore - self.w.protocol("WM_DELETE_WINDOW", self.w.withdraw) # close button shouldn't quit app - self.w.resizable(tk.FALSE, tk.FALSE) # Can't be only resizable on one axis - else: - self.file_menu = self.view_menu = tk.Menu(self.menubar, tearoff=tk.FALSE) - self.file_menu.add_command(command=lambda: stats.StatsDialog(self.w, self.status)) - self.file_menu.add_command(command=self.save_raw) - self.file_menu.add_command(command=lambda: prefs.PreferencesDialog(self.w, self.postprefs)) - self.file_menu.add_separator() - self.file_menu.add_command(command=self.onexit) - self.menubar.add_cascade(menu=self.file_menu) - self.edit_menu = tk.Menu(self.menubar, tearoff=tk.FALSE) - self.edit_menu.add_command(accelerator='Ctrl+C', state=tk.DISABLED, command=self.copy) - self.menubar.add_cascade(menu=self.edit_menu) - self.help_menu = tk.Menu(self.menubar, tearoff=tk.FALSE) # type: ignore - self.help_menu.add_command(command=self.help_general) # Documentation - self.help_menu.add_command(command=self.help_troubleshooting) # Troubleshooting - self.help_menu.add_command(command=self.help_report_a_bug) # Report A Bug - self.help_menu.add_command(command=self.help_privacy) # Privacy Policy - self.help_menu.add_command(command=self.help_releases) # Release Notes - self.help_menu.add_command(command=lambda: self.updater.check_for_updates()) # Check for Updates... - # About E:D Market Connector - self.help_menu.add_command(command=lambda: not self.HelpAbout.showing and self.HelpAbout(self.w)) - self.help_menu.add_command(command=prefs.help_open_log_folder) # Open Log Folder + self.w.bind('<Control-c>', self.copy) - self.menubar.add_cascade(menu=self.help_menu) - if sys.platform == 'win32': - # Must be added after at least one "real" menu entry - self.always_ontop = tk.BooleanVar(value=bool(config.get_int('always_ontop'))) - self.system_menu = tk.Menu(self.menubar, name='system', tearoff=tk.FALSE) - self.system_menu.add_separator() - # LANG: Appearance - Label for checkbox to select if application always on top - self.system_menu.add_checkbutton(label=_('Always on top'), - variable=self.always_ontop, - command=self.ontop_changed) # Appearance setting - self.menubar.add_cascade(menu=self.system_menu) - self.w.bind('<Control-c>', self.copy) + # Bind to the Default theme minimise button + self.w.bind("<Unmap>", self.default_iconify) - # Bind to the Default theme minimise button - self.w.bind("<Unmap>", self.default_iconify) + self.w.protocol("WM_DELETE_WINDOW", self.onexit) + theme.register(self.menubar) # menus and children aren't automatically registered + theme.register(self.file_menu) + theme.register(self.edit_menu) + theme.register(self.help_menu) - self.w.protocol("WM_DELETE_WINDOW", self.onexit) - theme.register(self.menubar) # menus and children aren't automatically registered - theme.register(self.file_menu) - theme.register(self.edit_menu) - theme.register(self.help_menu) - - # Alternate title bar and menu for dark theme - self.theme_menubar = tk.Frame(frame, name="alternate_menubar") - self.theme_menubar.columnconfigure(2, weight=1) - theme_titlebar = tk.Label( - self.theme_menubar, - name="alternate_titlebar", - text=applongname, - image=self.theme_icon, cursor='fleur', - anchor=tk.W, compound=tk.LEFT - ) - theme_titlebar.grid(columnspan=3, padx=2, sticky=tk.NSEW) - self.drag_offset: tuple[int | None, int | None] = (None, None) - theme_titlebar.bind('<Button-1>', self.drag_start) - theme_titlebar.bind('<B1-Motion>', self.drag_continue) - theme_titlebar.bind('<ButtonRelease-1>', self.drag_end) - theme_minimize = tk.Label(self.theme_menubar, image=self.theme_minimize) - theme_minimize.grid(row=0, column=3, padx=2) - theme.button_bind(theme_minimize, self.oniconify, image=self.theme_minimize) - theme_close = tk.Label(self.theme_menubar, image=self.theme_close) - theme_close.grid(row=0, column=4, padx=2) - theme.button_bind(theme_close, self.onexit, image=self.theme_close) - self.theme_file_menu = tk.Label(self.theme_menubar, anchor=tk.W) - self.theme_file_menu.grid(row=1, column=0, padx=self.PADX, sticky=tk.W) - theme.button_bind(self.theme_file_menu, - lambda e: self.file_menu.tk_popup(e.widget.winfo_rootx(), - e.widget.winfo_rooty() - + e.widget.winfo_height())) - self.theme_edit_menu = tk.Label(self.theme_menubar, anchor=tk.W) - self.theme_edit_menu.grid(row=1, column=1, sticky=tk.W) - theme.button_bind(self.theme_edit_menu, - lambda e: self.edit_menu.tk_popup(e.widget.winfo_rootx(), - e.widget.winfo_rooty() - + e.widget.winfo_height())) - self.theme_help_menu = tk.Label(self.theme_menubar, anchor=tk.W) - self.theme_help_menu.grid(row=1, column=2, sticky=tk.W) - theme.button_bind(self.theme_help_menu, - lambda e: self.help_menu.tk_popup(e.widget.winfo_rootx(), - e.widget.winfo_rooty() - + e.widget.winfo_height())) - tk.Frame(self.theme_menubar, highlightthickness=1).grid(columnspan=5, padx=self.PADX, sticky=tk.EW) - theme.register(self.theme_minimize) # images aren't automatically registered - theme.register(self.theme_close) - self.blank_menubar = tk.Frame(frame, name="blank_menubar") - tk.Label(self.blank_menubar).grid() - tk.Label(self.blank_menubar).grid() - tk.Frame(self.blank_menubar, height=2).grid() - theme.register_alternate((self.menubar, self.theme_menubar, self.blank_menubar), - {'row': 0, 'columnspan': 2, 'sticky': tk.NSEW}) - self.w.resizable(tk.TRUE, tk.FALSE) + # Alternate title bar and menu for dark theme + self.theme_menubar = tk.Frame(frame, name="alternate_menubar") + self.theme_menubar.columnconfigure(2, weight=1) + theme_titlebar = tk.Label( + self.theme_menubar, + name="alternate_titlebar", + text=applongname, + image=self.theme_icon, cursor='fleur', + anchor=tk.W, compound=tk.LEFT + ) + theme_titlebar.grid(columnspan=3, padx=2, sticky=tk.NSEW) + self.drag_offset: tuple[int | None, int | None] = (None, None) + theme_titlebar.bind('<Button-1>', self.drag_start) + theme_titlebar.bind('<B1-Motion>', self.drag_continue) + theme_titlebar.bind('<ButtonRelease-1>', self.drag_end) + theme_minimize = tk.Label(self.theme_menubar, image=self.theme_minimize) + theme_minimize.grid(row=0, column=3, padx=2) + theme.button_bind(theme_minimize, self.oniconify, image=self.theme_minimize) + theme_close = tk.Label(self.theme_menubar, image=self.theme_close) + theme_close.grid(row=0, column=4, padx=2) + theme.button_bind(theme_close, self.onexit, image=self.theme_close) + self.theme_file_menu = tk.Label(self.theme_menubar, anchor=tk.W) + self.theme_file_menu.grid(row=1, column=0, padx=self.PADX, sticky=tk.W) + theme.button_bind(self.theme_file_menu, + lambda e: self.file_menu.tk_popup(e.widget.winfo_rootx(), + e.widget.winfo_rooty() + + e.widget.winfo_height())) + self.theme_edit_menu = tk.Label(self.theme_menubar, anchor=tk.W) + self.theme_edit_menu.grid(row=1, column=1, sticky=tk.W) + theme.button_bind(self.theme_edit_menu, + lambda e: self.edit_menu.tk_popup(e.widget.winfo_rootx(), + e.widget.winfo_rooty() + + e.widget.winfo_height())) + self.theme_help_menu = tk.Label(self.theme_menubar, anchor=tk.W) + self.theme_help_menu.grid(row=1, column=2, sticky=tk.W) + theme.button_bind(self.theme_help_menu, + lambda e: self.help_menu.tk_popup(e.widget.winfo_rootx(), + e.widget.winfo_rooty() + + e.widget.winfo_height())) + tk.Frame(self.theme_menubar, highlightthickness=1).grid(columnspan=5, padx=self.PADX, sticky=tk.EW) + theme.register(self.theme_minimize) # images aren't automatically registered + theme.register(self.theme_close) + self.blank_menubar = tk.Frame(frame, name="blank_menubar") + tk.Label(self.blank_menubar).grid() + tk.Label(self.blank_menubar).grid() + tk.Frame(self.blank_menubar, height=2).grid() + theme.register_alternate((self.menubar, self.theme_menubar, self.blank_menubar), + {'row': 0, 'columnspan': 2, 'sticky': tk.NSEW}) + self.w.resizable(tk.TRUE, tk.FALSE) # update geometry if config.get_str('geometry'): match = re.match(r'\+([\-\d]+)\+([\-\d]+)', config.get_str('geometry')) if match: - if sys.platform == 'darwin': - # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 - if int(match.group(2)) >= 0: - self.w.geometry(config.get_str('geometry')) - elif sys.platform == 'win32': + if sys.platform == 'win32': # Check that the titlebar will be at least partly on screen import ctypes from ctypes.wintypes import POINT @@ -910,49 +865,28 @@ class AppWindow: self.system_label['text'] = _('System') + ':' # LANG: Label for 'System' line in main UI self.station_label['text'] = _('Station') + ':' # LANG: Label for 'Station' line in main UI self.button['text'] = self.theme_button['text'] = _('Update') # LANG: Update button in main window - if sys.platform == 'darwin': - self.menubar.entryconfigure(1, label=_('File')) # LANG: 'File' menu title on OSX - self.menubar.entryconfigure(2, label=_('Edit')) # LANG: 'Edit' menu title on OSX - self.menubar.entryconfigure(3, label=_('View')) # LANG: 'View' menu title on OSX - self.menubar.entryconfigure(4, label=_('Window')) # LANG: 'Window' menu title on OSX - self.menubar.entryconfigure(5, label=_('Help')) # LANG: Help' menu title on OSX - self.system_menu.entryconfigure( - 0, - label=_("About {APP}").format(APP=applongname) # LANG: App menu entry on OSX - ) - self.system_menu.entryconfigure(1, label=_("Check for Updates...")) # LANG: Help > Check for Updates... - self.file_menu.entryconfigure(0, label=_('Save Raw Data...')) # LANG: File > Save Raw Data... - self.view_menu.entryconfigure(0, label=_('Status')) # LANG: File > Status - self.help_menu.entryconfigure(1, label=_('Documentation')) # LANG: Help > Documentation - self.help_menu.entryconfigure(2, label=_('Troubleshooting')) # LANG: Help > Troubleshooting - self.help_menu.entryconfigure(3, label=_('Report A Bug')) # LANG: Help > Report A Bug - self.help_menu.entryconfigure(4, label=_('Privacy Policy')) # LANG: Help > Privacy Policy - self.help_menu.entryconfigure(5, label=_('Release Notes')) # LANG: Help > Release Notes - self.help_menu.entryconfigure(6, label=_('Open Log Folder')) # LANG: Help > Open Log Folder + self.menubar.entryconfigure(1, label=_('File')) # LANG: 'File' menu title + self.menubar.entryconfigure(2, label=_('Edit')) # LANG: 'Edit' menu title + self.menubar.entryconfigure(3, label=_('Help')) # LANG: 'Help' menu title + self.theme_file_menu['text'] = _('File') # LANG: 'File' menu title + self.theme_edit_menu['text'] = _('Edit') # LANG: 'Edit' menu title + self.theme_help_menu['text'] = _('Help') # LANG: 'Help' menu title - else: - self.menubar.entryconfigure(1, label=_('File')) # LANG: 'File' menu title - self.menubar.entryconfigure(2, label=_('Edit')) # LANG: 'Edit' menu title - self.menubar.entryconfigure(3, label=_('Help')) # LANG: 'Help' menu title - self.theme_file_menu['text'] = _('File') # LANG: 'File' menu title - self.theme_edit_menu['text'] = _('Edit') # LANG: 'Edit' menu title - self.theme_help_menu['text'] = _('Help') # LANG: 'Help' menu title + # File menu + self.file_menu.entryconfigure(0, label=_('Status')) # LANG: File > Status + self.file_menu.entryconfigure(1, label=_('Save Raw Data...')) # LANG: File > Save Raw Data... + self.file_menu.entryconfigure(2, label=_('Settings')) # LANG: File > Settings + self.file_menu.entryconfigure(4, label=_('Exit')) # LANG: File > Exit - # File menu - self.file_menu.entryconfigure(0, label=_('Status')) # LANG: File > Status - self.file_menu.entryconfigure(1, label=_('Save Raw Data...')) # LANG: File > Save Raw Data... - self.file_menu.entryconfigure(2, label=_('Settings')) # LANG: File > Settings - self.file_menu.entryconfigure(4, label=_('Exit')) # LANG: File > Exit - - # Help menu - self.help_menu.entryconfigure(0, label=_('Documentation')) # LANG: Help > Documentation - self.help_menu.entryconfigure(1, label=_('Troubleshooting')) # LANG: Help > Troubleshooting - self.help_menu.entryconfigure(2, label=_('Report A Bug')) # LANG: Help > Report A Bug - self.help_menu.entryconfigure(3, label=_('Privacy Policy')) # LANG: Help > Privacy Policy - self.help_menu.entryconfigure(4, label=_('Release Notes')) # LANG: Help > Release Notes - self.help_menu.entryconfigure(5, label=_('Check for Updates...')) # LANG: Help > Check for Updates... - self.help_menu.entryconfigure(6, label=_("About {APP}").format(APP=applongname)) # LANG: Help > About App - self.help_menu.entryconfigure(7, label=_('Open Log Folder')) # LANG: Help > Open Log Folder + # Help menu + self.help_menu.entryconfigure(0, label=_('Documentation')) # LANG: Help > Documentation + self.help_menu.entryconfigure(1, label=_('Troubleshooting')) # LANG: Help > Troubleshooting + self.help_menu.entryconfigure(2, label=_('Report A Bug')) # LANG: Help > Report A Bug + self.help_menu.entryconfigure(3, label=_('Privacy Policy')) # LANG: Help > Privacy Policy + self.help_menu.entryconfigure(4, label=_('Release Notes')) # LANG: Help > Release Notes + self.help_menu.entryconfigure(5, label=_('Check for Updates...')) # LANG: Help > Check for Updates... + self.help_menu.entryconfigure(6, label=_("About {APP}").format(APP=applongname)) # LANG: Help > About App + self.help_menu.entryconfigure(7, label=_('Open Log Folder')) # LANG: Help > Open Log Folder # Edit menu self.edit_menu.entryconfigure(0, label=_('Copy')) # LANG: Label for 'Copy' as in 'Copy and Paste' @@ -975,13 +909,8 @@ class AppWindow: self.button['state'] = self.theme_button['state'] = tk.DISABLED - if sys.platform == 'darwin': - self.view_menu.entryconfigure(0, state=tk.DISABLED) # Status - self.file_menu.entryconfigure(0, state=tk.DISABLED) # Save Raw Data - - else: - self.file_menu.entryconfigure(0, state=tk.DISABLED) # Status - self.file_menu.entryconfigure(1, state=tk.DISABLED) # Save Raw Data + self.file_menu.entryconfigure(0, state=tk.DISABLED) # Status + self.file_menu.entryconfigure(1, state=tk.DISABLED) # Save Raw Data self.w.update_idletasks() try: @@ -989,13 +918,8 @@ class AppWindow: # LANG: Successfully authenticated with the Frontier website self.status['text'] = _('Authentication successful') - if sys.platform == 'darwin': - self.view_menu.entryconfigure(0, state=tk.NORMAL) # Status - self.file_menu.entryconfigure(0, state=tk.NORMAL) # Save Raw Data - - else: - self.file_menu.entryconfigure(0, state=tk.NORMAL) # Status - self.file_menu.entryconfigure(1, state=tk.NORMAL) # Save Raw Data + self.file_menu.entryconfigure(0, state=tk.NORMAL) # Status + self.file_menu.entryconfigure(1, state=tk.NORMAL) # Save Raw Data except (companion.CredentialsError, companion.ServerError, companion.ServerLagging) as e: self.status['text'] = str(e) @@ -1666,13 +1590,8 @@ class AppWindow: companion.session.auth_callback() # LANG: Successfully authenticated with the Frontier website self.status['text'] = _('Authentication successful') - if sys.platform == 'darwin': - self.view_menu.entryconfigure(0, state=tk.NORMAL) # Status - self.file_menu.entryconfigure(0, state=tk.NORMAL) # Save Raw Data - - else: - self.file_menu.entryconfigure(0, state=tk.NORMAL) # Status - self.file_menu.entryconfigure(1, state=tk.NORMAL) # Save Raw Data + self.file_menu.entryconfigure(0, state=tk.NORMAL) # Status + self.file_menu.entryconfigure(1, state=tk.NORMAL) # Save Raw Data except companion.ServerError as e: self.status['text'] = str(e) @@ -1831,7 +1750,7 @@ class AppWindow: # position over parent # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 - if sys.platform != 'darwin' or parent.winfo_rooty() > 0: + if parent.winfo_rooty() > 0: self.geometry(f'+{parent.winfo_rootx():d}+{parent.winfo_rooty():d}') # remove decoration @@ -1916,9 +1835,6 @@ class AppWindow: """ default_extension: str = '' - if sys.platform == 'darwin': - default_extension = '.json' - timestamp: str = strftime('%Y-%m-%dT%H.%M.%S', localtime()) f = tkinter.filedialog.asksaveasfilename( parent=self.w, @@ -1954,7 +1870,7 @@ class AppWindow: config.set_shutdown() # Signal we're in shutdown now. # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 - if sys.platform != 'darwin' or self.w.winfo_rooty() > 0: + if self.w.winfo_rooty() > 0: x, y = self.w.geometry().split('+')[1:3] # e.g. '212x170+2881+1267' config.set('geometry', f'+{x}+{y}') diff --git a/dashboard.py b/dashboard.py index 1f95a943..3948c92b 100644 --- a/dashboard.py +++ b/dashboard.py @@ -20,7 +20,7 @@ from EDMCLogging import get_main_logger logger = get_main_logger() -if sys.platform in ('darwin', 'win32'): +if sys.platform == 'win32': from watchdog.events import FileSystemEventHandler from watchdog.observers import Observer else: diff --git a/myNotebook.py b/myNotebook.py index 6fa35774..dbfc9250 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -78,7 +78,7 @@ class Label(tk.Label): def __init__(self, master: ttk.Frame | None = None, **kw): # This format chosen over `sys.platform in (...)` as mypy and friends dont understand that - if sys.platform in ('darwin', 'win32'): + if sys.platform == 'win32': kw['foreground'] = kw.pop('foreground', PAGEFG) kw['background'] = kw.pop('background', PAGEBG) else: diff --git a/prefs.py b/prefs.py index 6c2722b6..862bda27 100644 --- a/prefs.py +++ b/prefs.py @@ -18,7 +18,7 @@ from typing import TYPE_CHECKING, Any, Callable, Optional, Type import myNotebook as nb # noqa: N813 import plug -from config import applongname, appversion_nobuild, config +from config import appversion_nobuild, config from EDMCLogging import edmclogger, get_main_logger from constants import appname from hotkey import hotkeymgr @@ -49,9 +49,6 @@ def help_open_log_folder() -> None: if sys.platform.startswith('win'): # On Windows, use the "start" command to open the folder system(f'start "" "{logfile_loc}"') - elif sys.platform.startswith('darwin'): - # On macOS, use the "open" command to open the folder - system(f'open "{logfile_loc}"') elif sys.platform.startswith('linux'): # On Linux, use the "xdg-open" command to open the folder system(f'xdg-open "{logfile_loc}"') @@ -172,32 +169,7 @@ class AutoInc(contextlib.AbstractContextManager): return None -if sys.platform == 'darwin': - import objc # type: ignore - from Foundation import NSFileManager # type: ignore - try: - from ApplicationServices import ( # type: ignore - AXIsProcessTrusted, AXIsProcessTrustedWithOptions, kAXTrustedCheckOptionPrompt - ) - - except ImportError: - HIServices = objc.loadBundle( - 'HIServices', - globals(), - '/System/Library/Frameworks/ApplicationServices.framework/Frameworks/HIServices.framework' - ) - - objc.loadBundleFunctions( - HIServices, - globals(), - [('AXIsProcessTrusted', 'B'), ('AXIsProcessTrustedWithOptions', 'B@')] - ) - - objc.loadBundleVariables(HIServices, globals(), [('kAXTrustedCheckOptionPrompt', '@^{__CFString=}')]) - - was_accessible_at_launch = AXIsProcessTrusted() # type: ignore - -elif sys.platform == 'win32': +if sys.platform == 'win32': import ctypes import winreg from ctypes.wintypes import HINSTANCE, HWND, LPCWSTR, LPWSTR, MAX_PATH, POINT, RECT, SIZE, UINT @@ -251,19 +223,14 @@ class PreferencesDialog(tk.Toplevel): self.parent = parent self.callback = callback - if sys.platform == 'darwin': - # LANG: File > Preferences menu entry for macOS - self.title(_('Preferences')) - - else: - # LANG: File > Settings (macOS) - self.title(_('Settings')) + # LANG: File > Settings (macOS) + self.title(_('Settings')) if parent.winfo_viewable(): self.transient(parent) # position over parent - if sys.platform != 'darwin' or parent.winfo_rooty() > 0: # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 + if parent.winfo_rooty() > 0: # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 # TODO this is fixed supposedly. self.geometry(f'+{parent.winfo_rootx()}+{parent.winfo_rooty()}') @@ -271,10 +238,6 @@ class PreferencesDialog(tk.Toplevel): if sys.platform == 'win32': self.attributes('-toolwindow', tk.TRUE) - elif sys.platform == 'darwin': - # http://wiki.tcl.tk/13428 - parent.call('tk::unsupported::MacWindowStyle', 'style', self, 'utility') - self.resizable(tk.FALSE, tk.FALSE) self.cmdr: str | bool | None = False # Note if Cmdr changes in the Journal @@ -302,19 +265,15 @@ class PreferencesDialog(tk.Toplevel): self.__setup_appearance_tab(notebook) self.__setup_plugin_tab(notebook) - if sys.platform == 'darwin': - self.protocol("WM_DELETE_WINDOW", self.apply) # close button applies changes - - else: - buttonframe = ttk.Frame(frame) - buttonframe.grid(padx=self.PADX, pady=self.PADX, sticky=tk.NSEW) - buttonframe.columnconfigure(0, weight=1) - ttk.Label(buttonframe).grid(row=0, column=0) # spacer - # LANG: 'OK' button on Settings/Preferences window - button = ttk.Button(buttonframe, text=_('OK'), command=self.apply) - button.grid(row=0, column=1, sticky=tk.E) - button.bind("<Return>", lambda event: self.apply()) - self.protocol("WM_DELETE_WINDOW", self._destroy) + buttonframe = ttk.Frame(frame) + buttonframe.grid(padx=self.PADX, pady=self.PADX, sticky=tk.NSEW) + buttonframe.columnconfigure(0, weight=1) + ttk.Label(buttonframe).grid(row=0, column=0) # spacer + # LANG: 'OK' button on Settings/Preferences window + button = ttk.Button(buttonframe, text=_('OK'), command=self.apply) + button.grid(row=0, column=1, sticky=tk.E) + button.bind("<Return>", lambda event: self.apply()) + self.protocol("WM_DELETE_WINDOW", self._destroy) # FIXME: Why are these being called when *creating* the Settings window? # Selectively disable buttons depending on output settings @@ -405,11 +364,7 @@ class PreferencesDialog(tk.Toplevel): self.outdir_entry = nb.Entry(output_frame, takefocus=False) self.outdir_entry.grid(columnspan=2, padx=self.PADX, pady=self.BOXY, sticky=tk.EW, row=row.get()) - if sys.platform == 'darwin': - text = (_('Change...')) # LANG: macOS Preferences - files location selection button - - else: - text = (_('Browse...')) # LANG: NOT-macOS Settings - files location selection button + text = (_('Browse...')) # LANG: NOT-macOS Settings - files location selection button self.outbutton = nb.Button( output_frame, @@ -455,11 +410,7 @@ class PreferencesDialog(tk.Toplevel): self.logdir_entry.grid(columnspan=4, padx=self.PADX, pady=self.BOXY, sticky=tk.EW, row=row.get()) - if sys.platform == 'darwin': - text = (_('Change...')) # LANG: macOS Preferences - files location selection button - - else: - text = (_('Browse...')) # LANG: NOT-macOS Setting - files location selection button + text = (_('Browse...')) # LANG: NOT-macOS Setting - files location selection button with row as cur_row: self.logbutton = nb.Button( @@ -499,7 +450,7 @@ class PreferencesDialog(tk.Toplevel): variable=self.capi_fleetcarrier ).grid(columnspan=4, padx=self.BUTTONX, pady=self.PADY, sticky=tk.W, row=row.get()) - if sys.platform in ('darwin', 'win32'): + if sys.platform == 'win32': ttk.Separator(config_frame, orient=tk.HORIZONTAL).grid( columnspan=4, padx=self.PADX, pady=self.SEPY, sticky=tk.EW, row=row.get() ) @@ -511,49 +462,21 @@ class PreferencesDialog(tk.Toplevel): with row as cur_row: nb.Label( config_frame, - text=_('Keyboard shortcut') if # LANG: Hotkey/Shortcut settings prompt on OSX - sys.platform == 'darwin' else - _('Hotkey') # LANG: Hotkey/Shortcut settings prompt on Windows + text=_('Hotkey') # LANG: Hotkey/Shortcut settings prompt on Windows ).grid(padx=self.PADX, pady=self.PADY, sticky=tk.W, row=cur_row) - if sys.platform == 'darwin' and not was_accessible_at_launch: - if AXIsProcessTrusted(): - # Shortcut settings prompt on OSX - nb.Label( - config_frame, - # LANG: macOS Preferences > Configuration - restart the app message - text=_('Re-start {APP} to use shortcuts').format(APP=applongname), - foreground='firebrick' - ).grid(padx=self.PADX, pady=self.PADY, sticky=tk.W, row=cur_row) + self.hotkey_text = nb.Entry(config_frame, width=30, justify=tk.CENTER) + self.hotkey_text.insert( + 0, + # No hotkey/shortcut currently defined + # TODO: display Only shows up on windows + # LANG: No hotkey/shortcut set + hotkeymgr.display(self.hotkey_code, self.hotkey_mods) if self.hotkey_code else _('None') + ) - else: - # Shortcut settings prompt on OSX - nb.Label( - config_frame, - # LANG: macOS - Configuration - need to grant the app permission for keyboard shortcuts - text=_('{APP} needs permission to use shortcuts').format(APP=applongname), - foreground='firebrick' - ).grid(columnspan=4, padx=self.PADX, pady=self.PADY, sticky=tk.W, row=cur_row) - - # LANG: Shortcut settings button on OSX - nb.Button(config_frame, text=_('Open System Preferences'), command=self.enableshortcuts).grid( - padx=self.PADX, pady=self.BOXY, sticky=tk.E, row=cur_row - ) - - else: - self.hotkey_text = nb.Entry(config_frame, width=( - 20 if sys.platform == 'darwin' else 30), justify=tk.CENTER) - self.hotkey_text.insert( - 0, - # No hotkey/shortcut currently defined - # TODO: display Only shows up on darwin or windows - # LANG: No hotkey/shortcut set - hotkeymgr.display(self.hotkey_code, self.hotkey_mods) if self.hotkey_code else _('None') - ) - - self.hotkey_text.bind('<FocusIn>', self.hotkeystart) - self.hotkey_text.bind('<FocusOut>', self.hotkeyend) - self.hotkey_text.grid(column=1, columnspan=2, pady=self.BOXY, sticky=tk.W, row=cur_row) + self.hotkey_text.bind('<FocusIn>', self.hotkeystart) + self.hotkey_text.bind('<FocusOut>', self.hotkeyend) + self.hotkey_text.grid(column=1, columnspan=2, pady=self.BOXY, sticky=tk.W, row=cur_row) # Hotkey/Shortcut setting self.hotkey_only_btn = nb.Checkbutton( @@ -1070,14 +993,6 @@ class PreferencesDialog(tk.Toplevel): def tabchanged(self, event: tk.Event) -> None: """Handle preferences active tab changing.""" self.outvarchanged() - if sys.platform == 'darwin': - # Hack to recompute size so that buttons show up under Mojave - notebook = event.widget - frame = self.nametowidget(notebook.winfo_parent()) - temp = nb.Label(frame) - temp.grid() - temp.update_idletasks() - temp.destroy() def outvarchanged(self, event: Optional[tk.Event] = None) -> None: """Handle Output tab variable changes.""" @@ -1139,16 +1054,6 @@ class PreferencesDialog(tk.Toplevel): entryfield.insert(0, '\\'.join(display)) # None if path doesn't exist - elif sys.platform == 'darwin' and NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get()): - if pathvar.get().startswith(config.home): - display = ['~'] + NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get())[ - len(NSFileManager.defaultManager().componentsToDisplayForPath_(config.home)): - ] - - else: - display = NSFileManager.defaultManager().componentsToDisplayForPath_(pathvar.get()) - - entryfield.insert(0, '/'.join(display)) else: if pathvar.get().startswith(config.home): entryfield.insert(0, '~' + pathvar.get()[len(config.home):]) @@ -1288,7 +1193,7 @@ class PreferencesDialog(tk.Toplevel): config.set('capi_fleetcarrier', self.capi_fleetcarrier.get()) - if sys.platform in ('darwin', 'win32'): + if sys.platform == 'win32': config.set('hotkey_code', self.hotkey_code) config.set('hotkey_mods', self.hotkey_mods) config.set('hotkey_always', int(not self.hotkey_only.get())) @@ -1333,25 +1238,3 @@ class PreferencesDialog(tk.Toplevel): self.parent.wm_attributes('-topmost', 1 if config.get_int('always_ontop') else 0) self.destroy() - - if sys.platform == 'darwin': - def enableshortcuts(self) -> None: - """Set up macOS preferences shortcut.""" - self.apply() - # popup System Preferences dialog - try: - # http://stackoverflow.com/questions/6652598/cocoa-button-opens-a-system-preference-page/6658201 - from ScriptingBridge import SBApplication # type: ignore - sysprefs = 'com.apple.systempreferences' - prefs = SBApplication.applicationWithBundleIdentifier_(sysprefs) - pane = [x for x in prefs.panes() if x.id() == 'com.apple.preference.security'][0] - prefs.setCurrentPane_(pane) - anchor = [x for x in pane.anchors() if x.name() == 'Privacy_Accessibility'][0] - anchor.reveal() - prefs.activate() - - except Exception: - AXIsProcessTrustedWithOptions({kAXTrustedCheckOptionPrompt: True}) - - if not config.shutting_down: - self.parent.event_generate('<<Quit>>', when="tail") From 57cd75e75ebb1a61eebac1f4b3e17b0356d6b57e Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 19:39:51 -0400 Subject: [PATCH 10/49] [2186] Additional Files --- journal_lock.py | 4 -- plugins/eddn.py | 4 +- protocol.py | 63 +------------------------ stats.py | 13 +---- td.py | 2 +- tests/config/_old_config.py | 94 +------------------------------------ theme.py | 21 +-------- update.py | 24 ---------- 8 files changed, 9 insertions(+), 216 deletions(-) diff --git a/journal_lock.py b/journal_lock.py index 4d04992f..3a4dad52 100644 --- a/journal_lock.py +++ b/journal_lock.py @@ -218,10 +218,6 @@ class JournalLock: if sys.platform == 'win32': self.attributes('-toolwindow', tk.TRUE) - elif sys.platform == 'darwin': - # http://wiki.tcl.tk/13428 - parent.call('tk::unsupported::MacWindowStyle', 'style', self, 'utility') - self.resizable(tk.FALSE, tk.FALSE) frame = ttk.Frame(self) diff --git a/plugins/eddn.py b/plugins/eddn.py index 522ce6cb..b7133725 100644 --- a/plugins/eddn.py +++ b/plugins/eddn.py @@ -282,7 +282,7 @@ class EDDNSender: msg['header'] = { # We have to lie and say it's *this* version, but denote that # it might not actually be this version. - 'softwareName': f'{applongname} [{system() if sys.platform != "darwin" else "Mac OS"}]' + 'softwareName': f'{applongname} [{system()}]' ' (legacy replay)', 'softwareVersion': str(appversion_nobuild()), 'uploaderID': cmdr, @@ -1074,7 +1074,7 @@ class EDDN: gb = this.game_build return { - 'softwareName': f'{applongname} [{system() if sys.platform != "darwin" else "Mac OS"}]', + 'softwareName': f'{applongname} [{system()}]', 'softwareVersion': str(appversion_nobuild()), 'uploaderID': this.cmdr_name, 'gameversion': gv, diff --git a/protocol.py b/protocol.py index f3b956d2..0f1c157f 100644 --- a/protocol.py +++ b/protocol.py @@ -58,66 +58,7 @@ class GenericProtocolHandler: self.master.event_generate('<<CompanionAuthEvent>>', when="tail") -if sys.platform == 'darwin' and getattr(sys, 'frozen', False): # noqa: C901 # its guarding ALL macos stuff. - import struct - - import objc # type: ignore - from AppKit import NSAppleEventManager, NSObject # type: ignore - - kInternetEventClass = kAEGetURL = struct.unpack('>l', b'GURL')[0] # noqa: N816 # API names - keyDirectObject = struct.unpack('>l', b'----')[0] # noqa: N816 # API names - - class DarwinProtocolHandler(GenericProtocolHandler): - """ - MacOS protocol handler implementation. - - Uses macOS event stuff. - """ - - POLL = 100 # ms - - def start(self, master: 'tkinter.Tk') -> None: - """Start Protocol Handler.""" - GenericProtocolHandler.start(self, master) - self.lasturl: str | None = None - self.eventhandler = EventHandler.alloc().init() - - def poll(self) -> None: - """Poll event until URL is updated.""" - # No way of signalling to Tkinter from within the callback handler block that doesn't cause Python to crash, - # so poll. TODO: Resolved? - if self.lasturl and self.lasturl.startswith(self.redirect): - self.event(self.lasturl) - self.lasturl = None - - class EventHandler(NSObject): - """Handle NSAppleEventManager IPC stuff.""" - - def init(self) -> None: - """ - Init method for handler. - - (I'd assume this is related to the subclassing of NSObject for why its not __init__) - """ - self = objc.super(EventHandler, self).init() - NSAppleEventManager.sharedAppleEventManager().setEventHandler_andSelector_forEventClass_andEventID_( - self, - 'handleEvent:withReplyEvent:', - kInternetEventClass, - kAEGetURL - ) - return self - - def handleEvent_withReplyEvent_(self, event, replyEvent) -> None: # noqa: N802 N803 # Required to override - """Actual event handling from NSAppleEventManager.""" - protocolhandler.lasturl = parse.unquote( - event.paramDescriptorForKeyword_(keyDirectObject).stringValue() - ).strip() - - protocolhandler.master.after(DarwinProtocolHandler.POLL, protocolhandler.poll) - - -elif (config.auth_force_edmc_protocol +if (config.auth_force_edmc_protocol or ( sys.platform == 'win32' and getattr(sys, 'frozen', False) @@ -480,8 +421,6 @@ def get_handler_impl() -> Type[GenericProtocolHandler]: :return: An instantiatable GenericProtocolHandler """ - if sys.platform == 'darwin' and getattr(sys, 'frozen', False): - return DarwinProtocolHandler # pyright: reportUnboundVariable=false if ( (sys.platform == 'win32' and config.auth_force_edmc_protocol) diff --git a/stats.py b/stats.py index 4351e297..c377e5d3 100644 --- a/stats.py +++ b/stats.py @@ -374,7 +374,7 @@ class StatsResults(tk.Toplevel): self.transient(parent) # position over parent - if sys.platform != 'darwin' or parent.winfo_rooty() > 0: # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 + if parent.winfo_rooty() > 0: # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 self.geometry(f"+{parent.winfo_rootx()}+{parent.winfo_rooty()}") # remove decoration @@ -382,10 +382,6 @@ class StatsResults(tk.Toplevel): if sys.platform == 'win32': self.attributes('-toolwindow', tk.TRUE) - elif sys.platform == 'darwin': - # http://wiki.tcl.tk/13428 - parent.call('tk::unsupported::MacWindowStyle', 'style', self, 'utility') - frame = ttk.Frame(self) frame.grid(sticky=tk.NSEW) @@ -423,13 +419,6 @@ class StatsResults(tk.Toplevel): ttk.Frame(page).grid(pady=5) # bottom spacer notebook.add(page, text=_('Ships')) # LANG: Status dialog title - if sys.platform != 'darwin': - buttonframe = ttk.Frame(frame) - buttonframe.grid(padx=10, pady=(0, 10), sticky=tk.NSEW) # type: ignore # the tuple is supported - buttonframe.columnconfigure(0, weight=1) - ttk.Label(buttonframe).grid(row=0, column=0) # spacer - ttk.Button(buttonframe, text='OK', command=self.destroy).grid(row=0, column=1, sticky=tk.E) - # wait for window to appear on screen before calling grab_set self.wait_visibility() self.grab_set() diff --git a/td.py b/td.py index 6a588f57..d2b5dbdd 100644 --- a/td.py +++ b/td.py @@ -32,7 +32,7 @@ def export(data: CAPIData) -> None: with open(data_path / data_filename, 'wb') as h: # Format described here: https://github.com/eyeonus/Trade-Dangerous/wiki/Price-Data h.write('#! trade.py import -\n'.encode('utf-8')) - this_platform = "Mac OS" if sys.platform == 'darwin' else system() + this_platform = system() cmdr_name = data['commander']['name'].strip() h.write( f'# Created by {applongname} {appversion()} on {this_platform} for Cmdr {cmdr_name}.\n'.encode('utf-8') diff --git a/tests/config/_old_config.py b/tests/config/_old_config.py index 690c75eb..35ae19e3 100644 --- a/tests/config/_old_config.py +++ b/tests/config/_old_config.py @@ -13,13 +13,7 @@ from EDMCLogging import get_main_logger logger = get_main_logger() -if sys.platform == 'darwin': - from Foundation import ( # type: ignore - NSApplicationSupportDirectory, NSBundle, NSDocumentDirectory, NSSearchPathForDirectoriesInDomains, - NSUserDefaults, NSUserDomainMask - ) - -elif sys.platform == 'win32': +if sys.platform == 'win32': import ctypes import uuid from ctypes.wintypes import DWORD, HANDLE, HKEY, LONG, LPCVOID, LPCWSTR @@ -115,91 +109,7 @@ class OldConfig: OUT_EDDN_DELAY = 4096 OUT_STATION_ANY = OUT_EDDN_SEND_STATION_DATA | OUT_MKT_TD | OUT_MKT_CSV - if sys.platform == 'darwin': # noqa: C901 # It's gating *all* the functions - - def __init__(self): - self.app_dir = join( - NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True)[0], appname - ) - if not isdir(self.app_dir): - mkdir(self.app_dir) - - self.plugin_dir = join(self.app_dir, 'plugins') - if not isdir(self.plugin_dir): - mkdir(self.plugin_dir) - - if getattr(sys, 'frozen', False): - self.internal_plugin_dir = normpath(join(dirname(sys.executable), pardir, 'Library', 'plugins')) - self.respath = normpath(join(dirname(sys.executable), pardir, 'Resources')) - self.identifier = NSBundle.mainBundle().bundleIdentifier() - - else: - self.internal_plugin_dir = join(dirname(__file__), 'plugins') - self.respath = dirname(__file__) - # Don't use Python's settings if interactive - self.identifier = f'uk.org.marginal.{appname.lower()}' - NSBundle.mainBundle().infoDictionary()['CFBundleIdentifier'] = self.identifier - - self.default_journal_dir: str | None = join( - NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True)[0], - 'Frontier Developments', - 'Elite Dangerous' - ) - self.home = expanduser('~') - - self.defaults = NSUserDefaults.standardUserDefaults() - self.settings = dict(self.defaults.persistentDomainForName_(self.identifier) or {}) # make writeable - - # Check out_dir exists - if not self.get('outdir') or not isdir(str(self.get('outdir'))): - self.set('outdir', NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, True)[0]) - - def get(self, key: str, default: None | list | str = None) -> None | list | str: - """Look up a string configuration value.""" - val = self.settings.get(key) - if val is None: - return default - - if isinstance(val, str): - return str(val) - - if isinstance(val, list): - return list(val) # make writeable - - return default - - def getint(self, key: str, default: int = 0) -> int: - """Look up an integer configuration value.""" - try: - return int(self.settings.get(key, default)) # should already be int, but check by casting - - except ValueError as e: - logger.error(f"Failed to int({key=})", exc_info=e) - return default - - except Exception as e: - logger.debug('The exception type is ...', exc_info=e) - return default - - def set(self, key: str, val: int | str | list) -> None: - """Set value on the specified configuration key.""" - self.settings[key] = val - - def delete(self, key: str) -> None: - """Delete the specified configuration key.""" - self.settings.pop(key, None) - - def save(self) -> None: - """Save current configuration to disk.""" - self.defaults.setPersistentDomain_forName_(self.settings, self.identifier) - self.defaults.synchronize() - - def close(self) -> None: - """Close the configuration.""" - self.save() - self.defaults = None - - elif sys.platform == 'win32': + if sys.platform == 'win32': def __init__(self): self.app_dir = join(known_folder_path(FOLDERID_LocalAppData), appname) # type: ignore diff --git a/theme.py b/theme.py index bfb76c55..b128bc91 100644 --- a/theme.py +++ b/theme.py @@ -268,8 +268,7 @@ class _Theme: # (Mostly) system colors style = ttk.Style() self.current = { - 'background': (sys.platform == 'darwin' and 'systemMovableModalBackground' or - style.lookup('TLabel', 'background')), + 'background': (style.lookup('TLabel', 'background')), 'foreground': style.lookup('TLabel', 'foreground'), 'activebackground': (sys.platform == 'win32' and 'SystemHighlight' or style.lookup('TLabel', 'background', ['active'])), @@ -366,8 +365,6 @@ class _Theme: if 'bg' not in attribs: widget['background'] = self.current['background'] widget['activebackground'] = self.current['activebackground'] - if sys.platform == 'darwin' and isinstance(widget, tk.Button): - widget['highlightbackground'] = self.current['background'] if 'font' not in attribs: widget['font'] = self.current['font'] @@ -426,21 +423,7 @@ class _Theme: return # Don't need to mess with the window manager self.active = theme - if sys.platform == 'darwin': - from AppKit import NSAppearance, NSApplication, NSMiniaturizableWindowMask, NSResizableWindowMask - root.update_idletasks() # need main window to be created - if theme == self.THEME_DEFAULT: - appearance = NSAppearance.appearanceNamed_('NSAppearanceNameAqua') - - else: # Dark (Transparent only on win32) - appearance = NSAppearance.appearanceNamed_('NSAppearanceNameDarkAqua') - - for window in NSApplication.sharedApplication().windows(): - window.setStyleMask_(window.styleMask() & ~( - NSMiniaturizableWindowMask | NSResizableWindowMask)) # disable zoom - window.setAppearance_(appearance) - - elif sys.platform == 'win32': + if sys.platform == 'win32': GWL_STYLE = -16 # noqa: N806 # ctypes WS_MAXIMIZEBOX = 0x00010000 # noqa: N806 # ctypes # tk8.5.9/win/tkWinWm.c:342 diff --git a/update.py b/update.py index 024aeb09..e0b8f97b 100644 --- a/update.py +++ b/update.py @@ -115,21 +115,6 @@ class Updater: return - if sys.platform == 'darwin': - import objc - - try: - objc.loadBundle( - 'Sparkle', globals(), join(dirname(sys.executable), os.pardir, 'Frameworks', 'Sparkle.framework') - ) - # loadBundle presumably supplies `SUUpdater` - self.updater = SUUpdater.sharedUpdater() # noqa: F821 - - except Exception: - # can't load framework - not frozen or not included in app bundle? - print_exc() - self.updater = None - def set_automatic_updates_check(self, onoroff: bool) -> None: """ Set (Win)Sparkle to perform automatic update checks, or not. @@ -142,9 +127,6 @@ class Updater: if sys.platform == 'win32' and self.updater: self.updater.win_sparkle_set_automatic_check_for_updates(onoroff) - if sys.platform == 'darwin' and self.updater: - self.updater.SUEnableAutomaticChecks(onoroff) - def check_for_updates(self) -> None: """Trigger the requisite method to check for an update.""" if self.use_internal(): @@ -155,9 +137,6 @@ class Updater: elif sys.platform == 'win32' and self.updater: self.updater.win_sparkle_check_update_with_ui() - elif sys.platform == 'darwin' and self.updater: - self.updater.checkForUpdates_(None) - def check_appcast(self) -> EDMCVersion | None: """ Manually (no Sparkle or WinSparkle) check the update_feed appcast file. @@ -184,9 +163,6 @@ class Updater: return None - if sys.platform == 'darwin': - sparkle_platform = 'macos' - else: # For *these* purposes anything else is the same as 'windows', as # non-win32 would be running from source. From 05eaf059389a25d16c778ea6861e0836a71184f3 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 19:41:01 -0400 Subject: [PATCH 11/49] [Minor] Remove Unused Import For Now --- ttkHyperlinkLabel.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ttkHyperlinkLabel.py b/ttkHyperlinkLabel.py index 0ca87fc7..3b65d6b9 100644 --- a/ttkHyperlinkLabel.py +++ b/ttkHyperlinkLabel.py @@ -22,7 +22,6 @@ from __future__ import annotations import sys import tkinter as tk -import warnings import webbrowser from tkinter import font as tk_font from tkinter import ttk From 08818785d051b81a7ad88c6975b0be0df88a07c7 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 20:03:23 -0400 Subject: [PATCH 12/49] [2186] HyperLinkLabel first pass --- ttkHyperlinkLabel.py | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/ttkHyperlinkLabel.py b/ttkHyperlinkLabel.py index 3b65d6b9..de906510 100644 --- a/ttkHyperlinkLabel.py +++ b/ttkHyperlinkLabel.py @@ -32,7 +32,7 @@ if TYPE_CHECKING: # FIXME: Split this into multi-file module to separate the platforms -class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label): # type: ignore +class HyperlinkLabel(tk.Label or ttk.Label): # type: ignore """Clickable label for HTTP links.""" def __init__(self, master: ttk.Frame | tk.Frame | None = None, **kw: Any) -> None: @@ -50,22 +50,14 @@ class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label): # typ self.foreground = kw.get('foreground', 'blue') self.disabledforeground = kw.pop('disabledforeground', ttk.Style().lookup( 'TLabel', 'foreground', ('disabled',))) # ttk.Label doesn't support disabledforeground option - - if sys.platform == 'darwin': - # Use tk.Label 'cos can't set ttk.Label background - http://www.tkdocs.com/tutorial/styles.html#whydifficult - kw['background'] = kw.pop('background', 'systemDialogBackgroundActive') - kw['anchor'] = kw.pop('anchor', tk.W) # like ttk.Label - tk.Label.__init__(self, master, **kw) - - else: - ttk.Label.__init__(self, master, **kw) + ttk.Label.__init__(self, master, **kw) self.bind('<Button-1>', self._click) self.menu = tk.Menu(tearoff=tk.FALSE) # LANG: Label for 'Copy' as in 'Copy and Paste' self.menu.add_command(label=_('Copy'), command=self.copy) # As in Copy and Paste - self.bind(sys.platform == 'darwin' and '<Button-2>' or '<Button-3>', self._contextmenu) + self.bind('<Button-3>', self._contextmenu) self.bind('<Enter>', self._enter) self.bind('<Leave>', self._leave) @@ -106,10 +98,9 @@ class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label): # typ if state == tk.DISABLED: kw['cursor'] = 'arrow' # System default elif self.url and (kw['text'] if 'text' in kw else self['text']): - kw['cursor'] = 'pointinghand' if sys.platform == 'darwin' else 'hand2' + kw['cursor'] = 'hand2' else: - kw['cursor'] = 'notallowed' if sys.platform == 'darwin' else ( - 'no' if sys.platform == 'win32' else 'circle') + kw['cursor'] = ('no' if sys.platform == 'win32' else 'circle') return super().configure(cnf, **kw) @@ -139,7 +130,7 @@ class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label): # typ def _contextmenu(self, event: tk.Event) -> None: if self['text'] and (self.popup_copy(self['text']) if callable(self.popup_copy) else self.popup_copy): - self.menu.post(sys.platform == 'darwin' and event.x_root + 1 or event.x_root, event.y_root) + self.menu.post(event.x_root, event.y_root) def copy(self) -> None: """Copy the current text to the clipboard.""" From f7b39f8dafedf453f6f80e278f88d8e12ccced60 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 20:10:55 -0400 Subject: [PATCH 13/49] [2186] MyNB First Pass --- myNotebook.py | 66 +++++++-------------------------------------------- 1 file changed, 9 insertions(+), 57 deletions(-) diff --git a/myNotebook.py b/myNotebook.py index dbfc9250..efae591c 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -16,13 +16,7 @@ import sys import tkinter as tk from tkinter import ttk -# Can't do this with styles on OSX - http://www.tkdocs.com/tutorial/styles.html#whydifficult -if sys.platform == 'darwin': - from platform import mac_ver - PAGEFG = 'systemButtonText' - PAGEBG = 'systemButtonActiveDarkShadow' - -elif sys.platform == 'win32': +if sys.platform == 'win32': PAGEFG = 'SystemWindowText' PAGEBG = 'SystemWindow' # typically white @@ -35,14 +29,7 @@ class Notebook(ttk.Notebook): ttk.Notebook.__init__(self, master, **kw) style = ttk.Style() - if sys.platform == 'darwin': - if list(map(int, mac_ver()[0].split('.'))) >= [10, 10]: - # Hack for tab appearance with 8.5 on Yosemite & El Capitan. For proper fix see - # https://github.com/tcltk/tk/commit/55c4dfca9353bbd69bbcec5d63bf1c8dfb461e25 - style.configure('TNotebook.Tab', padding=(12, 10, 12, 2)) - style.map('TNotebook.Tab', foreground=[('selected', '!background', 'systemWhite')]) - self.grid(sticky=tk.NSEW) # Already padded apropriately - elif sys.platform == 'win32': + if sys.platform == 'win32': style.configure('nb.TFrame', background=PAGEBG) style.configure('nb.TButton', background=PAGEBG) style.configure('nb.TCheckbutton', foreground=PAGEFG, background=PAGEBG) @@ -60,11 +47,7 @@ class Frame(sys.platform == 'darwin' and tk.Frame or ttk.Frame): # type: ignore """Custom t(t)k.Frame class to fix some display issues.""" def __init__(self, master: ttk.Notebook | None = None, **kw): - if sys.platform == 'darwin': - kw['background'] = kw.pop('background', PAGEBG) - tk.Frame.__init__(self, master, **kw) - tk.Frame(self).grid(pady=5) - elif sys.platform == 'win32': + if sys.platform == 'win32': ttk.Frame.__init__(self, master, style='nb.TFrame', **kw) ttk.Frame(self).grid(pady=5) # top spacer else: @@ -91,21 +74,14 @@ class Entry(sys.platform == 'darwin' and tk.Entry or ttk.Entry): # type: ignore """Custom t(t)k.Entry class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): - if sys.platform == 'darwin': - kw['highlightbackground'] = kw.pop('highlightbackground', PAGEBG) - tk.Entry.__init__(self, master, **kw) - else: - ttk.Entry.__init__(self, master, **kw) + ttk.Entry.__init__(self, master, **kw) class Button(sys.platform == 'darwin' and tk.Button or ttk.Button): # type: ignore """Custom t(t)k.Button class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): - if sys.platform == 'darwin': - kw['highlightbackground'] = kw.pop('highlightbackground', PAGEBG) - tk.Button.__init__(self, master, **kw) - elif sys.platform == 'win32': + if sys.platform == 'win32': ttk.Button.__init__(self, master, style='nb.TButton', **kw) else: ttk.Button.__init__(self, master, **kw) @@ -115,29 +91,14 @@ class ColoredButton(sys.platform == 'darwin' and tk.Label or tk.Button): # type """Custom t(t)k.ColoredButton class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): - if sys.platform == 'darwin': - # Can't set Button background on OSX, so use a Label instead - kw['relief'] = kw.pop('relief', tk.RAISED) - self._command = kw.pop('command', None) - tk.Label.__init__(self, master, **kw) - self.bind('<Button-1>', self._press) - else: - tk.Button.__init__(self, master, **kw) - - if sys.platform == 'darwin': - def _press(self, event): - self._command() + tk.Button.__init__(self, master, **kw) class Checkbutton(sys.platform == 'darwin' and tk.Checkbutton or ttk.Checkbutton): # type: ignore """Custom t(t)k.Checkbutton class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): - if sys.platform == 'darwin': - kw['foreground'] = kw.pop('foreground', PAGEFG) - kw['background'] = kw.pop('background', PAGEBG) - tk.Checkbutton.__init__(self, master, **kw) - elif sys.platform == 'win32': + if sys.platform == 'win32': ttk.Checkbutton.__init__(self, master, style='nb.TCheckbutton', **kw) else: ttk.Checkbutton.__init__(self, master, **kw) @@ -147,11 +108,7 @@ class Radiobutton(sys.platform == 'darwin' and tk.Radiobutton or ttk.Radiobutton """Custom t(t)k.Radiobutton class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): - if sys.platform == 'darwin': - kw['foreground'] = kw.pop('foreground', PAGEFG) - kw['background'] = kw.pop('background', PAGEBG) - tk.Radiobutton.__init__(self, master, **kw) - elif sys.platform == 'win32': + if sys.platform == 'win32': ttk.Radiobutton.__init__(self, master, style='nb.TRadiobutton', **kw) else: ttk.Radiobutton.__init__(self, master, **kw) @@ -161,12 +118,7 @@ class OptionMenu(sys.platform == 'darwin' and tk.OptionMenu or ttk.OptionMenu): """Custom t(t)k.OptionMenu class to fix some display issues.""" def __init__(self, master, variable, default=None, *values, **kw): - if sys.platform == 'darwin': - variable.set(default) - bg = kw.pop('background', PAGEBG) - tk.OptionMenu.__init__(self, master, variable, *values, **kw) - self['background'] = bg - elif sys.platform == 'win32': + if sys.platform == 'win32': # OptionMenu derives from Menubutton at the Python level, so uses Menubutton's style ttk.OptionMenu.__init__(self, master, variable, default, *values, style='nb.TMenubutton', **kw) self['menu'].configure(background=PAGEBG) From c1b8533cb41c2e33d63311dac120ff7b0ddd4c29 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 21:22:35 -0400 Subject: [PATCH 14/49] [2186] Simplify myNB Files --- docs/examples/click_counter/load.py | 4 +- myNotebook.py | 95 ++++++++++++----------------- plugins/coriolis.py | 8 +-- plugins/edsm.py | 8 +-- plugins/inara.py | 4 +- prefs.py | 22 +++---- 6 files changed, 62 insertions(+), 79 deletions(-) diff --git a/docs/examples/click_counter/load.py b/docs/examples/click_counter/load.py index ad90a084..f7f23837 100644 --- a/docs/examples/click_counter/load.py +++ b/docs/examples/click_counter/load.py @@ -7,6 +7,8 @@ from __future__ import annotations import logging import tkinter as tk +from tkinter import ttk + import myNotebook as nb # noqa: N813 from config import appname, config @@ -63,7 +65,7 @@ class ClickCounter: # setup our config in a "Click Count: number" nb.Label(frame, text='Click Count').grid(row=current_row) - nb.Entry(frame, textvariable=self.click_count).grid(row=current_row, column=1) + ttk.Entry(frame, textvariable=self.click_count).grid(row=current_row, column=1) current_row += 1 # Always increment our row counter, makes for far easier tkinter design. return frame diff --git a/myNotebook.py b/myNotebook.py index efae591c..528664ba 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -1,12 +1,9 @@ """ Custom `ttk.Notebook` to fix various display issues. -Hacks to fix various display issues with notebooks and their child widgets on -OSX and Windows. +Hacks to fix various display issues with notebooks and their child widgets on Windows. - Windows: page background should be White, not SystemButtonFace -- OSX: page background should be a darker gray than systemWindowBody - selected tab foreground should be White when the window is active Entire file may be imported by plugins. """ @@ -26,24 +23,17 @@ class Notebook(ttk.Notebook): def __init__(self, master: ttk.Frame | None = None, **kw): - ttk.Notebook.__init__(self, master, **kw) + super().__init__(master, **kw) style = ttk.Style() - - if sys.platform == 'win32': - style.configure('nb.TFrame', background=PAGEBG) - style.configure('nb.TButton', background=PAGEBG) - style.configure('nb.TCheckbutton', foreground=PAGEFG, background=PAGEBG) - style.configure('nb.TMenubutton', foreground=PAGEFG, background=PAGEBG) - style.configure('nb.TRadiobutton', foreground=PAGEFG, background=PAGEBG) - self.grid(padx=10, pady=10, sticky=tk.NSEW) - else: - self.grid(padx=10, pady=10, sticky=tk.NSEW) + style.configure('nb.TFrame', background=PAGEBG) + style.configure('nb.TButton', background=PAGEBG) + style.configure('nb.TCheckbutton', foreground=PAGEFG, background=PAGEBG) + style.configure('nb.TMenubutton', foreground=PAGEFG, background=PAGEBG) + style.configure('nb.TRadiobutton', foreground=PAGEFG, background=PAGEBG) + self.grid(padx=10, pady=10, sticky=tk.NSEW) -# FIXME: The real fix for this 'dynamic type' would be to split this whole -# thing into being a module with per-platform files, as we've done with config -# That would also make the code cleaner. -class Frame(sys.platform == 'darwin' and tk.Frame or ttk.Frame): # type: ignore +class Frame(tk.Frame or ttk.Frame): # type: ignore """Custom t(t)k.Frame class to fix some display issues.""" def __init__(self, master: ttk.Notebook | None = None, **kw): @@ -60,26 +50,25 @@ class Label(tk.Label): """Custom tk.Label class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): - # This format chosen over `sys.platform in (...)` as mypy and friends dont understand that - if sys.platform == 'win32': - kw['foreground'] = kw.pop('foreground', PAGEFG) - kw['background'] = kw.pop('background', PAGEBG) - else: - kw['foreground'] = kw.pop('foreground', ttk.Style().lookup('TLabel', 'foreground')) - kw['background'] = kw.pop('background', ttk.Style().lookup('TLabel', 'background')) - tk.Label.__init__(self, master, **kw) # Just use tk.Label on all platforms + kw['foreground'] = kw.pop('foreground', PAGEFG if sys.platform == 'win32' + else ttk.Style().lookup('TLabel', 'foreground')) + kw['background'] = kw.pop('background', PAGEBG if sys.platform == 'win32' + else ttk.Style().lookup('TLabel', 'background')) + super().__init__(master, **kw) -class Entry(sys.platform == 'darwin' and tk.Entry or ttk.Entry): # type: ignore +class Entry(ttk.Entry): # type: ignore """Custom t(t)k.Entry class to fix some display issues.""" + # DEPRECATED: Migrate to ttk.Entry. Will remove in 5.12 or later. def __init__(self, master: ttk.Frame | None = None, **kw): - ttk.Entry.__init__(self, master, **kw) + super().__init__(master, **kw) -class Button(sys.platform == 'darwin' and tk.Button or ttk.Button): # type: ignore +class Button(tk.Button or ttk.Button): # type: ignore """Custom t(t)k.Button class to fix some display issues.""" + # DEPRECATED: Migrate to ttk.Button. Will remove in 5.12 or later. def __init__(self, master: ttk.Frame | None = None, **kw): if sys.platform == 'win32': ttk.Button.__init__(self, master, style='nb.TButton', **kw) @@ -87,47 +76,39 @@ class Button(sys.platform == 'darwin' and tk.Button or ttk.Button): # type: ign ttk.Button.__init__(self, master, **kw) -class ColoredButton(sys.platform == 'darwin' and tk.Label or tk.Button): # type: ignore +class ColoredButton(tk.Label or tk.Button): # type: ignore """Custom t(t)k.ColoredButton class to fix some display issues.""" + # DEPRECATED: Migrate to tk.Button. Will remove in 5.12 or later. def __init__(self, master: ttk.Frame | None = None, **kw): tk.Button.__init__(self, master, **kw) -class Checkbutton(sys.platform == 'darwin' and tk.Checkbutton or ttk.Checkbutton): # type: ignore +class Checkbutton(ttk.Checkbutton): """Custom t(t)k.Checkbutton class to fix some display issues.""" - def __init__(self, master: ttk.Frame | None = None, **kw): - if sys.platform == 'win32': - ttk.Checkbutton.__init__(self, master, style='nb.TCheckbutton', **kw) - else: - ttk.Checkbutton.__init__(self, master, **kw) + def __init__(self, master=None, **kw): + style = 'nb.TCheckbutton' if sys.platform == 'win32' else None + super().__init__(master, style=style, **kw) # type: ignore -class Radiobutton(sys.platform == 'darwin' and tk.Radiobutton or ttk.Radiobutton): # type: ignore +class Radiobutton(ttk.Radiobutton): """Custom t(t)k.Radiobutton class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): - if sys.platform == 'win32': - ttk.Radiobutton.__init__(self, master, style='nb.TRadiobutton', **kw) - else: - ttk.Radiobutton.__init__(self, master, **kw) + style = 'nb.TRadiobutton' if sys.platform == 'win32' else None + super().__init__(master, style=style, **kw) # type: ignore -class OptionMenu(sys.platform == 'darwin' and tk.OptionMenu or ttk.OptionMenu): # type: ignore - """Custom t(t)k.OptionMenu class to fix some display issues.""" +class OptionMenu(ttk.OptionMenu): + """Custom ttk.OptionMenu class to fix some display issues.""" def __init__(self, master, variable, default=None, *values, **kw): - if sys.platform == 'win32': - # OptionMenu derives from Menubutton at the Python level, so uses Menubutton's style - ttk.OptionMenu.__init__(self, master, variable, default, *values, style='nb.TMenubutton', **kw) - self['menu'].configure(background=PAGEBG) - # Workaround for https://bugs.python.org/issue25684 - for i in range(0, self['menu'].index('end')+1): - self['menu'].entryconfig(i, variable=variable) - else: - ttk.OptionMenu.__init__(self, master, variable, default, *values, **kw) - self['menu'].configure(background=ttk.Style().lookup('TMenu', 'background')) - # Workaround for https://bugs.python.org/issue25684 - for i in range(0, self['menu'].index('end')+1): - self['menu'].entryconfig(i, variable=variable) + style = 'nb.TMenubutton' if sys.platform == 'win32' else ttk.Style().lookup('TMenu', 'background') + menu_background = PAGEBG if sys.platform == 'win32' else ttk.Style().lookup('TMenu', 'background') + + super().__init__(master, variable, default, *values, style=style, **kw) + self['menu'].configure(background=menu_background) + + for i in range(self['menu'].index('end') + 1): + self['menu'].entryconfig(i, variable=variable) diff --git a/plugins/coriolis.py b/plugins/coriolis.py index c142c686..20da16b1 100644 --- a/plugins/coriolis.py +++ b/plugins/coriolis.py @@ -106,12 +106,12 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> tk.Fr # LANG: Settings>Coriolis: Label for 'NOT alpha/beta game version' URL nb.Label(conf_frame, text=_('Normal URL')).grid(sticky=tk.W, row=cur_row, column=0, padx=PADX, pady=PADY) - nb.Entry(conf_frame, + ttk.Entry(conf_frame, textvariable=coriolis_config.normal_textvar).grid( sticky=tk.EW, row=cur_row, column=1, padx=PADX, pady=BOXY ) # LANG: Generic 'Reset' button label - nb.Button(conf_frame, text=_("Reset"), + ttk.Button(conf_frame, text=_("Reset"), command=lambda: coriolis_config.normal_textvar.set(value=DEFAULT_NORMAL_URL)).grid( sticky=tk.W, row=cur_row, column=2, padx=PADX, pady=0 ) @@ -119,11 +119,11 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> tk.Fr # LANG: Settings>Coriolis: Label for 'alpha/beta game version' URL nb.Label(conf_frame, text=_('Beta URL')).grid(sticky=tk.W, row=cur_row, column=0, padx=PADX, pady=PADY) - nb.Entry(conf_frame, textvariable=coriolis_config.beta_textvar).grid( + ttk.Entry(conf_frame, textvariable=coriolis_config.beta_textvar).grid( sticky=tk.EW, row=cur_row, column=1, padx=PADX, pady=BOXY ) # LANG: Generic 'Reset' button label - nb.Button(conf_frame, text=_('Reset'), + ttk.Button(conf_frame, text=_('Reset'), command=lambda: coriolis_config.beta_textvar.set(value=DEFAULT_BETA_URL)).grid( sticky=tk.W, row=cur_row, column=2, padx=PADX, pady=0 ) diff --git a/plugins/edsm.py b/plugins/edsm.py index 46d05f4c..146dd5ab 100644 --- a/plugins/edsm.py +++ b/plugins/edsm.py @@ -113,10 +113,10 @@ class This: self.cmdr_text: nb.Label | None = None self.user_label: nb.Label | None = None - self.user: nb.Entry | None = None + self.user: ttk.Entry | None = None self.apikey_label: nb.Label | None = None - self.apikey: nb.Entry | None = None + self.apikey: ttk.Entry | None = None this = This() @@ -345,14 +345,14 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> tk.Fr # LANG: EDSM Commander name label in EDSM settings this.user_label = nb.Label(frame, text=_('Commander Name')) this.user_label.grid(row=cur_row, padx=PADX, pady=PADY, sticky=tk.W) - this.user = nb.Entry(frame) + this.user = ttk.Entry(frame) this.user.grid(row=cur_row, column=1, padx=PADX, pady=BOXY, sticky=tk.EW) cur_row += 1 # LANG: EDSM API key label this.apikey_label = nb.Label(frame, text=_('API Key')) this.apikey_label.grid(row=cur_row, padx=PADX, pady=PADY, sticky=tk.W) - this.apikey = nb.Entry(frame, show="*", width=50) + this.apikey = ttk.Entry(frame, show="*", width=50) this.apikey.grid(row=cur_row, column=1, padx=PADX, pady=BOXY, sticky=tk.EW) cur_row += 1 diff --git a/plugins/inara.py b/plugins/inara.py index 0e0eb7bf..d96e05ef 100644 --- a/plugins/inara.py +++ b/plugins/inara.py @@ -125,7 +125,7 @@ class This: self.log: 'tk.IntVar' self.log_button: nb.Checkbutton self.label: HyperlinkLabel - self.apikey: nb.Entry + self.apikey: ttk.Entry self.apikey_label: tk.Label self.events: dict[Credentials, Deque[Event]] = defaultdict(deque) @@ -292,7 +292,7 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str, is_beta: bool) -> tk.Frame: # LANG: Inara API key label this.apikey_label = nb.Label(frame, text=_('API Key')) # Inara setting this.apikey_label.grid(row=cur_row, padx=PADX, pady=PADY, sticky=tk.W) - this.apikey = nb.Entry(frame, show="*", width=50) + this.apikey = ttk.Entry(frame, show="*", width=50) this.apikey.grid(row=cur_row, column=1, padx=PADX, pady=BOXY, sticky=tk.EW) cur_row += 1 diff --git a/prefs.py b/prefs.py index 862bda27..ef43c5de 100644 --- a/prefs.py +++ b/prefs.py @@ -361,12 +361,12 @@ class PreferencesDialog(tk.Toplevel): # Type ignored due to incorrect type annotation. a 2 tuple does padding for each side self.outdir_label.grid(padx=self.PADX, pady=self.PADY, sticky=tk.W, row=row.get()) # type: ignore - self.outdir_entry = nb.Entry(output_frame, takefocus=False) + self.outdir_entry = ttk.Entry(output_frame, takefocus=False) self.outdir_entry.grid(columnspan=2, padx=self.PADX, pady=self.BOXY, sticky=tk.EW, row=row.get()) text = (_('Browse...')) # LANG: NOT-macOS Settings - files location selection button - self.outbutton = nb.Button( + self.outbutton = ttk.Button( output_frame, text=text, # Technically this is different from the label in Settings > Output, as *this* is used @@ -399,7 +399,7 @@ class PreferencesDialog(tk.Toplevel): logdir = default self.logdir.set(logdir) - self.logdir_entry = nb.Entry(config_frame, takefocus=False) + self.logdir_entry = ttk.Entry(config_frame, takefocus=False) # Location of the Journal files nb.Label( @@ -413,7 +413,7 @@ class PreferencesDialog(tk.Toplevel): text = (_('Browse...')) # LANG: NOT-macOS Setting - files location selection button with row as cur_row: - self.logbutton = nb.Button( + self.logbutton = ttk.Button( config_frame, text=text, # LANG: Settings > Configuration - Label for Journal files location @@ -423,7 +423,7 @@ class PreferencesDialog(tk.Toplevel): if config.default_journal_dir_path: # Appearance theme and language setting - nb.Button( + ttk.Button( config_frame, # LANG: Settings > Configuration - Label on 'reset journal files location to default' button text=_('Default'), @@ -465,7 +465,7 @@ class PreferencesDialog(tk.Toplevel): text=_('Hotkey') # LANG: Hotkey/Shortcut settings prompt on Windows ).grid(padx=self.PADX, pady=self.PADY, sticky=tk.W, row=cur_row) - self.hotkey_text = nb.Entry(config_frame, width=30, justify=tk.CENTER) + self.hotkey_text = ttk.Entry(config_frame, width=30, justify=tk.CENTER) self.hotkey_text.insert( 0, # No hotkey/shortcut currently defined @@ -623,7 +623,7 @@ class PreferencesDialog(tk.Toplevel): self.loglevel_dropdown.configure(width=15) self.loglevel_dropdown.grid(column=1, pady=self.BOXY, sticky=tk.W, row=cur_row) - nb.Button( + ttk.Button( config_frame, # LANG: Label on button used to open a filesystem folder text=_('Open Log Folder'), # Button that opens a folder in Explorer/Finder @@ -726,7 +726,7 @@ class PreferencesDialog(tk.Toplevel): self.theme_label_0.grid(padx=self.PADX, pady=self.PADY, sticky=tk.W, row=cur_row) # Main window - self.theme_button_0 = nb.ColoredButton( + self.theme_button_0 = tk.Button( appearance_frame, # LANG: Appearance - Example 'Normal' text text=_('Station'), @@ -739,7 +739,7 @@ class PreferencesDialog(tk.Toplevel): with row as cur_row: self.theme_label_1 = nb.Label(appearance_frame, text=self.theme_prompts[1]) self.theme_label_1.grid(padx=self.PADX, pady=self.PADY, sticky=tk.W, row=cur_row) - self.theme_button_1 = nb.ColoredButton( + self.theme_button_1 = tk.Button( appearance_frame, text=' Hutton Orbital ', # Do not translate background='grey4', @@ -870,7 +870,7 @@ class PreferencesDialog(tk.Toplevel): padx=self.PADX, pady=self.PADY, sticky=tk.W, row=row.get() ) - plugdirentry = nb.Entry(plugins_frame, justify=tk.LEFT) + plugdirentry = ttk.Entry(plugins_frame, justify=tk.LEFT) self.displaypath(plugdir, plugdirentry) plugdirentry.grid(columnspan=2, padx=self.PADX, pady=self.BOXY, sticky=tk.EW, row=row.get()) @@ -882,7 +882,7 @@ class PreferencesDialog(tk.Toplevel): text=_("Tip: You can disable a plugin by{CR}adding '{EXT}' to its folder name").format(EXT='.disabled') ).grid(columnspan=2, padx=self.PADX, pady=self.PADY, sticky=tk.EW, row=cur_row) - nb.Button( + ttk.Button( plugins_frame, # LANG: Label on button used to open a filesystem folder text=_('Open'), # Button that opens a folder in Explorer/Finder From ae74d949a892b919a275c2cda45e951b97c3082c Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 21:24:11 -0400 Subject: [PATCH 15/49] [Nit] Indentation, Yay! --- plugins/coriolis.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/coriolis.py b/plugins/coriolis.py index 20da16b1..a97eb6c6 100644 --- a/plugins/coriolis.py +++ b/plugins/coriolis.py @@ -107,12 +107,12 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> tk.Fr # LANG: Settings>Coriolis: Label for 'NOT alpha/beta game version' URL nb.Label(conf_frame, text=_('Normal URL')).grid(sticky=tk.W, row=cur_row, column=0, padx=PADX, pady=PADY) ttk.Entry(conf_frame, - textvariable=coriolis_config.normal_textvar).grid( + textvariable=coriolis_config.normal_textvar).grid( sticky=tk.EW, row=cur_row, column=1, padx=PADX, pady=BOXY ) # LANG: Generic 'Reset' button label ttk.Button(conf_frame, text=_("Reset"), - command=lambda: coriolis_config.normal_textvar.set(value=DEFAULT_NORMAL_URL)).grid( + command=lambda: coriolis_config.normal_textvar.set(value=DEFAULT_NORMAL_URL)).grid( sticky=tk.W, row=cur_row, column=2, padx=PADX, pady=0 ) cur_row += 1 @@ -124,7 +124,7 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> tk.Fr ) # LANG: Generic 'Reset' button label ttk.Button(conf_frame, text=_('Reset'), - command=lambda: coriolis_config.beta_textvar.set(value=DEFAULT_BETA_URL)).grid( + command=lambda: coriolis_config.beta_textvar.set(value=DEFAULT_BETA_URL)).grid( sticky=tk.W, row=cur_row, column=2, padx=PADX, pady=0 ) cur_row += 1 From cfb6f729ab5888238c552aa0bb0d568b69356fbb Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 21:27:22 -0400 Subject: [PATCH 16/49] [2186] Remove Unused Translations --- L10n/en.template | 24 ------------------------ config/__init__.py | 2 +- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/L10n/en.template b/L10n/en.template index f5acb377..7ba67a61 100644 --- a/L10n/en.template +++ b/L10n/en.template @@ -78,12 +78,6 @@ /* EDMarketConnector.py: 'Edit' menu title on OSX; EDMarketConnector.py: 'Edit' menu title; In files: EDMarketConnector.py:922; EDMarketConnector.py:940; EDMarketConnector.py:943; */ "Edit" = "Edit"; -/* EDMarketConnector.py: 'View' menu title on OSX; In files: EDMarketConnector.py:923; */ -"View" = "View"; - -/* EDMarketConnector.py: 'Window' menu title on OSX; In files: EDMarketConnector.py:924; */ -"Window" = "Window"; - /* EDMarketConnector.py: Help' menu title on OSX; EDMarketConnector.py: 'Help' menu title; In files: EDMarketConnector.py:925; EDMarketConnector.py:941; EDMarketConnector.py:944; */ "Help" = "Help"; @@ -351,9 +345,6 @@ /* inara.py: INARA API returned some kind of error (error message will be contained in {MSG}); In files: inara.py:1650; inara.py:1663; */ "Error: Inara {MSG}" = "Error: Inara {MSG}"; -/* prefs.py: File > Preferences menu entry for macOS; In files: prefs.py:237; */ -"Preferences" = "Preferences"; - /* prefs.py: Settings > Output - choosing what data to save to files; In files: prefs.py:335; */ "Please choose what data to save" = "Please choose what data to save"; @@ -372,9 +363,6 @@ /* prefs.py: Settings > Output - Label for "where files are located"; In files: prefs.py:379; prefs.py:398; */ "File location" = "File location"; -/* prefs.py: macOS Preferences - files location selection button; In files: prefs.py:387; prefs.py:437; */ -"Change..." = "Change..."; - /* prefs.py: NOT-macOS Settings - files location selection button; prefs.py: NOT-macOS Setting - files location selection button; In files: prefs.py:390; prefs.py:440; */ "Browse..." = "Browse..."; @@ -390,21 +378,9 @@ /* prefs.py: Configuration - Enable or disable the Fleet Carrier CAPI calls; In files: prefs.py:475; */ "Enable Fleetcarrier CAPI Queries" = "Enable Fleetcarrier CAPI Queries"; -/* prefs.py: Hotkey/Shortcut settings prompt on OSX; In files: prefs.py:490; */ -"Keyboard shortcut" = "Keyboard shortcut"; - /* prefs.py: Hotkey/Shortcut settings prompt on Windows; In files: prefs.py:492; */ "Hotkey" = "Hotkey"; -/* prefs.py: macOS Preferences > Configuration - restart the app message; In files: prefs.py:501; */ -"Re-start {APP} to use shortcuts" = "Re-start {APP} to use shortcuts"; - -/* prefs.py: macOS - Configuration - need to grant the app permission for keyboard shortcuts; In files: prefs.py:510; */ -"{APP} needs permission to use shortcuts" = "{APP} needs permission to use shortcuts"; - -/* prefs.py: Shortcut settings button on OSX; In files: prefs.py:515; */ -"Open System Preferences" = "Open System Preferences"; - /* prefs.py: Configuration - Act on hotkey only when ED is in foreground; In files: prefs.py:538; */ "Only when Elite: Dangerous is the active app" = "Only when Elite: Dangerous is the active app"; diff --git a/config/__init__.py b/config/__init__.py index 992710a0..c6c404b9 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -54,7 +54,7 @@ appcmdname = 'EDMC' # <https://semver.org/#semantic-versioning-specification-semver> # Major.Minor.Patch(-prerelease)(+buildmetadata) # NB: Do *not* import this, use the functions appversion() and appversion_nobuild() -_static_appversion = '5.10.3' +_static_appversion = '5.11.0-alpha0' _cached_version: semantic_version.Version | None = None copyright = '© 2015-2019 Jonathan Harris, 2020-2024 EDCD' From 016fb96e065b45bd803587b31edb9619809f7198 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 22:01:49 -0400 Subject: [PATCH 17/49] [2186] General Cleanup --- prefs.py | 4 ++-- td.py | 1 - ttkHyperlinkLabel.py | 1 - update.py | 9 +++------ 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/prefs.py b/prefs.py index ef43c5de..307e3c7a 100644 --- a/prefs.py +++ b/prefs.py @@ -364,7 +364,7 @@ class PreferencesDialog(tk.Toplevel): self.outdir_entry = ttk.Entry(output_frame, takefocus=False) self.outdir_entry.grid(columnspan=2, padx=self.PADX, pady=self.BOXY, sticky=tk.EW, row=row.get()) - text = (_('Browse...')) # LANG: NOT-macOS Settings - files location selection button + text = _('Browse...') # LANG: NOT-macOS Settings - files location selection button self.outbutton = ttk.Button( output_frame, @@ -410,7 +410,7 @@ class PreferencesDialog(tk.Toplevel): self.logdir_entry.grid(columnspan=4, padx=self.PADX, pady=self.BOXY, sticky=tk.EW, row=row.get()) - text = (_('Browse...')) # LANG: NOT-macOS Setting - files location selection button + text = _('Browse...') # LANG: NOT-macOS Setting - files location selection button with row as cur_row: self.logbutton = ttk.Button( diff --git a/td.py b/td.py index d2b5dbdd..484e8d29 100644 --- a/td.py +++ b/td.py @@ -1,7 +1,6 @@ """Export data for Trade Dangerous.""" import pathlib -import sys import time from collections import defaultdict from operator import itemgetter diff --git a/ttkHyperlinkLabel.py b/ttkHyperlinkLabel.py index de906510..9bb3b9bf 100644 --- a/ttkHyperlinkLabel.py +++ b/ttkHyperlinkLabel.py @@ -31,7 +31,6 @@ if TYPE_CHECKING: def _(x: str) -> str: return x -# FIXME: Split this into multi-file module to separate the platforms class HyperlinkLabel(tk.Label or ttk.Label): # type: ignore """Clickable label for HTTP links.""" diff --git a/update.py b/update.py index e0b8f97b..346aff63 100644 --- a/update.py +++ b/update.py @@ -7,10 +7,8 @@ See LICENSE file. """ from __future__ import annotations -import os import sys import threading -from os.path import dirname, join from traceback import print_exc from typing import TYPE_CHECKING from xml.etree import ElementTree @@ -163,10 +161,9 @@ class Updater: return None - else: - # For *these* purposes anything else is the same as 'windows', as - # non-win32 would be running from source. - sparkle_platform = 'windows' + # For *these* purposes anything else is the same as 'windows', as + # non-win32 would be running from source. + sparkle_platform = 'windows' for item in feed.findall('channel/item'): # xml is a pain with types, hence these ignores From 1800f8f0b18cb8e13a7cc032d4eac61f7f67cbb1 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 22:17:21 -0400 Subject: [PATCH 18/49] [2186] Remove Some Comments --- config/__init__.py | 1 - dashboard.py | 4 ++-- monitor.py | 2 +- prefs.py | 2 +- theme.py | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/config/__init__.py b/config/__init__.py index c6c404b9..99e8fdc6 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -7,7 +7,6 @@ See LICENSE file. Windows uses the Registry to store values in a flat manner. Linux uses a file, but for commonality it's still a flat data structure. -macOS uses a 'defaults' object. """ from __future__ import annotations diff --git a/dashboard.py b/dashboard.py index 3948c92b..4776319c 100644 --- a/dashboard.py +++ b/dashboard.py @@ -26,7 +26,7 @@ if sys.platform == 'win32': else: # Linux's inotify doesn't work over CIFS or NFS, so poll class FileSystemEventHandler: # type: ignore - """Dummy class to represent a file system event handler on platforms other than macOS and Windows.""" + """Dummy class to represent a file system event handler on platforms other than Windows.""" class Dashboard(FileSystemEventHandler): @@ -160,7 +160,7 @@ class Dashboard(FileSystemEventHandler): def on_modified(self, event) -> None: """ - Watchdog callback - DirModifiedEvent on macOS, FileModifiedEvent on Windows. + Watchdog callback - FileModifiedEvent on Windows. :param event: Watchdog event. """ diff --git a/monitor.py b/monitor.py index d549e533..5acbcbc4 100644 --- a/monitor.py +++ b/monitor.py @@ -439,7 +439,7 @@ class EDLogs(FileSystemEventHandler): new_journal_file = None if logfile: - loghandle.seek(0, SEEK_END) # required to make macOS notice log change over SMB + loghandle.seek(0, SEEK_END) # required to make macOS notice log change over SMB. # TODO: Do we need this? loghandle.seek(log_pos, SEEK_SET) # reset EOF flag # TODO: log_pos reported as possibly unbound for line in loghandle: # Paranoia check to see if we're shutting down diff --git a/prefs.py b/prefs.py index 307e3c7a..5b045b1a 100644 --- a/prefs.py +++ b/prefs.py @@ -285,7 +285,7 @@ class PreferencesDialog(tk.Toplevel): # wait for window to appear on screen before calling grab_set self.parent.update_idletasks() - self.parent.wm_attributes('-topmost', 0) # needed for dialog to appear ontop of parent on OSX & Linux + self.parent.wm_attributes('-topmost', 0) # needed for dialog to appear ontop of parent on Linux self.wait_visibility() self.grab_set() diff --git a/theme.py b/theme.py index b128bc91..bbe62ef5 100644 --- a/theme.py +++ b/theme.py @@ -150,7 +150,7 @@ class _Theme: # the widget has explicit fg or bg attributes. assert isinstance(widget, (tk.BitmapImage, tk.Widget)), widget if not self.defaults: - # Can't initialise this til window is created # Windows, MacOS + # Can't initialise this til window is created # Windows self.defaults = { 'fg': tk.Label()['foreground'], # SystemButtonText, systemButtonText 'bg': tk.Label()['background'], # SystemButtonFace, White From 56a4ae25e0e598666bd0c8c6f8fa72daacdd90a2 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 27 Mar 2024 22:21:26 -0400 Subject: [PATCH 19/49] [Nit] Clarify Comments --- monitor.py | 2 +- myNotebook.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/monitor.py b/monitor.py index 5acbcbc4..ba634c51 100644 --- a/monitor.py +++ b/monitor.py @@ -439,7 +439,7 @@ class EDLogs(FileSystemEventHandler): new_journal_file = None if logfile: - loghandle.seek(0, SEEK_END) # required to make macOS notice log change over SMB. # TODO: Do we need this? + loghandle.seek(0, SEEK_END) # required for macOS to notice log change over SMB. TODO: Do we need this? loghandle.seek(log_pos, SEEK_SET) # reset EOF flag # TODO: log_pos reported as possibly unbound for line in loghandle: # Paranoia check to see if we're shutting down diff --git a/myNotebook.py b/myNotebook.py index 528664ba..64624550 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -57,7 +57,7 @@ class Label(tk.Label): super().__init__(master, **kw) -class Entry(ttk.Entry): # type: ignore +class Entry(ttk.Entry): """Custom t(t)k.Entry class to fix some display issues.""" # DEPRECATED: Migrate to ttk.Entry. Will remove in 5.12 or later. From b5a4ee6ed2f60c68cec307e9bcd946d6440fc0b7 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Thu, 28 Mar 2024 10:49:01 -0400 Subject: [PATCH 20/49] [Nit] Cleanup some Flake8 --- config/__init__.py | 1 - plugins/eddn.py | 1 - protocol.py | 36 ++++++++++++++++++------------------ tests/config/_old_config.py | 6 +++--- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/config/__init__.py b/config/__init__.py index 99e8fdc6..d85956a7 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -467,7 +467,6 @@ def get_config(*args, **kwargs) -> AbstractConfig: :param kwargs: Args to be passed through to implementation. :return: Instance of the implementation. """ - if sys.platform == "win32": # pragma: sys-platform-win32 from .windows import WinConfig return WinConfig(*args, **kwargs) diff --git a/plugins/eddn.py b/plugins/eddn.py index b7133725..6345f579 100644 --- a/plugins/eddn.py +++ b/plugins/eddn.py @@ -27,7 +27,6 @@ import os import pathlib import re import sqlite3 -import sys import tkinter as tk from platform import system from textwrap import dedent diff --git a/protocol.py b/protocol.py index 0f1c157f..4c9e41ca 100644 --- a/protocol.py +++ b/protocol.py @@ -26,6 +26,7 @@ is_wine = False if sys.platform == 'win32': from ctypes import windll # type: ignore + try: if windll.ntdll.wine_get_version: is_wine = True @@ -58,13 +59,13 @@ class GenericProtocolHandler: self.master.event_generate('<<CompanionAuthEvent>>', when="tail") -if (config.auth_force_edmc_protocol - or ( - sys.platform == 'win32' - and getattr(sys, 'frozen', False) - and not is_wine - and not config.auth_force_localserver - )): +if (config.auth_force_edmc_protocol # noqa: C901 + or ( + sys.platform == 'win32' + and getattr(sys, 'frozen', False) + and not is_wine + and not config.auth_force_localserver + )): # This could be false if you use auth_force_edmc_protocol, but then you get to keep the pieces assert sys.platform == 'win32' # spell-checker: words HBRUSH HICON WPARAM wstring WNDCLASS HMENU HGLOBAL @@ -186,11 +187,11 @@ if (config.auth_force_edmc_protocol # which we can read out as shown below, and then compare. target_is_valid = lparam_low == 0 or ( - GlobalGetAtomNameW(lparam_low, service, 256) and service.value == appname + GlobalGetAtomNameW(lparam_low, service, 256) and service.value == appname ) topic_is_valid = lparam_high == 0 or ( - GlobalGetAtomNameW(lparam_high, topic, 256) and topic.value.lower() == 'system' + GlobalGetAtomNameW(lparam_high, topic, 256) and topic.value.lower() == 'system' ) if target_is_valid and topic_is_valid: @@ -251,15 +252,15 @@ if (config.auth_force_edmc_protocol # https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createwindowexw hwnd = CreateWindowExW( - 0, # dwExStyle + 0, # dwExStyle wndclass.lpszClassName, # lpClassName - "DDE Server", # lpWindowName - 0, # dwStyle + "DDE Server", # lpWindowName + 0, # dwStyle CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, # X, Y, nWidth, nHeight self.master.winfo_id(), # hWndParent # Don't use HWND_MESSAGE since the window won't get DDE broadcasts - None, # hMenu - wndclass.hInstance, # hInstance - None # lpParam + None, # hMenu + wndclass.hInstance, # hInstance + None # lpParam ) msg = MSG() @@ -421,10 +422,9 @@ def get_handler_impl() -> Type[GenericProtocolHandler]: :return: An instantiatable GenericProtocolHandler """ - if ( - (sys.platform == 'win32' and config.auth_force_edmc_protocol) - or (getattr(sys, 'frozen', False) and not is_wine and not config.auth_force_localserver) + (sys.platform == 'win32' and config.auth_force_edmc_protocol) + or (getattr(sys, 'frozen', False) and not is_wine and not config.auth_force_localserver) ): return WindowsProtocolHandler diff --git a/tests/config/_old_config.py b/tests/config/_old_config.py index 35ae19e3..2b5244b6 100644 --- a/tests/config/_old_config.py +++ b/tests/config/_old_config.py @@ -5,8 +5,8 @@ import numbers import sys import warnings from configparser import NoOptionError -from os import getenv, makedirs, mkdir, pardir -from os.path import dirname, expanduser, isdir, join, normpath +from os import getenv, makedirs, mkdir +from os.path import dirname, expanduser, isdir, join from typing import TYPE_CHECKING from config import applongname, appname, update_interval from EDMCLogging import get_main_logger @@ -109,7 +109,7 @@ class OldConfig: OUT_EDDN_DELAY = 4096 OUT_STATION_ANY = OUT_EDDN_SEND_STATION_DATA | OUT_MKT_TD | OUT_MKT_CSV - if sys.platform == 'win32': + if sys.platform == 'win32': # noqa: C901 def __init__(self): self.app_dir = join(known_folder_path(FOLDERID_LocalAppData), appname) # type: ignore From 572f724a71a851b717f1a9938fd21e4fd24682c2 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Thu, 28 Mar 2024 12:59:22 -0400 Subject: [PATCH 21/49] [1471] Add PIL to Improve Clipboard --- L10n/en.template | 5 ++++- build.py | 1 - myNotebook.py | 22 ++++++++++++++++++---- requirements.txt | 1 + 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/L10n/en.template b/L10n/en.template index f5acb377..bf8d022e 100644 --- a/L10n/en.template +++ b/L10n/en.template @@ -802,4 +802,7 @@ "Ships" = "Ships"; /* update.py: Update Available Text; In files: update.py:229; */ -"{NEWVER} is available" = "{NEWVER} is available"; \ No newline at end of file +"{NEWVER} is available" = "{NEWVER} is available"; + +/* myNotebook.py: Can't Paste Images or Files in Text; */ +"Cannot paste non-text content." = "Cannot paste non-text content."; diff --git a/build.py b/build.py index 1bc96765..2d4ef790 100644 --- a/build.py +++ b/build.py @@ -133,7 +133,6 @@ def build() -> None: "distutils", "_markerlib", "optparse", - "PIL", "simplejson", "unittest", "doctest", diff --git a/myNotebook.py b/myNotebook.py index 63bb7dc8..398b2136 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -14,7 +14,12 @@ from __future__ import annotations import sys import tkinter as tk -from tkinter import ttk +from tkinter import ttk, messagebox +from typing import TYPE_CHECKING +from PIL import ImageGrab + +if TYPE_CHECKING: + def _(x: str) -> str: return x # Can't do this with styles on OSX - http://www.tkdocs.com/tutorial/styles.html#whydifficult if sys.platform == 'darwin': @@ -126,13 +131,22 @@ class EntryMenu(ttk.Entry): def paste(self) -> None: """Paste the selected Entry text.""" - if self.selection_present(): - self.delete(tk.SEL_FIRST, tk.SEL_LAST) try: + # Attempt to grab an image from the clipboard (apprently also works for files) + img = ImageGrab.grabclipboard() + if img: + # Hijack existing translation, yes it doesn't exactly match here. + # LANG: Generic error prefix - following text is from Frontier auth service; + messagebox.showwarning(_('Error'), + _('Cannot paste non-text content.')) # LANG: Can't Paste Images or Files in Text + return text = self.clipboard_get() + if self.selection_present() and text: + self.delete(tk.SEL_FIRST, tk.SEL_LAST) self.insert(tk.INSERT, text) except tk.TclError: - pass # No text in clipboard or clipboard is not text + # No text in clipboard or clipboard is not text + pass class Entry(sys.platform == 'darwin' and tk.Entry or EntryMenu or ttk.Entry): # type: ignore diff --git a/requirements.txt b/requirements.txt index 398041a1..e0e6138f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ certifi==2023.11.17 requests==2.31.0 +pillow==10.2.0 # requests depends on this now ? charset-normalizer==2.1.1 From 0d9607b4f89ee2d351542fb2d69b156e4bce9b3c Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Sat, 30 Mar 2024 16:02:54 -0400 Subject: [PATCH 22/49] [Minor] Add Missing Future Annotation --- config/linux.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/linux.py b/config/linux.py index 73100800..51a40626 100644 --- a/config/linux.py +++ b/config/linux.py @@ -5,6 +5,8 @@ Copyright (c) EDCD, All Rights Reserved Licensed under the GNU General Public License. See LICENSE file. """ +from __future__ import annotations + import os import pathlib import sys From ecf0ceb612f474e1f54bf2c28fa603708db960d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 17:08:13 +0000 Subject: [PATCH 23/49] build(deps-dev): bump mypy from 1.8.0 to 1.9.0 Bumps [mypy](https://github.com/python/mypy) from 1.8.0 to 1.9.0. - [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md) - [Commits](https://github.com/python/mypy/compare/v1.8.0...1.9.0) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 73ab5465..dd59b4f5 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -18,7 +18,7 @@ flake8-noqa==1.4.0 flake8-polyfill==1.0.2 flake8-use-fstring==1.4 -mypy==1.8.0 +mypy==1.9.0 pep8-naming==0.13.3 safety==2.3.5 types-requests==2.31.0.20240125 From 2ea942aec06e2a420ab801751e61db2a4d21dc65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 17:08:16 +0000 Subject: [PATCH 24/49] build(deps-dev): bump autopep8 from 2.0.4 to 2.1.0 Bumps [autopep8](https://github.com/hhatto/autopep8) from 2.0.4 to 2.1.0. - [Release notes](https://github.com/hhatto/autopep8/releases) - [Commits](https://github.com/hhatto/autopep8/compare/v2.0.4...v2.1.0) --- updated-dependencies: - dependency-name: autopep8 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 73ab5465..83e68822 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -25,7 +25,7 @@ types-requests==2.31.0.20240125 types-pkg-resources==0.1.3 # Code formatting tools -autopep8==2.0.4 +autopep8==2.1.0 # Git pre-commit checking pre-commit==3.6.2 From 854dd4072e221d066add0a136a3435e30d0dc0ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 17:08:19 +0000 Subject: [PATCH 25/49] build(deps): bump certifi from 2023.11.17 to 2024.2.2 Bumps [certifi](https://github.com/certifi/python-certifi) from 2023.11.17 to 2024.2.2. - [Commits](https://github.com/certifi/python-certifi/compare/2023.11.17...2024.02.02) --- updated-dependencies: - dependency-name: certifi dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 398041a1..75b7fc01 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -certifi==2023.11.17 +certifi==2024.2.2 requests==2.31.0 # requests depends on this now ? charset-normalizer==2.1.1 From 25d52eacf6dcf603bbdb36e9443023756342c4fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 17:29:12 +0000 Subject: [PATCH 26/49] build(deps): bump softprops/action-gh-release from 1 to 2 Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/windows-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml index 50962bbd..7bc60136 100644 --- a/.github/workflows/windows-build.yml +++ b/.github/workflows/windows-build.yml @@ -155,7 +155,7 @@ jobs: run: sha256sum EDMarketConnector_Installer_*.exe EDMarketConnector-release-*.{zip,tar.gz} > ./hashes.sum - name: Create Draft Release - uses: "softprops/action-gh-release@v1" + uses: "softprops/action-gh-release@v2" with: token: "${{secrets.GITHUB_TOKEN}}" draft: true From d8d8540ceeea7b2c9beb57843df4ce3be136e7e2 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Fri, 5 Apr 2024 17:16:25 -0400 Subject: [PATCH 27/49] [2186] Resolve Some Merge Issues From EntryMenu --- myNotebook.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/myNotebook.py b/myNotebook.py index 64624550..7379aa5a 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -57,12 +57,69 @@ class Label(tk.Label): super().__init__(master, **kw) -class Entry(ttk.Entry): +class EntryMenu(ttk.Entry): + """Extended entry widget that includes a context menu with Copy, Cut-and-Paste commands.""" + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.menu = tk.Menu(self, tearoff=False) + self.menu.add_command(label="Copy", command=self.copy) + self.menu.add_command(label="Cut", command=self.cut) + self.menu.add_separator() + self.menu.add_command(label="Paste", command=self.paste) + self.menu.add_separator() + self.menu.add_command(label="Select All", command=self.select_all) + + self.bind("<Button-3>", self.display_popup) + + def display_popup(self, event: tk.Event) -> None: + """Display the menu popup.""" + self.menu.post(event.x_root, event.y_root) + + def select_all(self) -> None: + """Select all the text within the Entry.""" + self.selection_range(0, tk.END) + self.focus_set() + + def copy(self) -> None: + """Copy the selected Entry text.""" + if self.selection_present(): + self.clipboard_clear() + self.clipboard_append(self.selection_get()) + + def cut(self) -> None: + """Cut the selected Entry text.""" + if self.selection_present(): + self.copy() + self.delete(tk.SEL_FIRST, tk.SEL_LAST) + + def paste(self) -> None: + """Paste the selected Entry text.""" + try: + # Attempt to grab an image from the clipboard (apprently also works for files) + img = ImageGrab.grabclipboard() + if img: + # Hijack existing translation, yes it doesn't exactly match here. + # LANG: Generic error prefix - following text is from Frontier auth service; + messagebox.showwarning(_('Error'), + _('Cannot paste non-text content.')) # LANG: Can't Paste Images or Files in Text + return + text = self.clipboard_get() + if self.selection_present() and text: + self.delete(tk.SEL_FIRST, tk.SEL_LAST) + self.insert(tk.INSERT, text) + except tk.TclError: + # No text in clipboard or clipboard is not text + pass + + +class Entry(ttk.Entry or EntryMenu): """Custom t(t)k.Entry class to fix some display issues.""" - # DEPRECATED: Migrate to ttk.Entry. Will remove in 5.12 or later. + # DEPRECATED: Migrate to ttk.Entry or EntryMenu. Will remove in 5.12 or later. def __init__(self, master: ttk.Frame | None = None, **kw): - super().__init__(master, **kw) + EntryMenu.__init__(self, master, **kw) class Button(tk.Button or ttk.Button): # type: ignore From d00226f9e3f8dbbf211851433bb501a984334658 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Fri, 5 Apr 2024 17:20:05 -0400 Subject: [PATCH 28/49] [2186] Additional Documentations --- .flake8 | 1 - .mypy.ini | 1 - Contributing.md | 2 +- pyproject.toml | 3 --- requirements.txt | 3 --- 5 files changed, 1 insertion(+), 9 deletions(-) diff --git a/.flake8 b/.flake8 index bdb25ca4..179e00ec 100644 --- a/.flake8 +++ b/.flake8 @@ -7,7 +7,6 @@ exclude = FDevIDs/ venv/ .venv/ - hotkey/darwin.py # FIXME: Check under macOS VM at some point # Show exactly where in a line the error happened #show-source = True diff --git a/.mypy.ini b/.mypy.ini index 75f4ccdb..9ac2f227 100644 --- a/.mypy.ini +++ b/.mypy.ini @@ -6,5 +6,4 @@ scripts_are_modules = True ; `<var> = <value>` ; i.e. no typing info. check_untyped_defs = True -; platform = darwin explicit_package_bases = True diff --git a/Contributing.md b/Contributing.md index 5f7bc158..f021f1a3 100644 --- a/Contributing.md +++ b/Contributing.md @@ -679,7 +679,7 @@ the following does not work: ```py from sys import platform -if platform == 'darwin': +if platform == 'win32': ... ``` diff --git a/pyproject.toml b/pyproject.toml index e32ad617..b98fbf4f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,3 @@ sys-platform-not-darwin = "sys_platform == 'darwin'" sys-platform-linux = "sys_platform != 'linux'" sys-platform-not-linux = "sys_platform == 'linux'" sys-platform-not-known = "sys_platform in ('darwin', 'linux', 'win32')" - -[tool.pyright] -# pythonPlatform = 'Darwin' diff --git a/requirements.txt b/requirements.txt index e9d4f58d..c9239fdc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,3 @@ infi.systray==0.1.12; sys_platform == 'win32' # argh==0.26.2 watchdog dep # pyyaml==5.3.1 watchdog dep semantic-version==2.10.0 - -# Base requirement for MacOS -pyobjc; sys_platform == 'darwin' From fbdc44139077db712fa39b6d4ae60fc3013e1fc2 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Fri, 5 Apr 2024 17:28:08 -0400 Subject: [PATCH 29/49] [Minor] Return Visual Padding Just makes it nicer to read. --- protocol.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/protocol.py b/protocol.py index 4c9e41ca..b052ebae 100644 --- a/protocol.py +++ b/protocol.py @@ -254,12 +254,12 @@ if (config.auth_force_edmc_protocol # noqa: C901 hwnd = CreateWindowExW( 0, # dwExStyle wndclass.lpszClassName, # lpClassName - "DDE Server", # lpWindowName - 0, # dwStyle + "DDE Server", # lpWindowName + 0, # dwStyle CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, # X, Y, nWidth, nHeight self.master.winfo_id(), # hWndParent # Don't use HWND_MESSAGE since the window won't get DDE broadcasts - None, # hMenu - wndclass.hInstance, # hInstance + None, # hMenu + wndclass.hInstance, # hInstance None # lpParam ) From 3a8227a8741ef2856472d300490ab2e30c2c7d57 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Fri, 5 Apr 2024 17:33:22 -0400 Subject: [PATCH 30/49] [2186] Correct Logic --- EDMarketConnector.py | 8 +++----- prefs.py | 6 +++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/EDMarketConnector.py b/EDMarketConnector.py index 967488e0..3ab97eb5 100755 --- a/EDMarketConnector.py +++ b/EDMarketConnector.py @@ -1750,8 +1750,7 @@ class AppWindow: # position over parent # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 - if parent.winfo_rooty() > 0: - self.geometry(f'+{parent.winfo_rootx():d}+{parent.winfo_rooty():d}') + self.geometry(f'+{parent.winfo_rootx():d}+{parent.winfo_rooty():d}') # remove decoration if sys.platform == 'win32': @@ -1870,9 +1869,8 @@ class AppWindow: config.set_shutdown() # Signal we're in shutdown now. # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 - if self.w.winfo_rooty() > 0: - x, y = self.w.geometry().split('+')[1:3] # e.g. '212x170+2881+1267' - config.set('geometry', f'+{x}+{y}') + x, y = self.w.geometry().split('+')[1:3] # e.g. '212x170+2881+1267' + config.set('geometry', f'+{x}+{y}') # Let the user know we're shutting down. # LANG: The application is shutting down diff --git a/prefs.py b/prefs.py index 5b045b1a..9e0459b6 100644 --- a/prefs.py +++ b/prefs.py @@ -230,9 +230,9 @@ class PreferencesDialog(tk.Toplevel): self.transient(parent) # position over parent - if parent.winfo_rooty() > 0: # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 - # TODO this is fixed supposedly. - self.geometry(f'+{parent.winfo_rootx()}+{parent.winfo_rooty()}') + # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 + # TODO this is fixed supposedly. + self.geometry(f'+{parent.winfo_rootx()}+{parent.winfo_rooty()}') # remove decoration if sys.platform == 'win32': From e0ef9b52c3cdc5aedc9982c736a7169bd3a5d2f8 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Fri, 5 Apr 2024 17:45:07 -0400 Subject: [PATCH 31/49] [2186] Additional Tweaks --- myNotebook.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/myNotebook.py b/myNotebook.py index 44488b8a..e8f8779b 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -30,15 +30,16 @@ class Notebook(ttk.Notebook): super().__init__(master, **kw) style = ttk.Style() - style.configure('nb.TFrame', background=PAGEBG) - style.configure('nb.TButton', background=PAGEBG) - style.configure('nb.TCheckbutton', foreground=PAGEFG, background=PAGEBG) - style.configure('nb.TMenubutton', foreground=PAGEFG, background=PAGEBG) - style.configure('nb.TRadiobutton', foreground=PAGEFG, background=PAGEBG) + if sys.platform == 'win32': + style.configure('nb.TFrame', background=PAGEBG) + style.configure('nb.TButton', background=PAGEBG) + style.configure('nb.TCheckbutton', foreground=PAGEFG, background=PAGEBG) + style.configure('nb.TMenubutton', foreground=PAGEFG, background=PAGEBG) + style.configure('nb.TRadiobutton', foreground=PAGEFG, background=PAGEBG) self.grid(padx=10, pady=10, sticky=tk.NSEW) -class Frame(tk.Frame or ttk.Frame): # type: ignore +class Frame(ttk.Frame): """Custom t(t)k.Frame class to fix some display issues.""" def __init__(self, master: ttk.Notebook | None = None, **kw): @@ -127,7 +128,7 @@ class Entry(ttk.Entry or EntryMenu): EntryMenu.__init__(self, master, **kw) -class Button(tk.Button or ttk.Button): # type: ignore +class Button(ttk.Button): # type: ignore """Custom t(t)k.Button class to fix some display issues.""" # DEPRECATED: Migrate to ttk.Button. Will remove in 5.12 or later. @@ -138,7 +139,7 @@ class Button(tk.Button or ttk.Button): # type: ignore ttk.Button.__init__(self, master, **kw) -class ColoredButton(tk.Label or tk.Button): # type: ignore +class ColoredButton(tk.Button): # type: ignore """Custom t(t)k.ColoredButton class to fix some display issues.""" # DEPRECATED: Migrate to tk.Button. Will remove in 5.12 or later. @@ -166,11 +167,14 @@ class OptionMenu(ttk.OptionMenu): """Custom ttk.OptionMenu class to fix some display issues.""" def __init__(self, master, variable, default=None, *values, **kw): - style = 'nb.TMenubutton' if sys.platform == 'win32' else ttk.Style().lookup('TMenu', 'background') - menu_background = PAGEBG if sys.platform == 'win32' else ttk.Style().lookup('TMenu', 'background') + if sys.platform == 'win32': + # OptionMenu derives from Menubutton at the Python level, so uses Menubutton's style + ttk.OptionMenu.__init__(self, master, variable, default, *values, style='nb.TMenubutton', **kw) + self['menu'].configure(background=PAGEBG) + else: + ttk.OptionMenu.__init__(self, master, variable, default, *values, **kw) + self['menu'].configure(background=ttk.Style().lookup('TMenu', 'background')) - super().__init__(master, variable, default, *values, style=style, **kw) - self['menu'].configure(background=menu_background) - - for i in range(self['menu'].index('end') + 1): + # Workaround for https://bugs.python.org/issue25684 + for i in range(0, self['menu'].index('end') + 1): self['menu'].entryconfig(i, variable=variable) From 3c6ea3c9328a95e2a82fa276a2d1e3865c235f36 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Fri, 5 Apr 2024 17:50:30 -0400 Subject: [PATCH 32/49] [Minor] Comment Clarify --- update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update.py b/update.py index 346aff63..991558d6 100644 --- a/update.py +++ b/update.py @@ -161,7 +161,7 @@ class Updater: return None - # For *these* purposes anything else is the same as 'windows', as + # For *these* purposes all systems are the same as 'windows', as # non-win32 would be running from source. sparkle_platform = 'windows' From c14bd826d08daee4509cf2bf2b184245d7f54695 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Sat, 6 Apr 2024 16:52:45 -0400 Subject: [PATCH 33/49] [Minor] Additional Visual Padding Fixes --- protocol.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol.py b/protocol.py index b052ebae..1fb88595 100644 --- a/protocol.py +++ b/protocol.py @@ -252,7 +252,7 @@ if (config.auth_force_edmc_protocol # noqa: C901 # https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createwindowexw hwnd = CreateWindowExW( - 0, # dwExStyle + 0, # dwExStyle wndclass.lpszClassName, # lpClassName "DDE Server", # lpWindowName 0, # dwStyle @@ -260,7 +260,7 @@ if (config.auth_force_edmc_protocol # noqa: C901 self.master.winfo_id(), # hWndParent # Don't use HWND_MESSAGE since the window won't get DDE broadcasts None, # hMenu wndclass.hInstance, # hInstance - None # lpParam + None # lpParam ) msg = MSG() From d9c7a791553f12489ed47f74f6275b533ca7ca22 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Sat, 6 Apr 2024 16:59:49 -0400 Subject: [PATCH 34/49] [Minor] Update Type Hintings No Content Changes, Shuts Up MyPy --- docs/examples/click_counter/load.py | 4 ++-- myNotebook.py | 2 +- plug.py | 2 +- plugins/coriolis.py | 2 +- plugins/eddn.py | 4 ++-- plugins/edsm.py | 2 +- plugins/inara.py | 2 +- prefs.py | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/examples/click_counter/load.py b/docs/examples/click_counter/load.py index f7f23837..a3b8cac6 100644 --- a/docs/examples/click_counter/load.py +++ b/docs/examples/click_counter/load.py @@ -49,7 +49,7 @@ class ClickCounter: """ self.on_preferences_closed("", False) # Save our prefs - def setup_preferences(self, parent: nb.Notebook, cmdr: str, is_beta: bool) -> tk.Frame | None: + def setup_preferences(self, parent: nb.Notebook, cmdr: str, is_beta: bool) -> nb.Frame | None: """ setup_preferences is called by plugin_prefs below. @@ -128,7 +128,7 @@ def plugin_stop() -> None: return cc.on_unload() -def plugin_prefs(parent: nb.Notebook, cmdr: str, is_beta: bool) -> tk.Frame | None: +def plugin_prefs(parent: nb.Notebook, cmdr: str, is_beta: bool) -> nb.Frame | None: """ Handle preferences tab for the plugin. diff --git a/myNotebook.py b/myNotebook.py index e8f8779b..0eeb96a4 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -120,7 +120,7 @@ class EntryMenu(ttk.Entry): pass -class Entry(ttk.Entry or EntryMenu): +class Entry(ttk.Entry or EntryMenu): # type: ignore """Custom t(t)k.Entry class to fix some display issues.""" # DEPRECATED: Migrate to ttk.Entry or EntryMenu. Will remove in 5.12 or later. diff --git a/plug.py b/plug.py index 15e7cfaa..dad08bc6 100644 --- a/plug.py +++ b/plug.py @@ -126,7 +126,7 @@ class Plugin: return None - def get_prefs(self, parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> tk.Frame | None: + def get_prefs(self, parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> nb.Frame | None: """ If the plugin provides a prefs frame, create and return it. diff --git a/plugins/coriolis.py b/plugins/coriolis.py index a97eb6c6..cc7e965a 100644 --- a/plugins/coriolis.py +++ b/plugins/coriolis.py @@ -84,7 +84,7 @@ def plugin_start3(path: str) -> str: return 'Coriolis' -def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> tk.Frame: +def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> nb.Frame: """Set up plugin preferences.""" PADX = 10 # noqa: N806 PADY = 1 # noqa: N806 diff --git a/plugins/eddn.py b/plugins/eddn.py index c5a978db..9504d1ab 100644 --- a/plugins/eddn.py +++ b/plugins/eddn.py @@ -1898,7 +1898,7 @@ class EDDN: :param cmdr: the commander under which this upload is made :param is_beta: whether or not we are in beta mode :param entry: the journal entry to send - + ___ Example: { "timestamp":"2022-06-10T10:09:41Z", @@ -1932,7 +1932,7 @@ class EDDN: :param cmdr: the commander under which this upload is made :param is_beta: whether or not we are in beta mode :param entry: the journal entry to send - + ___ Example: { "timestamp":"2023-10-01T14:56:34Z", diff --git a/plugins/edsm.py b/plugins/edsm.py index 146dd5ab..55aae7b8 100644 --- a/plugins/edsm.py +++ b/plugins/edsm.py @@ -279,7 +279,7 @@ def toggle_password_visibility(): this.apikey.config(show="*") # type: ignore -def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> tk.Frame: +def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> nb.Frame: """ Plugin preferences setup hook. diff --git a/plugins/inara.py b/plugins/inara.py index d96e05ef..29bfaaf2 100644 --- a/plugins/inara.py +++ b/plugins/inara.py @@ -244,7 +244,7 @@ def toggle_password_visibility(): this.apikey.config(show="*") -def plugin_prefs(parent: ttk.Notebook, cmdr: str, is_beta: bool) -> tk.Frame: +def plugin_prefs(parent: ttk.Notebook, cmdr: str, is_beta: bool) -> nb.Frame: """Plugin Preferences UI hook.""" PADX = 10 # noqa: N806 BUTTONX = 12 # noqa: N806 # indent Checkbuttons and Radiobuttons diff --git a/prefs.py b/prefs.py index 9e0459b6..5e0f946b 100644 --- a/prefs.py +++ b/prefs.py @@ -376,7 +376,7 @@ class PreferencesDialog(tk.Toplevel): ) self.outbutton.grid(column=1, padx=self.PADX, pady=self.PADY, sticky=tk.EW, row=row.get()) - nb.Frame(output_frame).grid(row=row.get()) # bottom spacer # TODO: does nothing? + nb.Frame(output_frame).grid(row=row.get()) # type: ignore # bottom spacer # TODO: does nothing? # LANG: Label for 'Output' Settings/Preferences tab root_notebook.add(output_frame, text=_('Output')) # Tab heading in settings From 4cbc86e650d04f696b58332dd27f1b502f312437 Mon Sep 17 00:00:00 2001 From: github-actions <github-actions@github.com> Date: Thu, 11 Apr 2024 12:25:11 +0000 Subject: [PATCH 35/49] updating submodules --- FDevIDs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FDevIDs b/FDevIDs index 7205c793..7cffab3d 160000 --- a/FDevIDs +++ b/FDevIDs @@ -1 +1 @@ -Subproject commit 7205c79331f42c1a28b757b27467f79ff106716b +Subproject commit 7cffab3d913b788f981923687203399c22cf358f From dd5e3812a759c1d3186df277e249d0a9e6216e76 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Sat, 13 Apr 2024 14:44:44 -0400 Subject: [PATCH 36/49] [2186] Refine macOS to preserve ContextMenu --- docs/examples/click_counter/load.py | 3 +-- myNotebook.py | 23 +++++++++++------------ plugins/coriolis.py | 15 +++++++-------- plugins/edsm.py | 8 ++++---- plugins/inara.py | 4 ++-- prefs.py | 2 -- requirements.txt | 4 ++-- 7 files changed, 27 insertions(+), 32 deletions(-) diff --git a/docs/examples/click_counter/load.py b/docs/examples/click_counter/load.py index a3b8cac6..3620e159 100644 --- a/docs/examples/click_counter/load.py +++ b/docs/examples/click_counter/load.py @@ -7,7 +7,6 @@ from __future__ import annotations import logging import tkinter as tk -from tkinter import ttk import myNotebook as nb # noqa: N813 from config import appname, config @@ -65,7 +64,7 @@ class ClickCounter: # setup our config in a "Click Count: number" nb.Label(frame, text='Click Count').grid(row=current_row) - ttk.Entry(frame, textvariable=self.click_count).grid(row=current_row, column=1) + nb.EntryMenu(frame, textvariable=self.click_count).grid(row=current_row, column=1) current_row += 1 # Always increment our row counter, makes for far easier tkinter design. return frame diff --git a/myNotebook.py b/myNotebook.py index 0eeb96a4..2442acbe 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -40,7 +40,7 @@ class Notebook(ttk.Notebook): class Frame(ttk.Frame): - """Custom t(t)k.Frame class to fix some display issues.""" + """Custom ttk.Frame class to fix some display issues.""" def __init__(self, master: ttk.Notebook | None = None, **kw): if sys.platform == 'win32': @@ -120,18 +120,17 @@ class EntryMenu(ttk.Entry): pass -class Entry(ttk.Entry or EntryMenu): # type: ignore - """Custom t(t)k.Entry class to fix some display issues.""" +class Entry(EntryMenu or ttk.Entry): # type: ignore + """Custom ttk.Entry class to fix some display issues.""" - # DEPRECATED: Migrate to ttk.Entry or EntryMenu. Will remove in 5.12 or later. + # DEPRECATED: Migrate to EntryMenu. Will remove in 5.12 or later. def __init__(self, master: ttk.Frame | None = None, **kw): EntryMenu.__init__(self, master, **kw) -class Button(ttk.Button): # type: ignore - """Custom t(t)k.Button class to fix some display issues.""" +class Button(ttk.Button): + """Custom ttk.Button class to fix some display issues.""" - # DEPRECATED: Migrate to ttk.Button. Will remove in 5.12 or later. def __init__(self, master: ttk.Frame | None = None, **kw): if sys.platform == 'win32': ttk.Button.__init__(self, master, style='nb.TButton', **kw) @@ -139,8 +138,8 @@ class Button(ttk.Button): # type: ignore ttk.Button.__init__(self, master, **kw) -class ColoredButton(tk.Button): # type: ignore - """Custom t(t)k.ColoredButton class to fix some display issues.""" +class ColoredButton(tk.Button): + """Custom tk.Button class to fix some display issues.""" # DEPRECATED: Migrate to tk.Button. Will remove in 5.12 or later. def __init__(self, master: ttk.Frame | None = None, **kw): @@ -148,15 +147,15 @@ class ColoredButton(tk.Button): # type: ignore class Checkbutton(ttk.Checkbutton): - """Custom t(t)k.Checkbutton class to fix some display issues.""" + """Custom ttk.Checkbutton class to fix some display issues.""" - def __init__(self, master=None, **kw): + def __init__(self, master: ttk.Frame | None = None, **kw): style = 'nb.TCheckbutton' if sys.platform == 'win32' else None super().__init__(master, style=style, **kw) # type: ignore class Radiobutton(ttk.Radiobutton): - """Custom t(t)k.Radiobutton class to fix some display issues.""" + """Custom ttk.Radiobutton class to fix some display issues.""" def __init__(self, master: ttk.Frame | None = None, **kw): style = 'nb.TRadiobutton' if sys.platform == 'win32' else None diff --git a/plugins/coriolis.py b/plugins/coriolis.py index cc7e965a..07b4ac9f 100644 --- a/plugins/coriolis.py +++ b/plugins/coriolis.py @@ -106,25 +106,24 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> nb.Fr # LANG: Settings>Coriolis: Label for 'NOT alpha/beta game version' URL nb.Label(conf_frame, text=_('Normal URL')).grid(sticky=tk.W, row=cur_row, column=0, padx=PADX, pady=PADY) - ttk.Entry(conf_frame, - textvariable=coriolis_config.normal_textvar).grid( + nb.EntryMenu(conf_frame, textvariable=coriolis_config.normal_textvar).grid( sticky=tk.EW, row=cur_row, column=1, padx=PADX, pady=BOXY ) # LANG: Generic 'Reset' button label - ttk.Button(conf_frame, text=_("Reset"), - command=lambda: coriolis_config.normal_textvar.set(value=DEFAULT_NORMAL_URL)).grid( + nb.Button(conf_frame, text=_("Reset"), + command=lambda: coriolis_config.normal_textvar.set(value=DEFAULT_NORMAL_URL)).grid( sticky=tk.W, row=cur_row, column=2, padx=PADX, pady=0 ) cur_row += 1 # LANG: Settings>Coriolis: Label for 'alpha/beta game version' URL nb.Label(conf_frame, text=_('Beta URL')).grid(sticky=tk.W, row=cur_row, column=0, padx=PADX, pady=PADY) - ttk.Entry(conf_frame, textvariable=coriolis_config.beta_textvar).grid( - sticky=tk.EW, row=cur_row, column=1, padx=PADX, pady=BOXY + nb.EntryMenu(conf_frame, textvariable=coriolis_config.beta_textvar).grid( + sticky=tk.EW, row=cur_row, column=1, padx=PADX, pady=BOXY ) # LANG: Generic 'Reset' button label - ttk.Button(conf_frame, text=_('Reset'), - command=lambda: coriolis_config.beta_textvar.set(value=DEFAULT_BETA_URL)).grid( + nb.Button(conf_frame, text=_('Reset'), + command=lambda: coriolis_config.beta_textvar.set(value=DEFAULT_BETA_URL)).grid( sticky=tk.W, row=cur_row, column=2, padx=PADX, pady=0 ) cur_row += 1 diff --git a/plugins/edsm.py b/plugins/edsm.py index 55aae7b8..b2a8035f 100644 --- a/plugins/edsm.py +++ b/plugins/edsm.py @@ -113,10 +113,10 @@ class This: self.cmdr_text: nb.Label | None = None self.user_label: nb.Label | None = None - self.user: ttk.Entry | None = None + self.user: nb.EntryMenu | None = None self.apikey_label: nb.Label | None = None - self.apikey: ttk.Entry | None = None + self.apikey: nb.EntryMenu | None = None this = This() @@ -345,14 +345,14 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> nb.Fr # LANG: EDSM Commander name label in EDSM settings this.user_label = nb.Label(frame, text=_('Commander Name')) this.user_label.grid(row=cur_row, padx=PADX, pady=PADY, sticky=tk.W) - this.user = ttk.Entry(frame) + this.user = nb.EntryMenu(frame) this.user.grid(row=cur_row, column=1, padx=PADX, pady=BOXY, sticky=tk.EW) cur_row += 1 # LANG: EDSM API key label this.apikey_label = nb.Label(frame, text=_('API Key')) this.apikey_label.grid(row=cur_row, padx=PADX, pady=PADY, sticky=tk.W) - this.apikey = ttk.Entry(frame, show="*", width=50) + this.apikey = nb.EntryMenu(frame, show="*", width=50) this.apikey.grid(row=cur_row, column=1, padx=PADX, pady=BOXY, sticky=tk.EW) cur_row += 1 diff --git a/plugins/inara.py b/plugins/inara.py index 29bfaaf2..810f7523 100644 --- a/plugins/inara.py +++ b/plugins/inara.py @@ -125,7 +125,7 @@ class This: self.log: 'tk.IntVar' self.log_button: nb.Checkbutton self.label: HyperlinkLabel - self.apikey: ttk.Entry + self.apikey: nb.EntryMenu self.apikey_label: tk.Label self.events: dict[Credentials, Deque[Event]] = defaultdict(deque) @@ -292,7 +292,7 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str, is_beta: bool) -> nb.Frame: # LANG: Inara API key label this.apikey_label = nb.Label(frame, text=_('API Key')) # Inara setting this.apikey_label.grid(row=cur_row, padx=PADX, pady=PADY, sticky=tk.W) - this.apikey = ttk.Entry(frame, show="*", width=50) + this.apikey = nb.EntryMenu(frame, show="*", width=50) this.apikey.grid(row=cur_row, column=1, padx=PADX, pady=BOXY, sticky=tk.EW) cur_row += 1 diff --git a/prefs.py b/prefs.py index 5e0f946b..285ef0d7 100644 --- a/prefs.py +++ b/prefs.py @@ -376,8 +376,6 @@ class PreferencesDialog(tk.Toplevel): ) self.outbutton.grid(column=1, padx=self.PADX, pady=self.PADY, sticky=tk.EW, row=row.get()) - nb.Frame(output_frame).grid(row=row.get()) # type: ignore # bottom spacer # TODO: does nothing? - # LANG: Label for 'Output' Settings/Preferences tab root_notebook.add(output_frame, text=_('Output')) # Tab heading in settings diff --git a/requirements.txt b/requirements.txt index c9239fdc..75ea4041 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ certifi==2024.2.2 requests==2.31.0 -pillow==10.2.0 +pillow==10.3.0 # requests depends on this now ? -charset-normalizer==2.1.1 +charset-normalizer==3.3.2 watchdog==3.0.0 # Commented out because this doesn't package well with py2exe From 0410806152fbe324867e9bc1258b3211b409344a Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Sun, 14 Apr 2024 18:07:30 -0400 Subject: [PATCH 37/49] [2199] Add Broader Exception --- killswitch.py | 4 ++-- myNotebook.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/killswitch.py b/killswitch.py index 9cc407a6..89a55292 100644 --- a/killswitch.py +++ b/killswitch.py @@ -361,8 +361,8 @@ def fetch_kill_switches(target=DEFAULT_KILLSWITCH_URL) -> KillSwitchJSONFile | N logger.warning(f"Failed to get kill switches, data was invalid: {e}") return None - except (requests.exceptions.BaseHTTPError, requests.exceptions.ConnectionError) as e: # type: ignore - logger.warning(f"unable to connect to {target!r}: {e}") + except requests.exceptions.RequestException as requ_err: + logger.warning(f"unable to connect to {target!r}: {requ_err}") return None return data diff --git a/myNotebook.py b/myNotebook.py index 0eeb96a4..88b4aec5 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -63,11 +63,11 @@ class Label(tk.Label): super().__init__(master, **kw) -class EntryMenu(ttk.Entry): +class EntryMenu: """Extended entry widget that includes a context menu with Copy, Cut-and-Paste commands.""" def __init__(self, *args, **kwargs) -> None: - super().__init__(*args, **kwargs) + ttk.Entry.__init__(self, *args, **kwargs) self.menu = tk.Menu(self, tearoff=False) self.menu.add_command(label="Copy", command=self.copy) @@ -120,7 +120,7 @@ class EntryMenu(ttk.Entry): pass -class Entry(ttk.Entry or EntryMenu): # type: ignore +class Entry(ttk.Entry, EntryMenu): """Custom t(t)k.Entry class to fix some display issues.""" # DEPRECATED: Migrate to ttk.Entry or EntryMenu. Will remove in 5.12 or later. From fbeeded28046aac2985dc468b757ccf82711cf92 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Sun, 14 Apr 2024 20:17:08 -0400 Subject: [PATCH 38/49] [2202] Add a number of missing modules This will need to be basically speedran into live. --- edmc_data.py | 31 ++++++++++++++++++++++++------- outfitting.py | 17 ++++++++++++++++- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/edmc_data.py b/edmc_data.py index 7be76096..d76badc6 100644 --- a/edmc_data.py +++ b/edmc_data.py @@ -69,6 +69,8 @@ outfitting_weapon_map = { 'advancedtorppylon': 'Torpedo Pylon', 'atdumbfiremissile': 'AX Missile Rack', 'atmulticannon': 'AX Multi-Cannon', + ('atmulticannon', 'v2'): 'Enhanced AX Multi-Cannon', + ('atdumbfiremissile', 'v2'): 'Enhanced AX Missile Rack', 'basicmissilerack': 'Seeker Missile Rack', 'beamlaser': 'Beam Laser', ('beamlaser', 'heat'): 'Retributor Beam Laser', @@ -88,6 +90,8 @@ outfitting_weapon_map = { 'mining_abrblstr': 'Abrasion Blaster', 'mining_seismchrgwarhd': 'Seismic Charge Launcher', 'mining_subsurfdispmisle': 'Sub-Surface Displacement Missile', + 'human_extraction': 'Sub-Surface Extraction Missile', + 'atventdisruptorpylon': 'Guardian Nanite Torpedo Pylon', 'mininglaser': 'Mining Laser', ('mininglaser', 'advanced'): 'Mining Lance Beam Laser', 'multicannon': 'Multi-Cannon', @@ -266,6 +270,11 @@ outfitting_weaponrating_map = { 'hpt_slugshot_turret_medium': 'D', 'hpt_slugshot_turret_large': 'C', 'hpt_xenoscannermk2_basic_tiny': '?', + 'hpt_atmulticannon_gimbal_large': 'C', + 'hpt_atmulticannon_gimbal_medium': 'E', + 'hpt_human_extraction_fixed_medium': 'B', + 'hpt_atventdisruptorpylon_fixed_medium': 'I', + 'hpt_atventdisruptorpylon_fixed_large': 'I', } # Old standard weapon variants @@ -278,13 +287,14 @@ outfitting_weaponoldvariant_map = { } outfitting_countermeasure_map = { - 'antiunknownshutdown': ('Shutdown Field Neutraliser', 'F'), - 'chafflauncher': ('Chaff Launcher', 'I'), - 'electroniccountermeasure': ('Electronic Countermeasure', 'F'), - 'heatsinklauncher': ('Heat Sink Launcher', 'I'), - 'plasmapointdefence': ('Point Defence', 'I'), - 'xenoscanner': ('Xeno Scanner', 'E'), - 'xenoscannermk2': ('Unknown Xeno Scanner Mk II', '?'), + 'antiunknownshutdown': ('Shutdown Field Neutraliser', 'F'), + ('antiunknownshutdown', 'v2'): ('Thargoid Pulse Neutraliser', 'E'), + 'chafflauncher': ('Chaff Launcher', 'I'), + 'electroniccountermeasure': ('Electronic Countermeasure', 'F'), + 'heatsinklauncher': ('Heat Sink Launcher', 'I'), + 'plasmapointdefence': ('Point Defence', 'I'), + 'xenoscanner': ('Xeno Scanner', 'E'), + 'xenoscannermk2': ('Unknown Xeno Scanner Mk II', '?'), } outfitting_utility_map = { @@ -347,6 +357,7 @@ outfitting_standard_map = { 'guardianpowerdistributor': 'Guardian Hybrid Power Distributor', 'guardianpowerplant': 'Guardian Hybrid Power Plant', 'hyperdrive': 'Frame Shift Drive', + ('hyperdrive', 'overcharge'): 'Frame Shift Drive', 'lifesupport': 'Life Support', # 'planetapproachsuite': handled separately 'powerdistributor': 'Power Distributor', @@ -376,6 +387,11 @@ outfitting_internal_map = { 'refinery': 'Refinery', 'recon': 'Recon Limpet Controller', 'repair': 'Repair Limpet Controller', + 'rescue': 'Rescue Limpet Controller', + 'mining': 'Mining Multi Limpet Controller', + 'xeno': 'Xeno Multi Limpet Controller', + 'operations': 'Operations Multi Limpet Controller', + 'universal': 'Universal Multi Limpet Controller', 'repairer': 'Auto Field-Maintenance Unit', 'resourcesiphon': 'Hatch Breaker Limpet Controller', 'shieldcellbank': 'Shield Cell Bank', @@ -383,6 +399,7 @@ outfitting_internal_map = { ('shieldgenerator', 'fast'): 'Bi-Weave Shield Generator', ('shieldgenerator', 'strong'): 'Prismatic Shield Generator', 'unkvesselresearch': 'Research Limpet Controller', + 'expmodulestabiliser': 'Experimental Weapon Stabiliser', } # Dashboard Flags constants diff --git a/outfitting.py b/outfitting.py index a1b6b9db..5632687c 100644 --- a/outfitting.py +++ b/outfitting.py @@ -98,6 +98,12 @@ def lookup(module, ship_map, entitled=False) -> dict | None: # noqa: C901, CCR0 elif not entitled and name[1] == 'planetapproachsuite': return None + # V2 Shutdown Field Neutralizer - Hpt_AntiUnknownShutdown_Tiny_V2 + elif name[0] == 'hpt' and name[1] in countermeasure_map and len(name) == 4 and name[3] == 'v2': + new['category'] = 'utility' + new['name'], new['rating'] = countermeasure_map[name[1]] + new['class'] = weaponclass_map[name[-2]] + # Countermeasures - e.g. Hpt_PlasmaPointDefence_Turret_Tiny elif name[0] == 'hpt' and name[1] in countermeasure_map: new['category'] = 'utility' @@ -179,12 +185,18 @@ def lookup(module, ship_map, entitled=False) -> dict | None: # noqa: C901, CCR0 if name[1] == 'dronecontrol': # e.g. Int_DroneControl_Collection_Size1_Class1 name.pop(0) + elif name[1] == 'multidronecontrol': # e.g. Int_MultiDroneControl_Rescue_Size3_Class3 + name.pop(0) + elif name[-1] == 'free': # Starter Sidewinder or Freagle modules - just treat them like vanilla modules name.pop() if name[1] in standard_map: # e.g. Int_Engine_Size2_Class1, Int_ShieldGenerator_Size8_Class5_Strong new['category'] = 'standard' - new['name'] = standard_map[len(name) > 4 and (name[1], name[4]) or name[1]] + if name[2] == 'overcharge': + new['name'] = standard_map[(name[1], name[2])] + else: + new['name'] = standard_map[len(name) > 4 and (name[1], name[4]) or name[1]] elif name[1] in internal_map: # e.g. Int_CargoRack_Size8_Class1 new['category'] = 'internal' @@ -209,6 +221,9 @@ def lookup(module, ship_map, entitled=False) -> dict | None: # noqa: C901, CCR0 elif len(name) < 4 and name[1] == 'guardianfsdbooster': # Hack! No class. (new['class'], new['rating']) = (str(name[2][4:]), 'H') + elif len(name) > 4 and name[1] == 'hyperdrive': # e.g. Int_Hyperdrive_Overcharge_Size6_Class3 + (new['class'], new['rating']) = (str(name[4][-1:]), 'C') + else: if len(name) < 3: raise AssertionError(f'{name}: length < 3]') From 5cc08f25175e6286f6012cc0b3c3311ec685f37d Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Sun, 14 Apr 2024 20:32:43 -0400 Subject: [PATCH 39/49] [Minor] Clarify Inheritence --- myNotebook.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/myNotebook.py b/myNotebook.py index 88b4aec5..dd6e3429 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -63,7 +63,7 @@ class Label(tk.Label): super().__init__(master, **kw) -class EntryMenu: +class EntryMenu(ttk.Entry): """Extended entry widget that includes a context menu with Copy, Cut-and-Paste commands.""" def __init__(self, *args, **kwargs) -> None: @@ -120,7 +120,7 @@ class EntryMenu: pass -class Entry(ttk.Entry, EntryMenu): +class Entry(EntryMenu): """Custom t(t)k.Entry class to fix some display issues.""" # DEPRECATED: Migrate to ttk.Entry or EntryMenu. Will remove in 5.12 or later. From 7a030cd7f4775493c17743ac4fb628ba29535a9d Mon Sep 17 00:00:00 2001 From: Phoebe <40956085+C1701D@users.noreply.github.com> Date: Thu, 28 Mar 2024 16:02:23 +0000 Subject: [PATCH 40/49] Merge pull request #2182 from HullSeals/enhancement/2155/add-docking-schemas [2155] Add DockingDenied and DockingGranted Schemas LGTM --- plugins/eddn.py | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/plugins/eddn.py b/plugins/eddn.py index 687b39b7..586242a5 100644 --- a/plugins/eddn.py +++ b/plugins/eddn.py @@ -1880,6 +1880,74 @@ class EDDN: return None + def export_journal_dockingdenied( + self, cmdr: str, is_beta: bool, entry: Mapping[str, Any] + ) -> str | None: + """ + Send a DockingDenied to EDDN on the correct schema. + + :param cmdr: the commander under which this upload is made + :param is_beta: whether or not we are in beta mode + :param entry: the journal entry to send + + Example: + { + "timestamp":"2022-06-10T10:09:41Z", + "event":"DockingDenied", + "Reason":"RestrictedAccess", + "MarketID":3706117376, + "StationName":"V7G-T1G", + "StationType":"FleetCarrier" + } + """ + ####################################################################### + # Elisions + ####################################################################### + # In case Frontier ever add any + entry = filter_localised(entry) + + msg = { + '$schemaRef': f'https://eddn.edcd.io/schemas/dockingdenied/1{"/test" if is_beta else ""}', + 'message': entry + } + + this.eddn.send_message(cmdr, msg) + return None + + def export_journal_dockinggranted( + self, cmdr: str, is_beta: bool, entry: Mapping[str, Any] + ) -> str | None: + """ + Send a DockingDenied to EDDN on the correct schema. + + :param cmdr: the commander under which this upload is made + :param is_beta: whether or not we are in beta mode + :param entry: the journal entry to send + + Example: + { + "timestamp":"2023-10-01T14:56:34Z", + "event":"DockingGranted", + "LandingPad":41, + "MarketID":3227312896, + "StationName":"Evans Horizons", + "StationType":"Coriolis" + } + """ + ####################################################################### + # Elisions + ####################################################################### + # In case Frontier ever add any + entry = filter_localised(entry) + + msg = { + '$schemaRef': f'https://eddn.edcd.io/schemas/dockinggranted/1{"/test" if is_beta else ""}', + 'message': entry + } + + this.eddn.send_message(cmdr, msg) + return None + def canonicalise(self, item: str) -> str: """ Canonicalise the given commodity name. @@ -2327,6 +2395,12 @@ def journal_entry( # noqa: C901, CCR001 if event_name == 'fcmaterials': return this.eddn.export_journal_fcmaterials(cmdr, is_beta, entry) + if event_name == "dockingdenied": + return this.eddn.export_journal_dockingdenied(cmdr, is_beta, entry) + + if event_name == "dockinggranted": + return this.eddn.export_journal_dockinggranted(cmdr, is_beta, entry) + if event_name == 'approachsettlement': # An `ApproachSettlement` can appear *before* `Location` if you # logged at one. We won't have necessary augmentation data From 96be38d85b1836f5d0cbefe4873b080d0743daca Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Sat, 30 Mar 2024 16:02:54 -0400 Subject: [PATCH 41/49] [Minor] Add Missing Future Annotation --- config/linux.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/linux.py b/config/linux.py index 73100800..51a40626 100644 --- a/config/linux.py +++ b/config/linux.py @@ -5,6 +5,8 @@ Copyright (c) EDCD, All Rights Reserved Licensed under the GNU General Public License. See LICENSE file. """ +from __future__ import annotations + import os import pathlib import sys From 5c49ea16b9d5f830ea6205c357062569c8bd01b5 Mon Sep 17 00:00:00 2001 From: David Sangrey <davidsangrey@gmail.com> Date: Thu, 11 Apr 2024 09:52:57 -0400 Subject: [PATCH 42/49] Merge pull request #2197 from EDCD/submodule-change/8646630819 [Auto-generated] Submodule Updates 8646630819 --- FDevIDs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FDevIDs b/FDevIDs index 7205c793..7cffab3d 160000 --- a/FDevIDs +++ b/FDevIDs @@ -1 +1 @@ -Subproject commit 7205c79331f42c1a28b757b27467f79ff106716b +Subproject commit 7cffab3d913b788f981923687203399c22cf358f From c4baf66dc36e692584856d7dc6a796ab3dffc924 Mon Sep 17 00:00:00 2001 From: David Sangrey <davidsangrey@gmail.com> Date: Mon, 15 Apr 2024 16:33:34 -0400 Subject: [PATCH 43/49] Merge pull request #2204 from HullSeals/enhancement/2202/add-missing-modules [2202] Add a number of missing modules --- edmc_data.py | 31 ++++++++++++++++++++++++------- outfitting.py | 17 ++++++++++++++++- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/edmc_data.py b/edmc_data.py index c628ae8d..b7ed4556 100644 --- a/edmc_data.py +++ b/edmc_data.py @@ -69,6 +69,8 @@ outfitting_weapon_map = { 'advancedtorppylon': 'Torpedo Pylon', 'atdumbfiremissile': 'AX Missile Rack', 'atmulticannon': 'AX Multi-Cannon', + ('atmulticannon', 'v2'): 'Enhanced AX Multi-Cannon', + ('atdumbfiremissile', 'v2'): 'Enhanced AX Missile Rack', 'basicmissilerack': 'Seeker Missile Rack', 'beamlaser': 'Beam Laser', ('beamlaser', 'heat'): 'Retributor Beam Laser', @@ -88,6 +90,8 @@ outfitting_weapon_map = { 'mining_abrblstr': 'Abrasion Blaster', 'mining_seismchrgwarhd': 'Seismic Charge Launcher', 'mining_subsurfdispmisle': 'Sub-Surface Displacement Missile', + 'human_extraction': 'Sub-Surface Extraction Missile', + 'atventdisruptorpylon': 'Guardian Nanite Torpedo Pylon', 'mininglaser': 'Mining Laser', ('mininglaser', 'advanced'): 'Mining Lance Beam Laser', 'multicannon': 'Multi-Cannon', @@ -266,6 +270,11 @@ outfitting_weaponrating_map = { 'hpt_slugshot_turret_medium': 'D', 'hpt_slugshot_turret_large': 'C', 'hpt_xenoscannermk2_basic_tiny': '?', + 'hpt_atmulticannon_gimbal_large': 'C', + 'hpt_atmulticannon_gimbal_medium': 'E', + 'hpt_human_extraction_fixed_medium': 'B', + 'hpt_atventdisruptorpylon_fixed_medium': 'I', + 'hpt_atventdisruptorpylon_fixed_large': 'I', } # Old standard weapon variants @@ -278,13 +287,14 @@ outfitting_weaponoldvariant_map = { } outfitting_countermeasure_map = { - 'antiunknownshutdown': ('Shutdown Field Neutraliser', 'F'), - 'chafflauncher': ('Chaff Launcher', 'I'), - 'electroniccountermeasure': ('Electronic Countermeasure', 'F'), - 'heatsinklauncher': ('Heat Sink Launcher', 'I'), - 'plasmapointdefence': ('Point Defence', 'I'), - 'xenoscanner': ('Xeno Scanner', 'E'), - 'xenoscannermk2': ('Unknown Xeno Scanner Mk II', '?'), + 'antiunknownshutdown': ('Shutdown Field Neutraliser', 'F'), + ('antiunknownshutdown', 'v2'): ('Thargoid Pulse Neutraliser', 'E'), + 'chafflauncher': ('Chaff Launcher', 'I'), + 'electroniccountermeasure': ('Electronic Countermeasure', 'F'), + 'heatsinklauncher': ('Heat Sink Launcher', 'I'), + 'plasmapointdefence': ('Point Defence', 'I'), + 'xenoscanner': ('Xeno Scanner', 'E'), + 'xenoscannermk2': ('Unknown Xeno Scanner Mk II', '?'), } outfitting_utility_map = { @@ -347,6 +357,7 @@ outfitting_standard_map = { 'guardianpowerdistributor': 'Guardian Hybrid Power Distributor', 'guardianpowerplant': 'Guardian Hybrid Power Plant', 'hyperdrive': 'Frame Shift Drive', + ('hyperdrive', 'overcharge'): 'Frame Shift Drive', 'lifesupport': 'Life Support', # 'planetapproachsuite': handled separately 'powerdistributor': 'Power Distributor', @@ -376,6 +387,11 @@ outfitting_internal_map = { 'refinery': 'Refinery', 'recon': 'Recon Limpet Controller', 'repair': 'Repair Limpet Controller', + 'rescue': 'Rescue Limpet Controller', + 'mining': 'Mining Multi Limpet Controller', + 'xeno': 'Xeno Multi Limpet Controller', + 'operations': 'Operations Multi Limpet Controller', + 'universal': 'Universal Multi Limpet Controller', 'repairer': 'Auto Field-Maintenance Unit', 'resourcesiphon': 'Hatch Breaker Limpet Controller', 'shieldcellbank': 'Shield Cell Bank', @@ -383,6 +399,7 @@ outfitting_internal_map = { ('shieldgenerator', 'fast'): 'Bi-Weave Shield Generator', ('shieldgenerator', 'strong'): 'Prismatic Shield Generator', 'unkvesselresearch': 'Research Limpet Controller', + 'expmodulestabiliser': 'Experimental Weapon Stabiliser', } # Dashboard Flags constants diff --git a/outfitting.py b/outfitting.py index a5ccb4be..d290ad3b 100644 --- a/outfitting.py +++ b/outfitting.py @@ -100,6 +100,12 @@ def lookup(module, ship_map, entitled=False) -> dict | None: # noqa: C901, CCR0 elif not entitled and name[1] == 'planetapproachsuite': return None + # V2 Shutdown Field Neutralizer - Hpt_AntiUnknownShutdown_Tiny_V2 + elif name[0] == 'hpt' and name[1] in countermeasure_map and len(name) == 4 and name[3] == 'v2': + new['category'] = 'utility' + new['name'], new['rating'] = countermeasure_map[name[1]] + new['class'] = weaponclass_map[name[-2]] + # Countermeasures - e.g. Hpt_PlasmaPointDefence_Turret_Tiny elif name[0] == 'hpt' and name[1] in countermeasure_map: new['category'] = 'utility' @@ -181,12 +187,18 @@ def lookup(module, ship_map, entitled=False) -> dict | None: # noqa: C901, CCR0 if name[1] == 'dronecontrol': # e.g. Int_DroneControl_Collection_Size1_Class1 name.pop(0) + elif name[1] == 'multidronecontrol': # e.g. Int_MultiDroneControl_Rescue_Size3_Class3 + name.pop(0) + elif name[-1] == 'free': # Starter Sidewinder or Freagle modules - just treat them like vanilla modules name.pop() if name[1] in standard_map: # e.g. Int_Engine_Size2_Class1, Int_ShieldGenerator_Size8_Class5_Strong new['category'] = 'standard' - new['name'] = standard_map[len(name) > 4 and (name[1], name[4]) or name[1]] + if name[2] == 'overcharge': + new['name'] = standard_map[(name[1], name[2])] + else: + new['name'] = standard_map[len(name) > 4 and (name[1], name[4]) or name[1]] elif name[1] in internal_map: # e.g. Int_CargoRack_Size8_Class1 new['category'] = 'internal' @@ -211,6 +223,9 @@ def lookup(module, ship_map, entitled=False) -> dict | None: # noqa: C901, CCR0 elif len(name) < 4 and name[1] == 'guardianfsdbooster': # Hack! No class. (new['class'], new['rating']) = (str(name[2][4:]), 'H') + elif len(name) > 4 and name[1] == 'hyperdrive': # e.g. Int_Hyperdrive_Overcharge_Size6_Class3 + (new['class'], new['rating']) = (str(name[4][-1:]), 'C') + else: if len(name) < 3: raise AssertionError(f'{name}: length < 3]') From 3cbe517fd6077e0e37141b10a877ff39a2724251 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Mon, 15 Apr 2024 16:44:18 -0400 Subject: [PATCH 44/49] [Translations] Update Translations and Requirements --- L10n/cs.strings | 6 +- L10n/de.strings | 20 +- L10n/es.strings | 6 +- L10n/it.strings | 20 +- L10n/ja.strings | 6 +- L10n/ko.strings | 6 +- L10n/pl.strings | 6 +- L10n/pt-BR.strings | 6 +- L10n/pt-PT.strings | 6 +- L10n/ru.strings | 35 +- L10n/sr-Latn-BA.strings | 6 +- L10n/sr-Latn.strings | 20 +- L10n/tr.strings | 805 ++++++++++++++++++++++++++++++++++++++++ L10n/zh-Hans.strings | 6 +- requirements.txt | 4 +- 15 files changed, 917 insertions(+), 41 deletions(-) create mode 100644 L10n/tr.strings diff --git a/L10n/cs.strings b/L10n/cs.strings index ba11dc39..071b5e69 100644 --- a/L10n/cs.strings +++ b/L10n/cs.strings @@ -178,13 +178,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Výchozí"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normal"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/de.strings b/L10n/de.strings index 2b7c72c4..be36b877 100644 --- a/L10n/de.strings +++ b/L10n/de.strings @@ -231,6 +231,18 @@ /* 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." = "Eins oder mehr deiner aktivierten Plugins konnte nicht geladen werden. Du kannst dir die Liste im '{PLUGINS}'-Tab unter '{FILE}' > '{SETTINGS}' ansehen. Dies könnte an einer falschen Ordnerstruktur liegen. Die Datei load.py sollte sich unter plugins/PLUGIN_NAME/load.py befinden.\n\nDu kannst ein Plugin deaktivieren, indem du dessen Ordner ein '{DISABLED}' am Ende des Namens anhängst."; +/* 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" = "Einer oder mehrere deiner URL-Anbieter waren ungültig und wurden zurückgesetzt:\n\n"; + +/* 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} war zuvor auf {OLDPROV} festgelegt und wurde zu {NEWPROV} zurückgesetzt.\n"; + +/* EDMarketConnector.py: Popup window title for Reset Providers; In files: EDMarketConnector.py:2161; */ +"EDMC: Default Providers Reset" = "EDMC: Standardanbieter wurden zurückgesetzt"; + +/* EDMarketConnector.py: Await Full CMDR Login to Game; In files: EDMarketConnector.py:813; */ +"Awaiting Full CMDR Login" = "Warte auf vollständige CMDR Anmeldung"; + /* journal_lock.py: Title text on popup when Journal directory already locked; In files: journal_lock.py:208; */ "Journal directory already locked" = "Journal-Ordner bereits gesperrt"; @@ -246,13 +258,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Standard"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normal"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ @@ -768,3 +780,5 @@ /* stats.py: Status dialog title; In files: stats.py:418; */ "Ships" = "Schiffe"; +/* update.py: Update Available Text; In files: update.py:229; */ +"{NEWVER} is available" = "{NEWVER} ist verfügbar"; diff --git a/L10n/es.strings b/L10n/es.strings index d2cb7b4b..18874ccf 100644 --- a/L10n/es.strings +++ b/L10n/es.strings @@ -184,13 +184,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Por defecto"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normal"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/it.strings b/L10n/it.strings index e5f6ece6..c1cd9b33 100644 --- a/L10n/it.strings +++ b/L10n/it.strings @@ -231,6 +231,18 @@ /* 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." = "Impossibile caricare uno o più plugin abilitati. Consulta l'elenco nella scheda '{PLUGINS}' di '{FILE}' > '{SETTINGS}'. Ciò potrebbe essere causato da un'errata struttura delle cartelle. Il file load.py dovrebbe trovarsi in plugins/PLUGIN_NAME/load.py.\n\nPuoi disabilitare un plugin rinominando la sua cartella in modo che abbia '{DISABLED}' alla fine del nome."; +/* 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" = "Uno o più Provider URL non erano validi e sono stati ripristinati:\n"; + +/* 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} era impostato su {OLDPROV} ed è stato reimpostato su {NEWPROV}\n"; + +/* EDMarketConnector.py: Popup window title for Reset Providers; In files: EDMarketConnector.py:2161; */ +"EDMC: Default Providers Reset" = "EDMC: Reset dei provider predefiniti"; + +/* EDMarketConnector.py: Await Full CMDR Login to Game; In files: EDMarketConnector.py:813; */ +"Awaiting Full CMDR Login" = "In attesa del login completo al CMDR"; + /* journal_lock.py: Title text on popup when Journal directory already locked; In files: journal_lock.py:208; */ "Journal directory already locked" = "cartella Journal già bloccata"; @@ -246,13 +258,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Predefinito"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normale"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ @@ -789,3 +801,5 @@ /* stats.py: Status dialog title; In files: stats.py:418; */ "Ships" = "Navi"; +/* update.py: Update Available Text; In files: update.py:229; */ +"{NEWVER} is available" = "{NEWVER} è disponibile"; diff --git a/L10n/ja.strings b/L10n/ja.strings index 68a9fd34..82d9f8df 100644 --- a/L10n/ja.strings +++ b/L10n/ja.strings @@ -246,13 +246,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "デフォルト"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "自動"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "通常版"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "ベータ版"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/ko.strings b/L10n/ko.strings index 577695b0..e29ad74f 100644 --- a/L10n/ko.strings +++ b/L10n/ko.strings @@ -202,13 +202,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "기본값"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "자동"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "일반"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "베타"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/pl.strings b/L10n/pl.strings index 72a66718..547406b1 100644 --- a/L10n/pl.strings +++ b/L10n/pl.strings @@ -234,13 +234,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Domyślne"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normalny"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/pt-BR.strings b/L10n/pt-BR.strings index e719101a..605e0559 100644 --- a/L10n/pt-BR.strings +++ b/L10n/pt-BR.strings @@ -234,13 +234,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Padrão"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Automático"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normal"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/pt-PT.strings b/L10n/pt-PT.strings index ea292b14..0fd5b585 100644 --- a/L10n/pt-PT.strings +++ b/L10n/pt-PT.strings @@ -246,13 +246,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Predefinido"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normal"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/ru.strings b/L10n/ru.strings index c3c0fae1..19449e21 100644 --- a/L10n/ru.strings +++ b/L10n/ru.strings @@ -213,12 +213,36 @@ /* 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." = "Один или несколько ваших подключённых плагинов ещё не имеют поддержки Python 3.x. Пожалуйста, ознакомьтесь со списком во вкладке '{PLUGINS}' '{FILE}' > '{SETTINGS}'. Вы должны проверить наличие обновлённой версии, в противном случае предупредите разработчика о необходимости обновления кода на Python 3.x.\n\nВы можете отключить плагин, переименовав его папку в '{DISABLED}'."; +/* EDMarketConnector.py: Popup-text about missing FDEVID Files; In files: EDMarketConnector.py:2329; */ +"FDevID Files not found! Some functionality regarding commodities may be disabled.\r\n\r\n Do you want to open the Wiki page on how to set up submodules?" = "FDevID файлы не найдены! Некоторые функции, связанные с товарами, могут быть отключены.\n\nВы хотите открыть страницу Wiki о том, как настроить вспомогательные модули?"; + +/* EDMarketConnector.py: Popup window title for missing FDEVID files; In files: EDMarketConnector.py:2340; */ +"FDevIDs: Missing Commodity Files" = "FDevIDs: отсутствуют файлы товаров"; + /* EDMarketConnector.py: Settings > Plugins tab; prefs.py: Label on Settings > Plugins tab; In files: EDMarketConnector.py:2263; prefs.py:986; */ "Plugins" = "Плагины"; /* EDMarketConnector.py: Popup window title for list of 'enabled' plugins that don't work with Python 3.x; In files: EDMarketConnector.py:2274; */ "EDMC: Plugins Without Python 3.x Support" = "EDMC: Без поддержки Python 3.x"; +/* EDMarketConnector.py: Popup window title for list of 'broken' plugins that failed to load; In files: EDMarketConnector.py:2285; */ +"EDMC: Broken Plugins" = "EDMC: Неработающие плагины"; + +/* 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." = "Не удалось загрузить один или несколько включенных плагинов. Пожалуйста, посмотрите список на вкладке '{PLUGINS}' в разделе '{FILE}' > '{SETTINGS}'. Причиной может быть неправильная структура папок. Файл load.py должен находиться в папке plugins/PLUGIN_NAME/load.py.\n\nВы можете отключить плагин, переименовав его папку так, чтобы в конце названия стояло '{DISABLED}'."; + +/* 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" = "Один или несколько ваших URL-провайдеров оказались некорректными и были сброшены:"; + +/* 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} был установлен на {OLDPROV} и был сброшен на {NEWPROV}"; + +/* EDMarketConnector.py: Popup window title for Reset Providers; In files: EDMarketConnector.py:2161; */ +"EDMC: Default Providers Reset" = "EDMC: сброс провайдеров по умолчанию"; + +/* EDMarketConnector.py: Await Full CMDR Login to Game; In files: EDMarketConnector.py:813; */ +"Awaiting Full CMDR Login" = "Ожидание полного входа в систему"; + /* journal_lock.py: Title text on popup when Journal directory already locked; In files: journal_lock.py:208; */ "Journal directory already locked" = "Каталог журнала уже заблокирован"; @@ -234,13 +258,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "По умолчанию"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Автоматический"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Стандартный"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Бета"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ @@ -471,6 +495,9 @@ /* prefs.py: Plugins - Label on URL to documentation about migrating plugins from Python 2.7; In files: prefs.py:962; */ "Information on migrating plugins" = "Информация о мигрирующих плагинах"; +/* prefs.py: Plugins - Label for list of 'broken' plugins that failed to load; In files: prefs.py:1039; */ +"Broken Plugins" = "Неработающие плагины"; + /* prefs.py: Lable on list of user-disabled plugins; In files: prefs.py:977; */ "Disabled Plugins" = "Отключенные плагины"; @@ -774,3 +801,5 @@ /* stats.py: Status dialog title; In files: stats.py:418; */ "Ships" = "Корабли"; +/* update.py: Update Available Text; In files: update.py:229; */ +"{NEWVER} is available" = "{NEWVER} доступен"; diff --git a/L10n/sr-Latn-BA.strings b/L10n/sr-Latn-BA.strings index 2950f8b8..f541416a 100644 --- a/L10n/sr-Latn-BA.strings +++ b/L10n/sr-Latn-BA.strings @@ -246,13 +246,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Standardna"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Automatski"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normalni"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/sr-Latn.strings b/L10n/sr-Latn.strings index 83da541a..e801d067 100644 --- a/L10n/sr-Latn.strings +++ b/L10n/sr-Latn.strings @@ -231,6 +231,18 @@ /* 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." = "Jedan ili više vaših aktivnih pluginova se nije učitao. Molimo pogledajte listu na '{PLUGINS}' tabu u okviru '{FILE}' > '{SETTINGS}'. Obo vi moglo da se desi zbog pogrešne strukture foldera. load.py fajl bi trebao da se nalazi unutar plugins/PLUGIN_NAME/load.py.\n\nPojedinačni plugin možete deaktivirati promenom imena njegovog foldera dodavanjem '{DISABLED}' na kraju."; +/* 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" = "Jedan ili više vaših URL Provajdera su pogrešni, pa su resetovani:\n"; + +/* 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} je bio postavljen na {OLDPROV} i sada je resetovan na {NEWPROV}\n"; + +/* EDMarketConnector.py: Popup window title for Reset Providers; In files: EDMarketConnector.py:2161; */ +"EDMC: Default Providers Reset" = "EDMC: Podrazumevani Provajderi resetovani"; + +/* EDMarketConnector.py: Await Full CMDR Login to Game; In files: EDMarketConnector.py:813; */ +"Awaiting Full CMDR Login" = "Čekam da se CMDR potpuno uloguje"; + /* journal_lock.py: Title text on popup when Journal directory already locked; In files: journal_lock.py:208; */ "Journal directory already locked" = "Žurnal direktorijum je već zaključan"; @@ -246,13 +258,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Podrazumevano"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normal"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ @@ -789,3 +801,5 @@ /* stats.py: Status dialog title; In files: stats.py:418; */ "Ships" = "Brodovi"; +/* update.py: Update Available Text; In files: update.py:229; */ +"{NEWVER} is available" = "{NEWVER} je dostupna"; diff --git a/L10n/tr.strings b/L10n/tr.strings new file mode 100644 index 00000000..9d37dfa1 --- /dev/null +++ b/L10n/tr.strings @@ -0,0 +1,805 @@ +/* edsm.py:Settings>EDSM - Label on checkbox for 'send data'; In files: edsm.py:316; */ +"Send flight log and CMDR status to EDSM" = "Uçuş günlüğünü ve CMDR durumunu EDSM'e gönder"; + +/* prefs.py:Label on button used to open a filesystem folder; In files: prefs.py:706; */ +"Open Log Folder" = "Günlük Klasörünü Aç"; + +/* inara.py:Text Inara Show API key; In files: inara.py:305; */ +"Show API Key" = "API Anahtarını Göster"; +/* Language name */ +"!Language" = "Türkçe"; + +/* companion.py: Frontier CAPI didn't respond; In files: companion.py:226; */ +"Error: Frontier CAPI didn't respond" = "Hata: Frontier CAPI yanıt vermedi"; + +/* companion.py: Frontier CAPI data doesn't agree with latest Journal game location; In files: companion.py:245; */ +"Error: Frontier server is lagging" = "Hata: Frontier sunucusu gecikmesi"; + +/* companion.py: Commander is docked at an EDO settlement, got out and back in, we forgot the station; In files: companion.py:261; */ +"Docked but unknown station: EDO Settlement?" = "Kenetlendi ancak bilinmeyen istasyon: EDO yerleşimi?"; + +/* companion.py: Generic "something went wrong with Frontier Auth" error; In files: companion.py:271; */ +"Error: Invalid Credentials" = "Hata: Geçersiz Kimlik"; + +/* companion.py: Frontier CAPI authorisation not for currently game-active commander; In files: companion.py:296; */ +"Error: Wrong Cmdr" = "Hata: Yanlış CMDR"; + +/* companion.py: Generic error prefix - following text is from Frontier auth service; In files: companion.py:432; companion.py:517; */ +"Error" = "Hata"; + +/* companion.py: Frontier auth, no 'usr' section in returned data; companion.py: Frontier auth, no 'customer_id' in 'usr' section in returned data; In files: companion.py:475; companion.py:480; */ +"Error: Couldn't check token customer_id" = "Hata: token kontrol edilemedi customer_id"; + +/* companion.py: Frontier auth customer_id doesn't match game session FID; In files: companion.py:486; */ +"Error: customer_id doesn't match!" = "Hata: customer_id uyuşmuyor!"; + +/* companion.py: Failed to get Access Token from Frontier Auth service; In files: companion.py:508; */ +"Error: unable to get token" = "Hata: token erişilemedi"; + +/* companion.py: Frontier CAPI returned 418, meaning down for maintenance; In files: companion.py:844; */ +"Frontier CAPI down for maintenance" = "Frontier CAPI bakım için kapalı durumda"; + +/* companion.py: Frontier CAPI data retrieval failed; In files: companion.py:856; */ +"Frontier CAPI query failure" = "Frontier CAPI sorgulama hatası"; + +/* EDMarketConnector.py: Main UI Update button; EDMarketConnector.py: Update button in main window; In files: EDMarketConnector.py:601; EDMarketConnector.py:919; EDMarketConnector.py:1748; */ +"Update" = "Güncelle"; + +/* EDMarketConnector.py: Appearance - Label for checkbox to select if application always on top; prefs.py: Appearance - Label for checkbox to select if application always on top; In files: EDMarketConnector.py:710; prefs.py:875; */ +"Always on top" = "Her zaman üstte"; + +/* EDMarketConnector.py: Unknown suit; In files: EDMarketConnector.py:837; */ +"Unknown" = "Bilinmeyen"; + +/* EDMarketConnector.py: ED Journal file location appears to be in error; In files: EDMarketConnector.py:906; */ +"Error: Check E:D journal file location" = "Hata: E:D günlük dosyası konumunu kontrol edin"; + +/* EDMarketConnector.py: Label for commander name in main window; edsm.py: Game Commander name label in EDSM settings; stats.py: Cmdr stats; theme.py: Label for commander name in main window; In files: EDMarketConnector.py:913; edsm.py:332; stats.py:57; theme.py:290; */ +"Cmdr" = "Cmdr"; + +/* EDMarketConnector.py: 'Ship' or multi-crew role label in main window, as applicable; EDMarketConnector.py: Multicrew role label in main window; In files: EDMarketConnector.py:915; EDMarketConnector.py:1487; */ +"Role" = "Rol"; + +/* EDMarketConnector.py: 'Ship' or multi-crew role label in main window, as applicable; EDMarketConnector.py: 'Ship' label in main UI; stats.py: Status dialog subtitle; In files: EDMarketConnector.py:915; EDMarketConnector.py:1497; EDMarketConnector.py:1520; stats.py:405; */ +"Ship" = "Gemi"; + +/* EDMarketConnector.py: Label for 'Suit' line in main UI; In files: EDMarketConnector.py:916; */ +"Suit" = "Süit"; + +/* EDMarketConnector.py: Label for 'System' line in main UI; prefs.py: Configuration - Label for selection of 'System' provider website; stats.py: Main window; In files: EDMarketConnector.py:917; prefs.py:614; stats.py:407; */ +"System" = "Sistem"; + +/* EDMarketConnector.py: Label for 'Station' line in main UI; prefs.py: Configuration - Label for selection of 'Station' provider website; prefs.py: Appearance - Example 'Normal' text; stats.py: Status dialog subtitle; In files: EDMarketConnector.py:918; prefs.py:632; prefs.py:770; stats.py:408; */ +"Station" = "İstasyon"; + +/* EDMarketConnector.py: 'File' menu title on OSX; EDMarketConnector.py: 'File' menu title; EDMarketConnector.py: 'File' menu; In files: EDMarketConnector.py:921; EDMarketConnector.py:939; EDMarketConnector.py:942; EDMarketConnector.py:2264; */ +"File" = "Dosya"; + +/* EDMarketConnector.py: 'Edit' menu title on OSX; EDMarketConnector.py: 'Edit' menu title; In files: EDMarketConnector.py:922; EDMarketConnector.py:940; EDMarketConnector.py:943; */ +"Edit" = "Düzenle"; + +/* EDMarketConnector.py: 'View' menu title on OSX; In files: EDMarketConnector.py:923; */ +"View" = "Görüntüle"; + +/* EDMarketConnector.py: 'Window' menu title on OSX; In files: EDMarketConnector.py:924; */ +"Window" = "Pencere"; + +/* EDMarketConnector.py: Help' menu title on OSX; EDMarketConnector.py: 'Help' menu title; In files: EDMarketConnector.py:925; EDMarketConnector.py:941; EDMarketConnector.py:944; */ +"Help" = "Yardım"; + +/* EDMarketConnector.py: App menu entry on OSX; EDMarketConnector.py: Help > About App; In files: EDMarketConnector.py:928; EDMarketConnector.py:959; EDMarketConnector.py:1804; */ +"About {APP}" = "Hakkında {APP}"; + +/* EDMarketConnector.py: Help > Check for Updates...; In files: EDMarketConnector.py:930; EDMarketConnector.py:958; */ +"Check for Updates..." = "Güncellemeleri Denetle..."; + +/* EDMarketConnector.py: File > Save Raw Data...; In files: EDMarketConnector.py:931; EDMarketConnector.py:948; */ +"Save Raw Data..." = "Ham Verileri Kaydet..."; + +/* EDMarketConnector.py: File > Status; stats.py: Status dialog title; In files: EDMarketConnector.py:932; EDMarketConnector.py:947; stats.py:402; */ +"Status" = "Durum"; + +/* EDMarketConnector.py: Help > Documentation; In files: EDMarketConnector.py:933; EDMarketConnector.py:953; */ +"Documentation" = "Dokümantasyon"; + +/* EDMarketConnector.py: Help > Troubleshooting; In files: EDMarketConnector.py:934; EDMarketConnector.py:954; */ +"Troubleshooting" = "Sorun giderme"; + +/* EDMarketConnector.py: Help > Report A Bug; In files: EDMarketConnector.py:935; EDMarketConnector.py:955; */ +"Report A Bug" = "Hata Bildir"; + +/* EDMarketConnector.py: Help > Privacy Policy; In files: EDMarketConnector.py:936; EDMarketConnector.py:956; */ +"Privacy Policy" = "Gizlilik Politikası"; + +/* EDMarketConnector.py: Help > Release Notes; In files: EDMarketConnector.py:937; EDMarketConnector.py:957; EDMarketConnector.py:1838; */ +"Release Notes" = "Sürüm notları"; + +/* EDMarketConnector.py: File > Settings; prefs.py: File > Settings (macOS); In files: EDMarketConnector.py:949; EDMarketConnector.py:2265; prefs.py:241; */ +"Settings" = "Ayarlar"; + +/* EDMarketConnector.py: File > Exit; In files: EDMarketConnector.py:950; */ +"Exit" = "Çıkış"; + +/* EDMarketConnector.py: Label for 'Copy' as in 'Copy and Paste'; ttkHyperlinkLabel.py: Label for 'Copy' as in 'Copy and Paste'; In files: EDMarketConnector.py:962; ttkHyperlinkLabel.py:53; */ +"Copy" = "Kopyala"; + +/* EDMarketConnector.py: CAPI auth aborted because of killswitch; EDMarketConnector.py: CAPI auth query aborted because of killswitch; In files: EDMarketConnector.py:973; EDMarketConnector.py:1067; */ +"CAPI auth disabled by killswitch" = "CAPI kimlik doğrulaması killswitch tarafından devre dışı bırakıldı"; + +/* EDMarketConnector.py: Status - Attempting to get a Frontier Auth Access Token; In files: EDMarketConnector.py:978; */ +"Logging in..." = "Giriş yapılıyor..."; + +/* EDMarketConnector.py: Successfully authenticated with the Frontier website; In files: EDMarketConnector.py:994; EDMarketConnector.py:1657; */ +"Authentication successful" = "Kimlik doğrulama başarılı"; + +/* EDMarketConnector.py: Player is not docked at a station, when we expect them to be; In files: EDMarketConnector.py:1025; */ +"You're not docked at a station!" = "Bir istasyona kenetli değilsiniz!"; + +/* EDMarketConnector.py: Status - Either no market or no modules data for station from Frontier CAPI; In files: EDMarketConnector.py:1033; */ +"Station doesn't have anything!" = "İstasyon içeriği mevcut değil."; + +/* EDMarketConnector.py: Status - No station market data from Frontier CAPI; In files: EDMarketConnector.py:1038; */ +"Station doesn't have a market!" = "İstasyon'da market bulunmuyor!"; + +/* EDMarketConnector.py: CAPI queries aborted because Cmdr name is unknown; EDMarketConnector.py: CAPI fleetcarrier query aborted because Cmdr name is unknown; In files: EDMarketConnector.py:1077; EDMarketConnector.py:1164; */ +"CAPI query aborted: Cmdr name unknown" = "CAPI sorgusu iptal edildi: Cmdr adı bilinmiyor"; + +/* EDMarketConnector.py: CAPI queries aborted because game mode unknown; In files: EDMarketConnector.py:1083; */ +"CAPI query aborted: Game mode unknown" = "CAPI sorgusu iptal edildi: Oyun modu bilinmiyor"; + +/* EDMarketConnector.py: CAPI queries aborted because GameVersion unknown; EDMarketConnector.py: CAPI fleetcarrier query aborted because GameVersion unknown; In files: EDMarketConnector.py:1089; EDMarketConnector.py:1170; */ +"CAPI query aborted: GameVersion unknown" = "CAPI sorgusu iptal edildi: GameVersion bilinmiyor"; + +/* EDMarketConnector.py: CAPI queries aborted because current star system name unknown; In files: EDMarketConnector.py:1095; */ +"CAPI query aborted: Current system unknown" = "CAPI sorgusu iptal edildi: Mevcut sistem bilinmiyor"; + +/* EDMarketConnector.py: CAPI queries aborted because player is in multi-crew on other Cmdr's ship; In files: EDMarketConnector.py:1101; */ +"CAPI query aborted: In other-ship multi-crew" = "CAPI sorgusu iptal edildi: Başka gemi çoklu-mürettebatı"; + +/* EDMarketConnector.py: CAPI queries aborted because player is in CQC (Arena); In files: EDMarketConnector.py:1107; */ +"CAPI query aborted: CQC (Arena) detected" = "CAPI sorgusu iptal edildi: CQC (Arena) tespit edildi"; + +/* EDMarketConnector.py: Status - Attempting to retrieve data from Frontier CAPI; In files: EDMarketConnector.py:1128; EDMarketConnector.py:1179; */ +"Fetching data..." = "Veri işleniyor..."; + +/* EDMarketConnector.py: CAPI fleetcarrier query aborted because of killswitch; In files: EDMarketConnector.py:1157; */ +"CAPI fleetcarrier disabled by killswitch" = "CAPI filo taşıyıcısı killswitch tarafından devre dışı bırakıldı"; + +/* EDMarketConnector.py: No data was returned for the fleetcarrier from the Frontier CAPI; In files: EDMarketConnector.py:1219; */ +"CAPI: No fleetcarrier data returned" = "CAPI: Filo taşıyıcı verisi gelmedi."; + +/* EDMarketConnector.py: We didn't have the fleetcarrier callsign when we should have; In files: EDMarketConnector.py:1223; */ +"CAPI: Fleetcarrier data incomplete" = "CAPI: Filo taşıyıcı verileri eksik"; + +/* EDMarketConnector.py: No data was returned for the commander from the Frontier CAPI; In files: EDMarketConnector.py:1242; */ +"CAPI: No commander data returned" = "CAPI: Cmdr verisi döndürülmedi"; + +/* EDMarketConnector.py: We didn't have the commander name when we should have; stats.py: Unknown commander; In files: EDMarketConnector.py:1246; stats.py:333; */ +"Who are you?!" = "Sen kimsin?!"; + +/* EDMarketConnector.py: We don't know where the commander is, when we should; stats.py: Unknown location; In files: EDMarketConnector.py:1252; stats.py:341; */ +"Where are you?!" = "Neredesin?!"; + +/* EDMarketConnector.py: We don't know what ship the commander is in, when we should; stats.py: Unknown ship; In files: EDMarketConnector.py:1259; stats.py:349; */ +"What are you flying?!" = "Ne uçuruyorsun?!"; + +/* EDMarketConnector.py: Frontier CAPI server error when fetching data; In files: EDMarketConnector.py:1384; */ +"Frontier CAPI server error" = "Frontier CAPI sunucu hatası"; + +/* EDMarketConnector.py: Frontier CAPI Access Token expired, trying to get a new one; In files: EDMarketConnector.py:1390; */ +"CAPI: Refreshing access token..." = "CAPI: Erişim token yenileniyor..."; + +/* EDMarketConnector.py: Time when we last obtained Frontier CAPI data; In files: EDMarketConnector.py:1434; */ +"Last updated at %H:%M:%S" = "Son güncelleme %H:%M:%S"; + +/* EDMarketConnector.py: Multicrew role; In files: EDMarketConnector.py:1462; */ +"Fighter" = "Avcı"; + +/* EDMarketConnector.py: Multicrew role; In files: EDMarketConnector.py:1463; */ +"Gunner" = "Nişancı"; + +/* EDMarketConnector.py: Multicrew role; In files: EDMarketConnector.py:1464; */ +"Helm" = "Dümen"; + +/* EDMarketConnector.py: Cooldown on 'Update' button; In files: EDMarketConnector.py:1742; */ +"cooldown {SS}s" = "bekleme süresi {SS}s"; + +/* EDMarketConnector.py: Generic 'OK' button label; prefs.py: 'OK' button on Settings/Preferences window; In files: EDMarketConnector.py:1864; prefs.py:292; */ +"OK" = "Tamam"; + +/* EDMarketConnector.py: The application is shutting down; In files: EDMarketConnector.py:1936; */ +"Shutting down..." = "Kapanıyor..."; + +/* 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." = "Etkin eklentilerinizden bir veya daha fazlası henüz Python 3.x desteğine sahip değil. '{PLUGINS}' sekmesindeki '{FILE}' > '{SETTINGS}' bölümünde bulunan listeyi bulun. Güncellenmiş bir sürümün mevcut olup olmadığını kontrol edin, aksi takdirde geliştiriciyi Python 3.x kodunu güncellemesi gerektiği konusunda uyarmalısınız.\n\nBir eklentiyi, klasörünü adının sonunda '{DISABLED}' olacak şekilde yeniden adlandırarak devre dışı bırakabilirsiniz."; + +/* EDMarketConnector.py: Popup-text about missing FDEVID Files; In files: EDMarketConnector.py:2329; */ +"FDevID Files not found! Some functionality regarding commodities may be disabled.\r\n\r\n Do you want to open the Wiki page on how to set up submodules?" = "FDevID Dosyaları bulunamadı! Ürünlerle ilgili bazı işlevler devre dışı bırakılabilir.\n\nAlt modüllerin nasıl kurulacağına ilişkin Wiki sayfasını açmak ister misiniz?"; + +/* EDMarketConnector.py: Popup window title for missing FDEVID files; In files: EDMarketConnector.py:2340; */ +"FDevIDs: Missing Commodity Files" = "FDevIDs: Eksik Ürün Dosyaları"; + +/* EDMarketConnector.py: Settings > Plugins tab; prefs.py: Label on Settings > Plugins tab; In files: EDMarketConnector.py:2263; prefs.py:986; */ +"Plugins" = "Eklentiler"; + +/* EDMarketConnector.py: Popup window title for list of 'enabled' plugins that don't work with Python 3.x; In files: EDMarketConnector.py:2274; */ +"EDMC: Plugins Without Python 3.x Support" = "EDMC: Python 3.x Desteği Olmayan Eklentiler"; + +/* EDMarketConnector.py: Popup window title for list of 'broken' plugins that failed to load; In files: EDMarketConnector.py:2285; */ +"EDMC: Broken Plugins" = "EDMC: Bozuk Eklentiler"; + +/* 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." = "Etkin eklentilerinizden bir veya daha fazlası yüklenemedi. '{PLUGINS}' sekmesindeki '{FILE}' > '{SETTINGS}' bölümünde bulunan listeyi bulun. Sorunun sebebi yanlış klasör yapısı olabilir. Load.py dosyası, plugins/PLUGIN_NAME/load.py altında bulunmalıdır.\n\nBir eklentiyi, klasörünü adının sonunda '{DISABLED}' olacak şekilde yeniden adlandırarak devre dışı bırakabilirsiniz."; + +/* 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" = "URL Sağlayıcılarınızdan bir veya daha fazlası geçersizdi ve sıfırlandı:"; + +/* 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} , {OLDPROV}'a ayarlanmıştı ancak {NEWPROV}'a sıfırlandı"; + +/* EDMarketConnector.py: Popup window title for Reset Providers; In files: EDMarketConnector.py:2161; */ +"EDMC: Default Providers Reset" = "EDMC: Varsayılan Sağlayıcıların Sıfırlanması"; + +/* EDMarketConnector.py: Await Full CMDR Login to Game; In files: EDMarketConnector.py:813; */ +"Awaiting Full CMDR Login" = "Tam CMDR Girişi Bekleniyor"; + +/* journal_lock.py: Title text on popup when Journal directory already locked; In files: journal_lock.py:208; */ +"Journal directory already locked" = "Günlük dizini zaten kilitli"; + +/* journal_lock.py: Text for when newly selected Journal directory is already locked; In files: journal_lock.py:225:226; */ +"The new Journal Directory location is already locked.{CR}You can either attempt to resolve this and then Retry, or choose to Ignore this." = "Yeni Günlük Dizini konumu zaten kilitli.{CR}Çözüm için Tekrar deneyebilir veya Yoksay'ı seçebilirsiniz."; + +/* journal_lock.py: Generic 'Retry' button label; In files: journal_lock.py:230; */ +"Retry" = "Tekrar Dene"; + +/* journal_lock.py: Generic 'Ignore' button label; In files: journal_lock.py:234; */ +"Ignore" = "Yoksay"; + +/* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ +"Default" = "Varsayılan"; + +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ +"Auto" = "Otomatik"; + +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ +"Normal" = "Normal"; + +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ +"Beta" = "Beta"; + +/* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ +"Set the URL to use with coriolis.io ship loadouts. Note that this MUST end with '/import?data='" = "Coriolis.io gemi ekipman tasarımları ile kullanılacak URL'yi ayarlayın. Link'in '/import?data=' ile bitmesi GEREKTİĞİNİ unutmayın."; + +/* coriolis.py: Settings>Coriolis: Label for 'NOT alpha/beta game version' URL; In files: coriolis.py:97; */ +"Normal URL" = "Normal URL"; + +/* coriolis.py: Generic 'Reset' button label; In files: coriolis.py:100; coriolis.py:109; */ +"Reset" = "Sıfırla"; + +/* coriolis.py: Settings>Coriolis: Label for 'alpha/beta game version' URL; In files: coriolis.py:106; */ +"Beta URL" = "Beta URL"; + +/* coriolis.py: Settings>Coriolis: Label for selection of using Normal, Beta or 'auto' Coriolis URL; In files: coriolis.py:116; */ +"Override Beta/Normal Selection" = "Beta/Normal Seçimi Geçersiz Kıl"; + +/* coriolis.py: Settings>Coriolis - invalid override mode found; In files: coriolis.py:156; */ +"Invalid Coriolis override mode!" = "Geçersiz Coriolis geçersiz kılma modu!"; + +/* eddn.py: Error while trying to send data to EDDN; In files: eddn.py:458; eddn.py:2413; eddn.py:2451; eddn.py:2519; */ +"Error: Can't connect to EDDN" = "Hata: EDDN'e bağlanılamıyor"; + +/* eddn.py: EDDN has banned this version of our client; In files: eddn.py:576; */ +"EDDN Error: EDMC is too old for EDDN. Please update." = "EDDN Hatası: EDMC sürümü EDDN için çok eski. Lütfen güncelle."; + +/* eddn.py: EDDN returned an error that indicates something about what we sent it was wrong; In files: eddn.py:582; */ +"EDDN Error: Validation Failed (EDMC Too Old?). See Log" = "EDDN Hatası: Doğrulama Başarısız Oldu (EDMC sürümü eski olabilir?). Günlüğe bakın"; + +/* eddn.py: EDDN returned some sort of HTTP error, one we didn't expect. {STATUS} contains a number; In files: eddn.py:587; */ +"EDDN Error: Returned {STATUS} status code" = "EDDN Hatası: {STATUS} durum kodu ile döndü."; + +/* eddn.py: Enable EDDN support for station data checkbox label; In files: eddn.py:2041; */ +"Send station data to the Elite Dangerous Data Network" = "İstasyon verilerini Elite Dangerous Data Network'e gönderin"; + +/* eddn.py: Enable EDDN support for system and other scan data checkbox label; In files: eddn.py:2052; */ +"Send system and scan data to the Elite Dangerous Data Network" = "Sistem ve tarama verilerini Elite Dangerous Data Network'e gönderin"; + +/* eddn.py: EDDN delay sending until docked option is on, this message notes that a send was skipped due to this; In files: eddn.py:2063; */ +"Delay sending until docked" = "Kenetlenmeye kadar gönderimi ertele"; + +/* eddn.py: Killswitch disabled EDDN; In files: eddn.py:2178; */ +"EDDN journal handler disabled. See Log." = "EDDN günlük düzenleyici devre dışı. Kayıt geçmişini kontrol edin."; + +/* eddn.py: Status text shown while attempting to send data; In files: eddn.py:2507; */ +"Sending data to EDDN..." = "Veriler EDDN'e gönderiliyor..."; + +/* edsm.py: Settings>EDSM - Label on header/URL to EDSM API key page; In files: edsm.py:319; */ +"Elite Dangerous Star Map credentials" = "Elite Dangerous Star Map kimlik bilgileri"; + +/* edsm.py: EDSM Commander name label in EDSM settings; In files: edsm.py:341; */ +"Commander Name" = "Cmdr ismi"; + +/* edsm.py: EDSM API key label; inara.py: Inara API key label; In files: edsm.py:350; inara.py:278; */ +"API Key" = "API Anahtarı"; + +/* edsm.py: We have no data on the current commander; prefs.py: No hotkey/shortcut set; stats.py: No rank; In files: edsm.py:394; prefs.py:527; prefs.py:1157; prefs.py:1190; stats.py:154; stats.py:173; stats.py:192; stats.py:209; */ +"None" = "Hiçbiri"; + +/* edsm.py: EDSM plugin - Journal handling disabled by killswitch; In files: edsm.py:516; */ +"EDSM Handler disabled. See Log." = "EDSM düzenleyici devre dışı. Kayıt geçmişini kontrol edin."; + +/* edsm.py: EDSM - Only Live data; In files: edsm.py:632; */ +"EDSM only accepts Live galaxy data" = "EDSM sadece canlı galaxy verilerini kabul eder"; + +/* edsm.py: EDSM Plugin - Error message from EDSM API; In files: edsm.py:916; edsm.py:1048; */ +"Error: EDSM {MSG}" = "Hata: EDSM {MSG}"; + +/* edsm.py: EDSM Plugin - Error connecting to EDSM API; In files: edsm.py:953; edsm.py:1043; */ +"Error: Can't connect to EDSM" = "Hata: EDSM'e bağlanılamıyor"; + +/* inara.py: Checkbox to enable INARA API Usage; In files: inara.py:257; */ +"Send flight log and Cmdr status to Inara" = "Uçuş günlüğünü ve Cmdr durumunu Inara'ya gönder"; + +/* inara.py: Text for INARA API keys link ( goes to https://inara.cz/settings-api ); In files: inara.py:269; */ +"Inara credentials" = "Inara kimlik bilgileri"; + +/* inara.py: The Inara API only accepts Live galaxy data, not Legacy galaxy data; inara.py: Inara - Only Live data; In files: inara.py:384; inara.py:386; */ +"Inara only accepts Live galaxy data" = "Inara sadece canlı galaxy verilerini kabul eder"; + +/* inara.py: INARA support disabled via killswitch; In files: inara.py:395; */ +"Inara disabled. See Log." = "Inara devre dışı. Kayıt geçmişini kontrol edin."; + +/* inara.py: INARA API returned some kind of error (error message will be contained in {MSG}); In files: inara.py:1650; inara.py:1663; */ +"Error: Inara {MSG}" = "Hata: Inara {MSG}"; + +/* prefs.py: File > Preferences menu entry for macOS; In files: prefs.py:237; */ +"Preferences" = "Tercihler"; + +/* prefs.py: Settings > Output - choosing what data to save to files; In files: prefs.py:335; */ +"Please choose what data to save" = "Lütfen hangi verilerin kaydedileceğini seçin"; + +/* prefs.py: Settings > Output option; In files: prefs.py:341; */ +"Market data in CSV format file" = "CSV formatında Market verileri"; + +/* prefs.py: Settings > Output option; In files: prefs.py:350; */ +"Market data in Trade Dangerous format file" = "Trade Dangerous formatında Market verileri"; + +/* prefs.py: Settings > Output option; In files: prefs.py:360; */ +"Ship loadout" = "Gemi Ekipmanları"; + +/* prefs.py: Settings > Output option; In files: prefs.py:370; */ +"Automatically update on docking" = "Kenetlenme sırasında otomatik güncelle"; + +/* prefs.py: Settings > Output - Label for "where files are located"; In files: prefs.py:379; prefs.py:398; */ +"File location" = "Dosya konumu"; + +/* prefs.py: macOS Preferences - files location selection button; In files: prefs.py:387; prefs.py:437; */ +"Change..." = "Değiştir..."; + +/* prefs.py: NOT-macOS Settings - files location selection button; prefs.py: NOT-macOS Setting - files location selection button; In files: prefs.py:390; prefs.py:440; */ +"Browse..." = "Gezin..."; + +/* prefs.py: Label for 'Output' Settings/Preferences tab; In files: prefs.py:405; */ +"Output" = "Kayıt"; + +/* prefs.py: Settings > Configuration - Label for Journal files location; In files: prefs.py:431; prefs.py:446; */ +"E:D journal file location" = "E:D günlük dosya konumu"; + +/* prefs.py: Settings > Configuration - Label for CAPI section; In files: prefs.py:469; */ +"CAPI Settings" = "CAPI ayarları"; + +/* prefs.py: Configuration - Enable or disable the Fleet Carrier CAPI calls; In files: prefs.py:475; */ +"Enable Fleetcarrier CAPI Queries" = "Filo Taşıyıcı CAPI sorgulamalarını etkinleştir"; + +/* prefs.py: Hotkey/Shortcut settings prompt on OSX; In files: prefs.py:490; */ +"Keyboard shortcut" = "Klavye Kısayolu"; + +/* prefs.py: Hotkey/Shortcut settings prompt on Windows; In files: prefs.py:492; */ +"Hotkey" = "Kısayoltuşu"; + +/* prefs.py: macOS Preferences > Configuration - restart the app message; In files: prefs.py:501; */ +"Re-start {APP} to use shortcuts" = "Kısayolları kullanmak için {APP}'i yeniden başlat"; + +/* prefs.py: macOS - Configuration - need to grant the app permission for keyboard shortcuts; In files: prefs.py:510; */ +"{APP} needs permission to use shortcuts" = "{APP}'nin kısayolları kullanabilmesi için izne ihtiyacı var"; + +/* prefs.py: Shortcut settings button on OSX; In files: prefs.py:515; */ +"Open System Preferences" = "Sistem Tercihlerini Aç"; + +/* prefs.py: Configuration - Act on hotkey only when ED is in foreground; In files: prefs.py:538; */ +"Only when Elite: Dangerous is the active app" = "Sadece Elite: Dangerous aktif uygulama olduğunda"; + +/* prefs.py: Configuration - play sound when hotkey used; In files: prefs.py:549; */ +"Play sound" = "Ses çal"; + +/* prefs.py: Configuration - disable checks for app updates when in-game; In files: prefs.py:564; */ +"Disable Automatic Application Updates Check when in-game" = "Otomatik Uygulama Güncellemelerini Oyun sırasında Devre Dışı Bırak"; + +/* prefs.py: Label for preferred shipyard, system and station 'providers'; In files: prefs.py:577; */ +"Preferred websites" = "Tercih edilen web siteleri"; + +/* prefs.py: Label for Shipyard provider selection; In files: prefs.py:588; */ +"Shipyard" = "Tersane"; + +/* prefs.py: Label for checkbox to utilise alternative Coriolis URL method; In files: prefs.py:600; */ +"Use alternate URL method" = "Alternatif URL yöntemi kullan"; + +/* prefs.py: Configuration - Label for selection of Log Level; In files: prefs.py:653; */ +"Log Level" = "Günlük Seviyesi"; + +/* prefs.py: Label for 'Configuration' tab in Settings; In files: prefs.py:681; */ +"Configuration" = "Yapılandırma"; + +/* prefs.py: UI elements privacy section header in privacy tab of preferences; In files: prefs.py:690; */ +"Main UI privacy options" = "Ana Arayüz gizlilik seçenekleri"; + +/* prefs.py: Hide private group owner name from UI checkbox; In files: prefs.py:695; */ +"Hide private group name in UI" = "Özel grup ismini arayüzde gizle"; + +/* prefs.py: Hide multicrew captain name from main UI checkbox; In files: prefs.py:699; */ +"Hide multi-crew captain name" = "Çoklu-mürettebat ismini gizle"; + +/* prefs.py: Preferences privacy tab title; In files: prefs.py:703; */ +"Privacy" = "Gizlilik"; + +/* prefs.py: Label for Settings > Appeareance > selection of 'normal' text colour; In files: prefs.py:716; */ +"Normal text" = "Normal metin"; + +/* prefs.py: Label for Settings > Appeareance > selection of 'highlightes' text colour; In files: prefs.py:718; */ +"Highlighted text" = "Vurgulanan metin"; + +/* prefs.py: Appearance - Label for selection of application display language; In files: prefs.py:727; */ +"Language" = "Dil"; + +/* prefs.py: Label for Settings > Appearance > Theme selection; In files: prefs.py:737; */ +"Theme" = "Tema"; + +/* prefs.py: Label for 'Dark' theme radio button; In files: prefs.py:749; */ +"Dark" = "Karanlık"; + +/* prefs.py: Label for 'Transparent' theme radio button; In files: prefs.py:756; */ +"Transparent" = "Şeffaflık"; + +/* prefs.py: Appearance - Label for selection of UI scaling; In files: prefs.py:802; */ +"UI Scale Percentage" = "Arayüz ölçek yüzdesi"; + +/* prefs.py: Appearance - Help/hint text for UI scaling selection; In files: prefs.py:823; */ +"100 means Default{CR}Restart Required for{CR}changes to take effect!" = "100 Varsayılan değerdir. Değişikliklerin geçerli olması için {CR}Yeniden Başlatma Gereklidir{CR}!"; + +/* prefs.py: Appearance - Label for selection of main window transparency; In files: prefs.py:833; */ +"Main window transparency" = "Ana pencere şeffaflığı"; + +/* prefs.py: Appearance - Help/hint text for Main window transparency selection; In files: prefs.py:853:856; */ +"100 means fully opaque.{CR}Window is updated in real time" = "100 tamamen opak anlamına gelir.{CR}Pencere gerçek zamanlı olarak güncellenir"; + +/* prefs.py: Appearance option for Windows "minimize to system tray"; In files: prefs.py:885; */ +"Minimize to system tray" = "Simge durumuna küçült"; + +/* prefs.py: Label for Settings > Appearance tab; In files: prefs.py:893; */ +"Appearance" = "Görünüm"; + +/* prefs.py: Label for location of third-party plugins folder; In files: prefs.py:908; */ +"Plugins folder" = "Eklentiler klasörü"; + +/* prefs.py: Label on button used to open a filesystem folder; In files: prefs.py:915; */ +"Open" = "Aç"; + +/* prefs.py: Tip/label about how to disable plugins; In files: prefs.py:923; */ +"Tip: You can disable a plugin by{CR}adding '{EXT}' to its folder name" = "İpucu: Bir eklentiyi, klasör adına{CR}'{EXT}' ekleyerek devre dışı bırakabilirsiniz"; + +/* prefs.py: Label on list of enabled plugins; In files: prefs.py:934; */ +"Enabled Plugins" = "Etkin Eklentiler"; + +/* prefs.py: Plugins - Label for list of 'enabled' plugins that don't work with Python 3.x; In files: prefs.py:954; */ +"Plugins Without Python 3.x Support" = "Python 3.x Desteği Olmayan Eklentiler"; + +/* prefs.py: Plugins - Label on URL to documentation about migrating plugins from Python 2.7; In files: prefs.py:962; */ +"Information on migrating plugins" = "Eklentilerin taşınmasıyla ilgili bilgiler"; + +/* prefs.py: Plugins - Label for list of 'broken' plugins that failed to load; In files: prefs.py:1039; */ +"Broken Plugins" = "Bozuk Eklentiler"; + +/* prefs.py: Lable on list of user-disabled plugins; In files: prefs.py:977; */ +"Disabled Plugins" = "Devre Dışı Eklentiler"; + +/* stats.py: Cmdr stats; In files: stats.py:58; */ +"Balance" = "Bakiye"; + +/* stats.py: Cmdr stats; In files: stats.py:59; */ +"Loan" = "Borç"; + +/* stats.py: Top rank; In files: stats.py:63; */ +"Elite" = "Elite"; + +/* stats.py: Top rank +1; In files: stats.py:64; */ +"Elite I" = "Elite I"; + +/* stats.py: Top rank +2; In files: stats.py:65; */ +"Elite II" = "Elite II"; + +/* stats.py: Top rank +3; In files: stats.py:66; */ +"Elite III" = "Elite III"; + +/* stats.py: Top rank +4; In files: stats.py:67; */ +"Elite IV" = "Elite IV"; + +/* stats.py: Top rank +5; In files: stats.py:68; */ +"Elite V" = "Elite V"; + +/* stats.py: Ranking; In files: stats.py:74; */ +"Combat" = "Combat"; + +/* stats.py: Ranking; In files: stats.py:75; */ +"Trade" = "Trade"; + +/* stats.py: Ranking; In files: stats.py:76; */ +"Explorer" = "Explorer"; + +/* stats.py: Ranking; In files: stats.py:77; */ +"Mercenary" = "Mercenary"; + +/* stats.py: Ranking; In files: stats.py:78; */ +"Exobiologist" = "Exobiologist"; + +/* stats.py: Ranking; In files: stats.py:79; */ +"CQC" = "CQC"; + +/* stats.py: Ranking; In files: stats.py:80; */ +"Federation" = "Federation"; + +/* stats.py: Ranking; In files: stats.py:81; */ +"Empire" = "Empire"; + +/* stats.py: Ranking; In files: stats.py:82; */ +"Powerplay" = "Powerplay"; + +/* stats.py: Combat rank; In files: stats.py:91; */ +"Harmless" = "Harmless"; + +/* stats.py: Combat rank; In files: stats.py:92; */ +"Mostly Harmless" = "Mostly Harmless"; + +/* stats.py: Combat rank; In files: stats.py:93; */ +"Novice" = "Novice"; + +/* stats.py: Combat rank; In files: stats.py:94; */ +"Competent" = "Competent"; + +/* stats.py: Combat rank; In files: stats.py:95; */ +"Expert" = "Expert"; + +/* stats.py: Combat rank; stats.py: Empire rank; In files: stats.py:96; stats.py:176; */ +"Master" = "Master"; + +/* stats.py: Combat rank; In files: stats.py:97; */ +"Dangerous" = "Dangerous"; + +/* stats.py: Combat rank; In files: stats.py:98; */ +"Deadly" = "Deadly"; + +/* stats.py: Trade rank; In files: stats.py:101; */ +"Penniless" = "Penniless"; + +/* stats.py: Trade rank; In files: stats.py:102; */ +"Mostly Penniless" = "Mostly Penniless"; + +/* stats.py: Trade rank; In files: stats.py:103; */ +"Peddler" = "Peddler"; + +/* stats.py: Trade rank; In files: stats.py:104; */ +"Dealer" = "Dealer"; + +/* stats.py: Trade rank; In files: stats.py:105; */ +"Merchant" = "Merchant"; + +/* stats.py: Trade rank; In files: stats.py:106; */ +"Broker" = "Broker"; + +/* stats.py: Trade rank; In files: stats.py:107; */ +"Entrepreneur" = "Entrepreneur"; + +/* stats.py: Trade rank; In files: stats.py:108; */ +"Tycoon" = "Tycoon"; + +/* stats.py: Explorer rank; In files: stats.py:111; */ +"Aimless" = "Aimless"; + +/* stats.py: Explorer rank; In files: stats.py:112; */ +"Mostly Aimless" = "Mostly Aimless"; + +/* stats.py: Explorer rank; In files: stats.py:113; */ +"Scout" = "Scout"; + +/* stats.py: Explorer rank; In files: stats.py:114; */ +"Surveyor" = "Surveyor"; + +/* stats.py: Explorer rank; In files: stats.py:115; */ +"Trailblazer" = "Trailblazer"; + +/* stats.py: Explorer rank; In files: stats.py:116; */ +"Pathfinder" = "Pathfinder"; + +/* stats.py: Explorer rank; In files: stats.py:117; */ +"Ranger" = "Ranger"; + +/* stats.py: Explorer rank; In files: stats.py:118; */ +"Pioneer" = "Pioneer"; + +/* stats.py: Mercenary rank; In files: stats.py:122; */ +"Defenceless" = "Defenceless"; + +/* stats.py: Mercenary rank; In files: stats.py:123; */ +"Mostly Defenceless" = "Mostly Defenceless"; + +/* stats.py: Mercenary rank; In files: stats.py:124; */ +"Rookie" = "Rookie"; + +/* stats.py: Mercenary rank; In files: stats.py:125; */ +"Soldier" = "Soldier"; + +/* stats.py: Mercenary rank; In files: stats.py:126; stats.py:128; */ +"Gunslinger" = "Gunslinger"; + +/* stats.py: Mercenary rank; In files: stats.py:127; */ +"Warrior" = "Warrior"; + +/* stats.py: Mercenary rank; In files: stats.py:129; */ +"Deadeye" = "Deadeye"; + +/* stats.py: Exobiologist rank; In files: stats.py:132; */ +"Directionless" = "Directionless"; + +/* stats.py: Exobiologist rank; In files: stats.py:133; */ +"Mostly Directionless" = "Mostly Directionless"; + +/* stats.py: Exobiologist rank; In files: stats.py:134; */ +"Compiler" = "Compiler"; + +/* stats.py: Exobiologist rank; In files: stats.py:135; */ +"Collector" = "Collector"; + +/* stats.py: Exobiologist rank; In files: stats.py:136; */ +"Cataloguer" = "Cataloguer"; + +/* stats.py: Exobiologist rank; In files: stats.py:137; */ +"Taxonomist" = "Taxonomist"; + +/* stats.py: Exobiologist rank; In files: stats.py:138; */ +"Ecologist" = "Ecologist"; + +/* stats.py: Exobiologist rank; In files: stats.py:139; */ +"Geneticist" = "Geneticist"; + +/* stats.py: CQC rank; In files: stats.py:142; */ +"Helpless" = "Helpless"; + +/* stats.py: CQC rank; In files: stats.py:143; */ +"Mostly Helpless" = "Mostly Helpless"; + +/* stats.py: CQC rank; In files: stats.py:144; */ +"Amateur" = "Amateur"; + +/* stats.py: CQC rank; In files: stats.py:145; */ +"Semi Professional" = "Semi Professional"; + +/* stats.py: CQC rank; In files: stats.py:146; */ +"Professional" = "Professional"; + +/* stats.py: CQC rank; In files: stats.py:147; */ +"Champion" = "Champion"; + +/* stats.py: CQC rank; In files: stats.py:148; */ +"Hero" = "Hero"; + +/* stats.py: CQC rank; In files: stats.py:149; */ +"Gladiator" = "Gladiator"; + +/* stats.py: Federation rank; In files: stats.py:155; */ +"Recruit" = "Recruit"; + +/* stats.py: Federation rank; In files: stats.py:156; */ +"Cadet" = "Cadet"; + +/* stats.py: Federation rank; In files: stats.py:157; */ +"Midshipman" = "Midshipman"; + +/* stats.py: Federation rank; In files: stats.py:158; */ +"Petty Officer" = "Petty Officer"; + +/* stats.py: Federation rank; In files: stats.py:159; */ +"Chief Petty Officer" = "Chief Petty Officer"; + +/* stats.py: Federation rank; In files: stats.py:160; */ +"Warrant Officer" = "Warrant Officer"; + +/* stats.py: Federation rank; In files: stats.py:161; */ +"Ensign" = "Ensign"; + +/* stats.py: Federation rank; In files: stats.py:162; */ +"Lieutenant" = "Lieutenant"; + +/* stats.py: Federation rank; In files: stats.py:163; */ +"Lieutenant Commander" = "Lieutenant Commander"; + +/* stats.py: Federation rank; In files: stats.py:164; */ +"Post Commander" = "Post Commander"; + +/* stats.py: Federation rank; In files: stats.py:165; */ +"Post Captain" = "Post Captain"; + +/* stats.py: Federation rank; In files: stats.py:166; */ +"Rear Admiral" = "Rear Admiral"; + +/* stats.py: Federation rank; In files: stats.py:167; */ +"Vice Admiral" = "Vice Admiral"; + +/* stats.py: Federation rank; In files: stats.py:168; */ +"Admiral" = "Admiral"; + +/* stats.py: Empire rank; In files: stats.py:174; */ +"Outsider" = "Outsider"; + +/* stats.py: Empire rank; In files: stats.py:175; */ +"Serf" = "Serf"; + +/* stats.py: Empire rank; In files: stats.py:177; */ +"Squire" = "Squire"; + +/* stats.py: Empire rank; In files: stats.py:178; */ +"Knight" = "Knight"; + +/* stats.py: Empire rank; In files: stats.py:179; */ +"Lord" = "Lord"; + +/* stats.py: Empire rank; In files: stats.py:180; */ +"Baron" = "Baron"; + +/* stats.py: Empire rank; In files: stats.py:181; */ +"Viscount" = "Viscount"; + +/* stats.py: Empire rank; In files: stats.py:182; */ +"Count" = "Count"; + +/* stats.py: Empire rank; In files: stats.py:183; */ +"Earl" = "Earl"; + +/* stats.py: Empire rank; In files: stats.py:184; */ +"Marquis" = "Marquis"; + +/* stats.py: Empire rank; In files: stats.py:185; */ +"Duke" = "Duke"; + +/* stats.py: Empire rank; In files: stats.py:186; */ +"Prince" = "Prince"; + +/* stats.py: Empire rank; In files: stats.py:187; */ +"King" = "King"; + +/* stats.py: Power rank; In files: stats.py:193; */ +"Rating 1" = "Reyting 1"; + +/* stats.py: Power rank; In files: stats.py:194; */ +"Rating 2" = "Reyting 2"; + +/* stats.py: Power rank; In files: stats.py:195; */ +"Rating 3" = "Reyting 3"; + +/* stats.py: Power rank; In files: stats.py:196; */ +"Rating 4" = "Reyting 4"; + +/* stats.py: Power rank; In files: stats.py:197; */ +"Rating 5" = "Reyting 5"; + +/* stats.py: Current commander unknown when trying to use 'File' > 'Status'; In files: stats.py:315; */ +"Status: Don't yet know your Commander name" = "Durum: Cmdr adınızı henüz bilmiyorum"; + +/* stats.py: No Frontier CAPI data yet when trying to use 'File' > 'Status'; In files: stats.py:323; */ +"Status: No CAPI data yet" = "Durum: Henüz CAPI verisi yok"; + +/* stats.py: Status dialog subtitle - CR value of ship; In files: stats.py:409; */ +"Value" = "Değer"; + +/* stats.py: Status dialog title; In files: stats.py:418; */ +"Ships" = "Gemiler"; + +/* update.py: Update Available Text; In files: update.py:229; */ +"{NEWVER} is available" = "{NEWVER} sürüm mevcut"; diff --git a/L10n/zh-Hans.strings b/L10n/zh-Hans.strings index 2b9eb75d..03e263dd 100644 --- a/L10n/zh-Hans.strings +++ b/L10n/zh-Hans.strings @@ -226,13 +226,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "默认"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "自动"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "普通版"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "测试版"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/requirements.txt b/requirements.txt index 398041a1..b6a7482f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ -certifi==2023.11.17 +certifi==2024.2.2 requests==2.31.0 # requests depends on this now ? -charset-normalizer==2.1.1 +charset-normalizer==3.3.2 watchdog==3.0.0 # Commented out because this doesn't package well with py2exe From 674413b36f50deb76466fd0822c2b12ec325a3f9 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Mon, 15 Apr 2024 16:51:43 -0400 Subject: [PATCH 45/49] Update Version String and Changelog --- ChangeLog.md | 24 ++++++++++++++++++++++++ config/__init__.py | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 6ee5749f..949b6bf8 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -6,6 +6,30 @@ This is the master changelog for Elite Dangerous Market Connector. Entries are in the source (not distributed with the Windows installer) for the currently used version. --- +Release 5.10.4 +=== +This release contains updated dependencies, modules files, translations, and adds two new EDDN schemas. It also +adds Turkish translations to EDMC! + +We now sign our code! This does mean that built EXEs are now slightly modified on our developer's machines. +For information on what this means, and opt-out options, please visit https://github.com/EDCD/EDMarketConnector/wiki/Code-Signing-and-EDMC + +**Changes and Enhancements** +* Adds Turkish Translations to EDMC +* Adds DockingDenied and DockingGranted EDDN Schemas +* Updated FDevIDs Dependency +* Updated Translations +* Updated modules files to process several missing module types used for bug squishing or going fast +* Updated Python Dependencies + +**Bug Fixes** +* Fixed a bug on older Python versions which couldn't import updated type annotations + +**Plugin Developers** +* modules.p and ships.p are deprecated, and slated for removal in 5.11+! +* The `openurl()` function in ttkHyperlinkLabel has been deprecated, +and slated for removal in 5.11+! Please migrate to `webbrowser.open()`. + Release 5.10.3 === This release contains a bugfix for the shipyard outfitting parsing system and an update to the French translations. diff --git a/config/__init__.py b/config/__init__.py index d85956a7..27d9b450 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -53,7 +53,7 @@ appcmdname = 'EDMC' # <https://semver.org/#semantic-versioning-specification-semver> # Major.Minor.Patch(-prerelease)(+buildmetadata) # NB: Do *not* import this, use the functions appversion() and appversion_nobuild() -_static_appversion = '5.11.0-alpha0' +_static_appversion = '5.10.4' _cached_version: semantic_version.Version | None = None copyright = '© 2015-2019 Jonathan Harris, 2020-2024 EDCD' From 3b2f37f868df1116253142ddfb68451bde4dc6a5 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Mon, 15 Apr 2024 16:51:43 -0400 Subject: [PATCH 46/49] Update Version String and Changelog --- ChangeLog.md | 24 ++++++++++++++++++++++++ config/__init__.py | 3 +-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 6ee5749f..949b6bf8 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -6,6 +6,30 @@ This is the master changelog for Elite Dangerous Market Connector. Entries are in the source (not distributed with the Windows installer) for the currently used version. --- +Release 5.10.4 +=== +This release contains updated dependencies, modules files, translations, and adds two new EDDN schemas. It also +adds Turkish translations to EDMC! + +We now sign our code! This does mean that built EXEs are now slightly modified on our developer's machines. +For information on what this means, and opt-out options, please visit https://github.com/EDCD/EDMarketConnector/wiki/Code-Signing-and-EDMC + +**Changes and Enhancements** +* Adds Turkish Translations to EDMC +* Adds DockingDenied and DockingGranted EDDN Schemas +* Updated FDevIDs Dependency +* Updated Translations +* Updated modules files to process several missing module types used for bug squishing or going fast +* Updated Python Dependencies + +**Bug Fixes** +* Fixed a bug on older Python versions which couldn't import updated type annotations + +**Plugin Developers** +* modules.p and ships.p are deprecated, and slated for removal in 5.11+! +* The `openurl()` function in ttkHyperlinkLabel has been deprecated, +and slated for removal in 5.11+! Please migrate to `webbrowser.open()`. + Release 5.10.3 === This release contains a bugfix for the shipyard outfitting parsing system and an update to the French translations. diff --git a/config/__init__.py b/config/__init__.py index 3acb2edd..1dfe26c3 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -54,8 +54,7 @@ appcmdname = 'EDMC' # <https://semver.org/#semantic-versioning-specification-semver> # Major.Minor.Patch(-prerelease)(+buildmetadata) # NB: Do *not* import this, use the functions appversion() and appversion_nobuild() -_static_appversion = '5.10.3' - +_static_appversion = '5.10.4' _cached_version: semantic_version.Version | None = None copyright = '© 2015-2019 Jonathan Harris, 2020-2024 EDCD' From 1f90ca94092012aa35078a5f0bcb06a4deabbfbf Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Mon, 15 Apr 2024 21:48:30 -0400 Subject: [PATCH 47/49] [Translations] Update Translation Files --- L10n/cs.strings | 6 +- L10n/de.strings | 20 +- L10n/es.strings | 6 +- L10n/it.strings | 20 +- L10n/ja.strings | 6 +- L10n/ko.strings | 6 +- L10n/pl.strings | 6 +- L10n/pt-BR.strings | 6 +- L10n/pt-PT.strings | 6 +- L10n/ru.strings | 35 +- L10n/sr-Latn-BA.strings | 6 +- L10n/sr-Latn.strings | 20 +- L10n/tr.strings | 805 ++++++++++++++++++++++++++++++++++++++++ L10n/zh-Hans.strings | 6 +- 14 files changed, 915 insertions(+), 39 deletions(-) create mode 100644 L10n/tr.strings diff --git a/L10n/cs.strings b/L10n/cs.strings index ba11dc39..071b5e69 100644 --- a/L10n/cs.strings +++ b/L10n/cs.strings @@ -178,13 +178,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Výchozí"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normal"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/de.strings b/L10n/de.strings index 2b7c72c4..be36b877 100644 --- a/L10n/de.strings +++ b/L10n/de.strings @@ -231,6 +231,18 @@ /* 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." = "Eins oder mehr deiner aktivierten Plugins konnte nicht geladen werden. Du kannst dir die Liste im '{PLUGINS}'-Tab unter '{FILE}' > '{SETTINGS}' ansehen. Dies könnte an einer falschen Ordnerstruktur liegen. Die Datei load.py sollte sich unter plugins/PLUGIN_NAME/load.py befinden.\n\nDu kannst ein Plugin deaktivieren, indem du dessen Ordner ein '{DISABLED}' am Ende des Namens anhängst."; +/* 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" = "Einer oder mehrere deiner URL-Anbieter waren ungültig und wurden zurückgesetzt:\n\n"; + +/* 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} war zuvor auf {OLDPROV} festgelegt und wurde zu {NEWPROV} zurückgesetzt.\n"; + +/* EDMarketConnector.py: Popup window title for Reset Providers; In files: EDMarketConnector.py:2161; */ +"EDMC: Default Providers Reset" = "EDMC: Standardanbieter wurden zurückgesetzt"; + +/* EDMarketConnector.py: Await Full CMDR Login to Game; In files: EDMarketConnector.py:813; */ +"Awaiting Full CMDR Login" = "Warte auf vollständige CMDR Anmeldung"; + /* journal_lock.py: Title text on popup when Journal directory already locked; In files: journal_lock.py:208; */ "Journal directory already locked" = "Journal-Ordner bereits gesperrt"; @@ -246,13 +258,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Standard"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normal"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ @@ -768,3 +780,5 @@ /* stats.py: Status dialog title; In files: stats.py:418; */ "Ships" = "Schiffe"; +/* update.py: Update Available Text; In files: update.py:229; */ +"{NEWVER} is available" = "{NEWVER} ist verfügbar"; diff --git a/L10n/es.strings b/L10n/es.strings index d2cb7b4b..18874ccf 100644 --- a/L10n/es.strings +++ b/L10n/es.strings @@ -184,13 +184,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Por defecto"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normal"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/it.strings b/L10n/it.strings index e5f6ece6..c1cd9b33 100644 --- a/L10n/it.strings +++ b/L10n/it.strings @@ -231,6 +231,18 @@ /* 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." = "Impossibile caricare uno o più plugin abilitati. Consulta l'elenco nella scheda '{PLUGINS}' di '{FILE}' > '{SETTINGS}'. Ciò potrebbe essere causato da un'errata struttura delle cartelle. Il file load.py dovrebbe trovarsi in plugins/PLUGIN_NAME/load.py.\n\nPuoi disabilitare un plugin rinominando la sua cartella in modo che abbia '{DISABLED}' alla fine del nome."; +/* 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" = "Uno o più Provider URL non erano validi e sono stati ripristinati:\n"; + +/* 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} era impostato su {OLDPROV} ed è stato reimpostato su {NEWPROV}\n"; + +/* EDMarketConnector.py: Popup window title for Reset Providers; In files: EDMarketConnector.py:2161; */ +"EDMC: Default Providers Reset" = "EDMC: Reset dei provider predefiniti"; + +/* EDMarketConnector.py: Await Full CMDR Login to Game; In files: EDMarketConnector.py:813; */ +"Awaiting Full CMDR Login" = "In attesa del login completo al CMDR"; + /* journal_lock.py: Title text on popup when Journal directory already locked; In files: journal_lock.py:208; */ "Journal directory already locked" = "cartella Journal già bloccata"; @@ -246,13 +258,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Predefinito"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normale"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ @@ -789,3 +801,5 @@ /* stats.py: Status dialog title; In files: stats.py:418; */ "Ships" = "Navi"; +/* update.py: Update Available Text; In files: update.py:229; */ +"{NEWVER} is available" = "{NEWVER} è disponibile"; diff --git a/L10n/ja.strings b/L10n/ja.strings index 68a9fd34..82d9f8df 100644 --- a/L10n/ja.strings +++ b/L10n/ja.strings @@ -246,13 +246,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "デフォルト"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "自動"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "通常版"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "ベータ版"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/ko.strings b/L10n/ko.strings index 577695b0..e29ad74f 100644 --- a/L10n/ko.strings +++ b/L10n/ko.strings @@ -202,13 +202,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "기본값"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "자동"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "일반"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "베타"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/pl.strings b/L10n/pl.strings index 72a66718..547406b1 100644 --- a/L10n/pl.strings +++ b/L10n/pl.strings @@ -234,13 +234,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Domyślne"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normalny"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/pt-BR.strings b/L10n/pt-BR.strings index e719101a..605e0559 100644 --- a/L10n/pt-BR.strings +++ b/L10n/pt-BR.strings @@ -234,13 +234,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Padrão"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Automático"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normal"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/pt-PT.strings b/L10n/pt-PT.strings index ea292b14..0fd5b585 100644 --- a/L10n/pt-PT.strings +++ b/L10n/pt-PT.strings @@ -246,13 +246,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Predefinido"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normal"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/ru.strings b/L10n/ru.strings index c3c0fae1..19449e21 100644 --- a/L10n/ru.strings +++ b/L10n/ru.strings @@ -213,12 +213,36 @@ /* 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." = "Один или несколько ваших подключённых плагинов ещё не имеют поддержки Python 3.x. Пожалуйста, ознакомьтесь со списком во вкладке '{PLUGINS}' '{FILE}' > '{SETTINGS}'. Вы должны проверить наличие обновлённой версии, в противном случае предупредите разработчика о необходимости обновления кода на Python 3.x.\n\nВы можете отключить плагин, переименовав его папку в '{DISABLED}'."; +/* EDMarketConnector.py: Popup-text about missing FDEVID Files; In files: EDMarketConnector.py:2329; */ +"FDevID Files not found! Some functionality regarding commodities may be disabled.\r\n\r\n Do you want to open the Wiki page on how to set up submodules?" = "FDevID файлы не найдены! Некоторые функции, связанные с товарами, могут быть отключены.\n\nВы хотите открыть страницу Wiki о том, как настроить вспомогательные модули?"; + +/* EDMarketConnector.py: Popup window title for missing FDEVID files; In files: EDMarketConnector.py:2340; */ +"FDevIDs: Missing Commodity Files" = "FDevIDs: отсутствуют файлы товаров"; + /* EDMarketConnector.py: Settings > Plugins tab; prefs.py: Label on Settings > Plugins tab; In files: EDMarketConnector.py:2263; prefs.py:986; */ "Plugins" = "Плагины"; /* EDMarketConnector.py: Popup window title for list of 'enabled' plugins that don't work with Python 3.x; In files: EDMarketConnector.py:2274; */ "EDMC: Plugins Without Python 3.x Support" = "EDMC: Без поддержки Python 3.x"; +/* EDMarketConnector.py: Popup window title for list of 'broken' plugins that failed to load; In files: EDMarketConnector.py:2285; */ +"EDMC: Broken Plugins" = "EDMC: Неработающие плагины"; + +/* 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." = "Не удалось загрузить один или несколько включенных плагинов. Пожалуйста, посмотрите список на вкладке '{PLUGINS}' в разделе '{FILE}' > '{SETTINGS}'. Причиной может быть неправильная структура папок. Файл load.py должен находиться в папке plugins/PLUGIN_NAME/load.py.\n\nВы можете отключить плагин, переименовав его папку так, чтобы в конце названия стояло '{DISABLED}'."; + +/* 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" = "Один или несколько ваших URL-провайдеров оказались некорректными и были сброшены:"; + +/* 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} был установлен на {OLDPROV} и был сброшен на {NEWPROV}"; + +/* EDMarketConnector.py: Popup window title for Reset Providers; In files: EDMarketConnector.py:2161; */ +"EDMC: Default Providers Reset" = "EDMC: сброс провайдеров по умолчанию"; + +/* EDMarketConnector.py: Await Full CMDR Login to Game; In files: EDMarketConnector.py:813; */ +"Awaiting Full CMDR Login" = "Ожидание полного входа в систему"; + /* journal_lock.py: Title text on popup when Journal directory already locked; In files: journal_lock.py:208; */ "Journal directory already locked" = "Каталог журнала уже заблокирован"; @@ -234,13 +258,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "По умолчанию"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Автоматический"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Стандартный"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Бета"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ @@ -471,6 +495,9 @@ /* prefs.py: Plugins - Label on URL to documentation about migrating plugins from Python 2.7; In files: prefs.py:962; */ "Information on migrating plugins" = "Информация о мигрирующих плагинах"; +/* prefs.py: Plugins - Label for list of 'broken' plugins that failed to load; In files: prefs.py:1039; */ +"Broken Plugins" = "Неработающие плагины"; + /* prefs.py: Lable on list of user-disabled plugins; In files: prefs.py:977; */ "Disabled Plugins" = "Отключенные плагины"; @@ -774,3 +801,5 @@ /* stats.py: Status dialog title; In files: stats.py:418; */ "Ships" = "Корабли"; +/* update.py: Update Available Text; In files: update.py:229; */ +"{NEWVER} is available" = "{NEWVER} доступен"; diff --git a/L10n/sr-Latn-BA.strings b/L10n/sr-Latn-BA.strings index 2950f8b8..f541416a 100644 --- a/L10n/sr-Latn-BA.strings +++ b/L10n/sr-Latn-BA.strings @@ -246,13 +246,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Standardna"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Automatski"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normalni"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ diff --git a/L10n/sr-Latn.strings b/L10n/sr-Latn.strings index 83da541a..e801d067 100644 --- a/L10n/sr-Latn.strings +++ b/L10n/sr-Latn.strings @@ -231,6 +231,18 @@ /* 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." = "Jedan ili više vaših aktivnih pluginova se nije učitao. Molimo pogledajte listu na '{PLUGINS}' tabu u okviru '{FILE}' > '{SETTINGS}'. Obo vi moglo da se desi zbog pogrešne strukture foldera. load.py fajl bi trebao da se nalazi unutar plugins/PLUGIN_NAME/load.py.\n\nPojedinačni plugin možete deaktivirati promenom imena njegovog foldera dodavanjem '{DISABLED}' na kraju."; +/* 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" = "Jedan ili više vaših URL Provajdera su pogrešni, pa su resetovani:\n"; + +/* 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} je bio postavljen na {OLDPROV} i sada je resetovan na {NEWPROV}\n"; + +/* EDMarketConnector.py: Popup window title for Reset Providers; In files: EDMarketConnector.py:2161; */ +"EDMC: Default Providers Reset" = "EDMC: Podrazumevani Provajderi resetovani"; + +/* EDMarketConnector.py: Await Full CMDR Login to Game; In files: EDMarketConnector.py:813; */ +"Awaiting Full CMDR Login" = "Čekam da se CMDR potpuno uloguje"; + /* journal_lock.py: Title text on popup when Journal directory already locked; In files: journal_lock.py:208; */ "Journal directory already locked" = "Žurnal direktorijum je već zaključan"; @@ -246,13 +258,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "Podrazumevano"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "Auto"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "Normal"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "Beta"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ @@ -789,3 +801,5 @@ /* stats.py: Status dialog title; In files: stats.py:418; */ "Ships" = "Brodovi"; +/* update.py: Update Available Text; In files: update.py:229; */ +"{NEWVER} is available" = "{NEWVER} je dostupna"; diff --git a/L10n/tr.strings b/L10n/tr.strings new file mode 100644 index 00000000..9d37dfa1 --- /dev/null +++ b/L10n/tr.strings @@ -0,0 +1,805 @@ +/* edsm.py:Settings>EDSM - Label on checkbox for 'send data'; In files: edsm.py:316; */ +"Send flight log and CMDR status to EDSM" = "Uçuş günlüğünü ve CMDR durumunu EDSM'e gönder"; + +/* prefs.py:Label on button used to open a filesystem folder; In files: prefs.py:706; */ +"Open Log Folder" = "Günlük Klasörünü Aç"; + +/* inara.py:Text Inara Show API key; In files: inara.py:305; */ +"Show API Key" = "API Anahtarını Göster"; +/* Language name */ +"!Language" = "Türkçe"; + +/* companion.py: Frontier CAPI didn't respond; In files: companion.py:226; */ +"Error: Frontier CAPI didn't respond" = "Hata: Frontier CAPI yanıt vermedi"; + +/* companion.py: Frontier CAPI data doesn't agree with latest Journal game location; In files: companion.py:245; */ +"Error: Frontier server is lagging" = "Hata: Frontier sunucusu gecikmesi"; + +/* companion.py: Commander is docked at an EDO settlement, got out and back in, we forgot the station; In files: companion.py:261; */ +"Docked but unknown station: EDO Settlement?" = "Kenetlendi ancak bilinmeyen istasyon: EDO yerleşimi?"; + +/* companion.py: Generic "something went wrong with Frontier Auth" error; In files: companion.py:271; */ +"Error: Invalid Credentials" = "Hata: Geçersiz Kimlik"; + +/* companion.py: Frontier CAPI authorisation not for currently game-active commander; In files: companion.py:296; */ +"Error: Wrong Cmdr" = "Hata: Yanlış CMDR"; + +/* companion.py: Generic error prefix - following text is from Frontier auth service; In files: companion.py:432; companion.py:517; */ +"Error" = "Hata"; + +/* companion.py: Frontier auth, no 'usr' section in returned data; companion.py: Frontier auth, no 'customer_id' in 'usr' section in returned data; In files: companion.py:475; companion.py:480; */ +"Error: Couldn't check token customer_id" = "Hata: token kontrol edilemedi customer_id"; + +/* companion.py: Frontier auth customer_id doesn't match game session FID; In files: companion.py:486; */ +"Error: customer_id doesn't match!" = "Hata: customer_id uyuşmuyor!"; + +/* companion.py: Failed to get Access Token from Frontier Auth service; In files: companion.py:508; */ +"Error: unable to get token" = "Hata: token erişilemedi"; + +/* companion.py: Frontier CAPI returned 418, meaning down for maintenance; In files: companion.py:844; */ +"Frontier CAPI down for maintenance" = "Frontier CAPI bakım için kapalı durumda"; + +/* companion.py: Frontier CAPI data retrieval failed; In files: companion.py:856; */ +"Frontier CAPI query failure" = "Frontier CAPI sorgulama hatası"; + +/* EDMarketConnector.py: Main UI Update button; EDMarketConnector.py: Update button in main window; In files: EDMarketConnector.py:601; EDMarketConnector.py:919; EDMarketConnector.py:1748; */ +"Update" = "Güncelle"; + +/* EDMarketConnector.py: Appearance - Label for checkbox to select if application always on top; prefs.py: Appearance - Label for checkbox to select if application always on top; In files: EDMarketConnector.py:710; prefs.py:875; */ +"Always on top" = "Her zaman üstte"; + +/* EDMarketConnector.py: Unknown suit; In files: EDMarketConnector.py:837; */ +"Unknown" = "Bilinmeyen"; + +/* EDMarketConnector.py: ED Journal file location appears to be in error; In files: EDMarketConnector.py:906; */ +"Error: Check E:D journal file location" = "Hata: E:D günlük dosyası konumunu kontrol edin"; + +/* EDMarketConnector.py: Label for commander name in main window; edsm.py: Game Commander name label in EDSM settings; stats.py: Cmdr stats; theme.py: Label for commander name in main window; In files: EDMarketConnector.py:913; edsm.py:332; stats.py:57; theme.py:290; */ +"Cmdr" = "Cmdr"; + +/* EDMarketConnector.py: 'Ship' or multi-crew role label in main window, as applicable; EDMarketConnector.py: Multicrew role label in main window; In files: EDMarketConnector.py:915; EDMarketConnector.py:1487; */ +"Role" = "Rol"; + +/* EDMarketConnector.py: 'Ship' or multi-crew role label in main window, as applicable; EDMarketConnector.py: 'Ship' label in main UI; stats.py: Status dialog subtitle; In files: EDMarketConnector.py:915; EDMarketConnector.py:1497; EDMarketConnector.py:1520; stats.py:405; */ +"Ship" = "Gemi"; + +/* EDMarketConnector.py: Label for 'Suit' line in main UI; In files: EDMarketConnector.py:916; */ +"Suit" = "Süit"; + +/* EDMarketConnector.py: Label for 'System' line in main UI; prefs.py: Configuration - Label for selection of 'System' provider website; stats.py: Main window; In files: EDMarketConnector.py:917; prefs.py:614; stats.py:407; */ +"System" = "Sistem"; + +/* EDMarketConnector.py: Label for 'Station' line in main UI; prefs.py: Configuration - Label for selection of 'Station' provider website; prefs.py: Appearance - Example 'Normal' text; stats.py: Status dialog subtitle; In files: EDMarketConnector.py:918; prefs.py:632; prefs.py:770; stats.py:408; */ +"Station" = "İstasyon"; + +/* EDMarketConnector.py: 'File' menu title on OSX; EDMarketConnector.py: 'File' menu title; EDMarketConnector.py: 'File' menu; In files: EDMarketConnector.py:921; EDMarketConnector.py:939; EDMarketConnector.py:942; EDMarketConnector.py:2264; */ +"File" = "Dosya"; + +/* EDMarketConnector.py: 'Edit' menu title on OSX; EDMarketConnector.py: 'Edit' menu title; In files: EDMarketConnector.py:922; EDMarketConnector.py:940; EDMarketConnector.py:943; */ +"Edit" = "Düzenle"; + +/* EDMarketConnector.py: 'View' menu title on OSX; In files: EDMarketConnector.py:923; */ +"View" = "Görüntüle"; + +/* EDMarketConnector.py: 'Window' menu title on OSX; In files: EDMarketConnector.py:924; */ +"Window" = "Pencere"; + +/* EDMarketConnector.py: Help' menu title on OSX; EDMarketConnector.py: 'Help' menu title; In files: EDMarketConnector.py:925; EDMarketConnector.py:941; EDMarketConnector.py:944; */ +"Help" = "Yardım"; + +/* EDMarketConnector.py: App menu entry on OSX; EDMarketConnector.py: Help > About App; In files: EDMarketConnector.py:928; EDMarketConnector.py:959; EDMarketConnector.py:1804; */ +"About {APP}" = "Hakkında {APP}"; + +/* EDMarketConnector.py: Help > Check for Updates...; In files: EDMarketConnector.py:930; EDMarketConnector.py:958; */ +"Check for Updates..." = "Güncellemeleri Denetle..."; + +/* EDMarketConnector.py: File > Save Raw Data...; In files: EDMarketConnector.py:931; EDMarketConnector.py:948; */ +"Save Raw Data..." = "Ham Verileri Kaydet..."; + +/* EDMarketConnector.py: File > Status; stats.py: Status dialog title; In files: EDMarketConnector.py:932; EDMarketConnector.py:947; stats.py:402; */ +"Status" = "Durum"; + +/* EDMarketConnector.py: Help > Documentation; In files: EDMarketConnector.py:933; EDMarketConnector.py:953; */ +"Documentation" = "Dokümantasyon"; + +/* EDMarketConnector.py: Help > Troubleshooting; In files: EDMarketConnector.py:934; EDMarketConnector.py:954; */ +"Troubleshooting" = "Sorun giderme"; + +/* EDMarketConnector.py: Help > Report A Bug; In files: EDMarketConnector.py:935; EDMarketConnector.py:955; */ +"Report A Bug" = "Hata Bildir"; + +/* EDMarketConnector.py: Help > Privacy Policy; In files: EDMarketConnector.py:936; EDMarketConnector.py:956; */ +"Privacy Policy" = "Gizlilik Politikası"; + +/* EDMarketConnector.py: Help > Release Notes; In files: EDMarketConnector.py:937; EDMarketConnector.py:957; EDMarketConnector.py:1838; */ +"Release Notes" = "Sürüm notları"; + +/* EDMarketConnector.py: File > Settings; prefs.py: File > Settings (macOS); In files: EDMarketConnector.py:949; EDMarketConnector.py:2265; prefs.py:241; */ +"Settings" = "Ayarlar"; + +/* EDMarketConnector.py: File > Exit; In files: EDMarketConnector.py:950; */ +"Exit" = "Çıkış"; + +/* EDMarketConnector.py: Label for 'Copy' as in 'Copy and Paste'; ttkHyperlinkLabel.py: Label for 'Copy' as in 'Copy and Paste'; In files: EDMarketConnector.py:962; ttkHyperlinkLabel.py:53; */ +"Copy" = "Kopyala"; + +/* EDMarketConnector.py: CAPI auth aborted because of killswitch; EDMarketConnector.py: CAPI auth query aborted because of killswitch; In files: EDMarketConnector.py:973; EDMarketConnector.py:1067; */ +"CAPI auth disabled by killswitch" = "CAPI kimlik doğrulaması killswitch tarafından devre dışı bırakıldı"; + +/* EDMarketConnector.py: Status - Attempting to get a Frontier Auth Access Token; In files: EDMarketConnector.py:978; */ +"Logging in..." = "Giriş yapılıyor..."; + +/* EDMarketConnector.py: Successfully authenticated with the Frontier website; In files: EDMarketConnector.py:994; EDMarketConnector.py:1657; */ +"Authentication successful" = "Kimlik doğrulama başarılı"; + +/* EDMarketConnector.py: Player is not docked at a station, when we expect them to be; In files: EDMarketConnector.py:1025; */ +"You're not docked at a station!" = "Bir istasyona kenetli değilsiniz!"; + +/* EDMarketConnector.py: Status - Either no market or no modules data for station from Frontier CAPI; In files: EDMarketConnector.py:1033; */ +"Station doesn't have anything!" = "İstasyon içeriği mevcut değil."; + +/* EDMarketConnector.py: Status - No station market data from Frontier CAPI; In files: EDMarketConnector.py:1038; */ +"Station doesn't have a market!" = "İstasyon'da market bulunmuyor!"; + +/* EDMarketConnector.py: CAPI queries aborted because Cmdr name is unknown; EDMarketConnector.py: CAPI fleetcarrier query aborted because Cmdr name is unknown; In files: EDMarketConnector.py:1077; EDMarketConnector.py:1164; */ +"CAPI query aborted: Cmdr name unknown" = "CAPI sorgusu iptal edildi: Cmdr adı bilinmiyor"; + +/* EDMarketConnector.py: CAPI queries aborted because game mode unknown; In files: EDMarketConnector.py:1083; */ +"CAPI query aborted: Game mode unknown" = "CAPI sorgusu iptal edildi: Oyun modu bilinmiyor"; + +/* EDMarketConnector.py: CAPI queries aborted because GameVersion unknown; EDMarketConnector.py: CAPI fleetcarrier query aborted because GameVersion unknown; In files: EDMarketConnector.py:1089; EDMarketConnector.py:1170; */ +"CAPI query aborted: GameVersion unknown" = "CAPI sorgusu iptal edildi: GameVersion bilinmiyor"; + +/* EDMarketConnector.py: CAPI queries aborted because current star system name unknown; In files: EDMarketConnector.py:1095; */ +"CAPI query aborted: Current system unknown" = "CAPI sorgusu iptal edildi: Mevcut sistem bilinmiyor"; + +/* EDMarketConnector.py: CAPI queries aborted because player is in multi-crew on other Cmdr's ship; In files: EDMarketConnector.py:1101; */ +"CAPI query aborted: In other-ship multi-crew" = "CAPI sorgusu iptal edildi: Başka gemi çoklu-mürettebatı"; + +/* EDMarketConnector.py: CAPI queries aborted because player is in CQC (Arena); In files: EDMarketConnector.py:1107; */ +"CAPI query aborted: CQC (Arena) detected" = "CAPI sorgusu iptal edildi: CQC (Arena) tespit edildi"; + +/* EDMarketConnector.py: Status - Attempting to retrieve data from Frontier CAPI; In files: EDMarketConnector.py:1128; EDMarketConnector.py:1179; */ +"Fetching data..." = "Veri işleniyor..."; + +/* EDMarketConnector.py: CAPI fleetcarrier query aborted because of killswitch; In files: EDMarketConnector.py:1157; */ +"CAPI fleetcarrier disabled by killswitch" = "CAPI filo taşıyıcısı killswitch tarafından devre dışı bırakıldı"; + +/* EDMarketConnector.py: No data was returned for the fleetcarrier from the Frontier CAPI; In files: EDMarketConnector.py:1219; */ +"CAPI: No fleetcarrier data returned" = "CAPI: Filo taşıyıcı verisi gelmedi."; + +/* EDMarketConnector.py: We didn't have the fleetcarrier callsign when we should have; In files: EDMarketConnector.py:1223; */ +"CAPI: Fleetcarrier data incomplete" = "CAPI: Filo taşıyıcı verileri eksik"; + +/* EDMarketConnector.py: No data was returned for the commander from the Frontier CAPI; In files: EDMarketConnector.py:1242; */ +"CAPI: No commander data returned" = "CAPI: Cmdr verisi döndürülmedi"; + +/* EDMarketConnector.py: We didn't have the commander name when we should have; stats.py: Unknown commander; In files: EDMarketConnector.py:1246; stats.py:333; */ +"Who are you?!" = "Sen kimsin?!"; + +/* EDMarketConnector.py: We don't know where the commander is, when we should; stats.py: Unknown location; In files: EDMarketConnector.py:1252; stats.py:341; */ +"Where are you?!" = "Neredesin?!"; + +/* EDMarketConnector.py: We don't know what ship the commander is in, when we should; stats.py: Unknown ship; In files: EDMarketConnector.py:1259; stats.py:349; */ +"What are you flying?!" = "Ne uçuruyorsun?!"; + +/* EDMarketConnector.py: Frontier CAPI server error when fetching data; In files: EDMarketConnector.py:1384; */ +"Frontier CAPI server error" = "Frontier CAPI sunucu hatası"; + +/* EDMarketConnector.py: Frontier CAPI Access Token expired, trying to get a new one; In files: EDMarketConnector.py:1390; */ +"CAPI: Refreshing access token..." = "CAPI: Erişim token yenileniyor..."; + +/* EDMarketConnector.py: Time when we last obtained Frontier CAPI data; In files: EDMarketConnector.py:1434; */ +"Last updated at %H:%M:%S" = "Son güncelleme %H:%M:%S"; + +/* EDMarketConnector.py: Multicrew role; In files: EDMarketConnector.py:1462; */ +"Fighter" = "Avcı"; + +/* EDMarketConnector.py: Multicrew role; In files: EDMarketConnector.py:1463; */ +"Gunner" = "Nişancı"; + +/* EDMarketConnector.py: Multicrew role; In files: EDMarketConnector.py:1464; */ +"Helm" = "Dümen"; + +/* EDMarketConnector.py: Cooldown on 'Update' button; In files: EDMarketConnector.py:1742; */ +"cooldown {SS}s" = "bekleme süresi {SS}s"; + +/* EDMarketConnector.py: Generic 'OK' button label; prefs.py: 'OK' button on Settings/Preferences window; In files: EDMarketConnector.py:1864; prefs.py:292; */ +"OK" = "Tamam"; + +/* EDMarketConnector.py: The application is shutting down; In files: EDMarketConnector.py:1936; */ +"Shutting down..." = "Kapanıyor..."; + +/* 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." = "Etkin eklentilerinizden bir veya daha fazlası henüz Python 3.x desteğine sahip değil. '{PLUGINS}' sekmesindeki '{FILE}' > '{SETTINGS}' bölümünde bulunan listeyi bulun. Güncellenmiş bir sürümün mevcut olup olmadığını kontrol edin, aksi takdirde geliştiriciyi Python 3.x kodunu güncellemesi gerektiği konusunda uyarmalısınız.\n\nBir eklentiyi, klasörünü adının sonunda '{DISABLED}' olacak şekilde yeniden adlandırarak devre dışı bırakabilirsiniz."; + +/* EDMarketConnector.py: Popup-text about missing FDEVID Files; In files: EDMarketConnector.py:2329; */ +"FDevID Files not found! Some functionality regarding commodities may be disabled.\r\n\r\n Do you want to open the Wiki page on how to set up submodules?" = "FDevID Dosyaları bulunamadı! Ürünlerle ilgili bazı işlevler devre dışı bırakılabilir.\n\nAlt modüllerin nasıl kurulacağına ilişkin Wiki sayfasını açmak ister misiniz?"; + +/* EDMarketConnector.py: Popup window title for missing FDEVID files; In files: EDMarketConnector.py:2340; */ +"FDevIDs: Missing Commodity Files" = "FDevIDs: Eksik Ürün Dosyaları"; + +/* EDMarketConnector.py: Settings > Plugins tab; prefs.py: Label on Settings > Plugins tab; In files: EDMarketConnector.py:2263; prefs.py:986; */ +"Plugins" = "Eklentiler"; + +/* EDMarketConnector.py: Popup window title for list of 'enabled' plugins that don't work with Python 3.x; In files: EDMarketConnector.py:2274; */ +"EDMC: Plugins Without Python 3.x Support" = "EDMC: Python 3.x Desteği Olmayan Eklentiler"; + +/* EDMarketConnector.py: Popup window title for list of 'broken' plugins that failed to load; In files: EDMarketConnector.py:2285; */ +"EDMC: Broken Plugins" = "EDMC: Bozuk Eklentiler"; + +/* 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." = "Etkin eklentilerinizden bir veya daha fazlası yüklenemedi. '{PLUGINS}' sekmesindeki '{FILE}' > '{SETTINGS}' bölümünde bulunan listeyi bulun. Sorunun sebebi yanlış klasör yapısı olabilir. Load.py dosyası, plugins/PLUGIN_NAME/load.py altında bulunmalıdır.\n\nBir eklentiyi, klasörünü adının sonunda '{DISABLED}' olacak şekilde yeniden adlandırarak devre dışı bırakabilirsiniz."; + +/* 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" = "URL Sağlayıcılarınızdan bir veya daha fazlası geçersizdi ve sıfırlandı:"; + +/* 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} , {OLDPROV}'a ayarlanmıştı ancak {NEWPROV}'a sıfırlandı"; + +/* EDMarketConnector.py: Popup window title for Reset Providers; In files: EDMarketConnector.py:2161; */ +"EDMC: Default Providers Reset" = "EDMC: Varsayılan Sağlayıcıların Sıfırlanması"; + +/* EDMarketConnector.py: Await Full CMDR Login to Game; In files: EDMarketConnector.py:813; */ +"Awaiting Full CMDR Login" = "Tam CMDR Girişi Bekleniyor"; + +/* journal_lock.py: Title text on popup when Journal directory already locked; In files: journal_lock.py:208; */ +"Journal directory already locked" = "Günlük dizini zaten kilitli"; + +/* journal_lock.py: Text for when newly selected Journal directory is already locked; In files: journal_lock.py:225:226; */ +"The new Journal Directory location is already locked.{CR}You can either attempt to resolve this and then Retry, or choose to Ignore this." = "Yeni Günlük Dizini konumu zaten kilitli.{CR}Çözüm için Tekrar deneyebilir veya Yoksay'ı seçebilirsiniz."; + +/* journal_lock.py: Generic 'Retry' button label; In files: journal_lock.py:230; */ +"Retry" = "Tekrar Dene"; + +/* journal_lock.py: Generic 'Ignore' button label; In files: journal_lock.py:234; */ +"Ignore" = "Yoksay"; + +/* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ +"Default" = "Varsayılan"; + +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ +"Auto" = "Otomatik"; + +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ +"Normal" = "Normal"; + +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ +"Beta" = "Beta"; + +/* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ +"Set the URL to use with coriolis.io ship loadouts. Note that this MUST end with '/import?data='" = "Coriolis.io gemi ekipman tasarımları ile kullanılacak URL'yi ayarlayın. Link'in '/import?data=' ile bitmesi GEREKTİĞİNİ unutmayın."; + +/* coriolis.py: Settings>Coriolis: Label for 'NOT alpha/beta game version' URL; In files: coriolis.py:97; */ +"Normal URL" = "Normal URL"; + +/* coriolis.py: Generic 'Reset' button label; In files: coriolis.py:100; coriolis.py:109; */ +"Reset" = "Sıfırla"; + +/* coriolis.py: Settings>Coriolis: Label for 'alpha/beta game version' URL; In files: coriolis.py:106; */ +"Beta URL" = "Beta URL"; + +/* coriolis.py: Settings>Coriolis: Label for selection of using Normal, Beta or 'auto' Coriolis URL; In files: coriolis.py:116; */ +"Override Beta/Normal Selection" = "Beta/Normal Seçimi Geçersiz Kıl"; + +/* coriolis.py: Settings>Coriolis - invalid override mode found; In files: coriolis.py:156; */ +"Invalid Coriolis override mode!" = "Geçersiz Coriolis geçersiz kılma modu!"; + +/* eddn.py: Error while trying to send data to EDDN; In files: eddn.py:458; eddn.py:2413; eddn.py:2451; eddn.py:2519; */ +"Error: Can't connect to EDDN" = "Hata: EDDN'e bağlanılamıyor"; + +/* eddn.py: EDDN has banned this version of our client; In files: eddn.py:576; */ +"EDDN Error: EDMC is too old for EDDN. Please update." = "EDDN Hatası: EDMC sürümü EDDN için çok eski. Lütfen güncelle."; + +/* eddn.py: EDDN returned an error that indicates something about what we sent it was wrong; In files: eddn.py:582; */ +"EDDN Error: Validation Failed (EDMC Too Old?). See Log" = "EDDN Hatası: Doğrulama Başarısız Oldu (EDMC sürümü eski olabilir?). Günlüğe bakın"; + +/* eddn.py: EDDN returned some sort of HTTP error, one we didn't expect. {STATUS} contains a number; In files: eddn.py:587; */ +"EDDN Error: Returned {STATUS} status code" = "EDDN Hatası: {STATUS} durum kodu ile döndü."; + +/* eddn.py: Enable EDDN support for station data checkbox label; In files: eddn.py:2041; */ +"Send station data to the Elite Dangerous Data Network" = "İstasyon verilerini Elite Dangerous Data Network'e gönderin"; + +/* eddn.py: Enable EDDN support for system and other scan data checkbox label; In files: eddn.py:2052; */ +"Send system and scan data to the Elite Dangerous Data Network" = "Sistem ve tarama verilerini Elite Dangerous Data Network'e gönderin"; + +/* eddn.py: EDDN delay sending until docked option is on, this message notes that a send was skipped due to this; In files: eddn.py:2063; */ +"Delay sending until docked" = "Kenetlenmeye kadar gönderimi ertele"; + +/* eddn.py: Killswitch disabled EDDN; In files: eddn.py:2178; */ +"EDDN journal handler disabled. See Log." = "EDDN günlük düzenleyici devre dışı. Kayıt geçmişini kontrol edin."; + +/* eddn.py: Status text shown while attempting to send data; In files: eddn.py:2507; */ +"Sending data to EDDN..." = "Veriler EDDN'e gönderiliyor..."; + +/* edsm.py: Settings>EDSM - Label on header/URL to EDSM API key page; In files: edsm.py:319; */ +"Elite Dangerous Star Map credentials" = "Elite Dangerous Star Map kimlik bilgileri"; + +/* edsm.py: EDSM Commander name label in EDSM settings; In files: edsm.py:341; */ +"Commander Name" = "Cmdr ismi"; + +/* edsm.py: EDSM API key label; inara.py: Inara API key label; In files: edsm.py:350; inara.py:278; */ +"API Key" = "API Anahtarı"; + +/* edsm.py: We have no data on the current commander; prefs.py: No hotkey/shortcut set; stats.py: No rank; In files: edsm.py:394; prefs.py:527; prefs.py:1157; prefs.py:1190; stats.py:154; stats.py:173; stats.py:192; stats.py:209; */ +"None" = "Hiçbiri"; + +/* edsm.py: EDSM plugin - Journal handling disabled by killswitch; In files: edsm.py:516; */ +"EDSM Handler disabled. See Log." = "EDSM düzenleyici devre dışı. Kayıt geçmişini kontrol edin."; + +/* edsm.py: EDSM - Only Live data; In files: edsm.py:632; */ +"EDSM only accepts Live galaxy data" = "EDSM sadece canlı galaxy verilerini kabul eder"; + +/* edsm.py: EDSM Plugin - Error message from EDSM API; In files: edsm.py:916; edsm.py:1048; */ +"Error: EDSM {MSG}" = "Hata: EDSM {MSG}"; + +/* edsm.py: EDSM Plugin - Error connecting to EDSM API; In files: edsm.py:953; edsm.py:1043; */ +"Error: Can't connect to EDSM" = "Hata: EDSM'e bağlanılamıyor"; + +/* inara.py: Checkbox to enable INARA API Usage; In files: inara.py:257; */ +"Send flight log and Cmdr status to Inara" = "Uçuş günlüğünü ve Cmdr durumunu Inara'ya gönder"; + +/* inara.py: Text for INARA API keys link ( goes to https://inara.cz/settings-api ); In files: inara.py:269; */ +"Inara credentials" = "Inara kimlik bilgileri"; + +/* inara.py: The Inara API only accepts Live galaxy data, not Legacy galaxy data; inara.py: Inara - Only Live data; In files: inara.py:384; inara.py:386; */ +"Inara only accepts Live galaxy data" = "Inara sadece canlı galaxy verilerini kabul eder"; + +/* inara.py: INARA support disabled via killswitch; In files: inara.py:395; */ +"Inara disabled. See Log." = "Inara devre dışı. Kayıt geçmişini kontrol edin."; + +/* inara.py: INARA API returned some kind of error (error message will be contained in {MSG}); In files: inara.py:1650; inara.py:1663; */ +"Error: Inara {MSG}" = "Hata: Inara {MSG}"; + +/* prefs.py: File > Preferences menu entry for macOS; In files: prefs.py:237; */ +"Preferences" = "Tercihler"; + +/* prefs.py: Settings > Output - choosing what data to save to files; In files: prefs.py:335; */ +"Please choose what data to save" = "Lütfen hangi verilerin kaydedileceğini seçin"; + +/* prefs.py: Settings > Output option; In files: prefs.py:341; */ +"Market data in CSV format file" = "CSV formatında Market verileri"; + +/* prefs.py: Settings > Output option; In files: prefs.py:350; */ +"Market data in Trade Dangerous format file" = "Trade Dangerous formatında Market verileri"; + +/* prefs.py: Settings > Output option; In files: prefs.py:360; */ +"Ship loadout" = "Gemi Ekipmanları"; + +/* prefs.py: Settings > Output option; In files: prefs.py:370; */ +"Automatically update on docking" = "Kenetlenme sırasında otomatik güncelle"; + +/* prefs.py: Settings > Output - Label for "where files are located"; In files: prefs.py:379; prefs.py:398; */ +"File location" = "Dosya konumu"; + +/* prefs.py: macOS Preferences - files location selection button; In files: prefs.py:387; prefs.py:437; */ +"Change..." = "Değiştir..."; + +/* prefs.py: NOT-macOS Settings - files location selection button; prefs.py: NOT-macOS Setting - files location selection button; In files: prefs.py:390; prefs.py:440; */ +"Browse..." = "Gezin..."; + +/* prefs.py: Label for 'Output' Settings/Preferences tab; In files: prefs.py:405; */ +"Output" = "Kayıt"; + +/* prefs.py: Settings > Configuration - Label for Journal files location; In files: prefs.py:431; prefs.py:446; */ +"E:D journal file location" = "E:D günlük dosya konumu"; + +/* prefs.py: Settings > Configuration - Label for CAPI section; In files: prefs.py:469; */ +"CAPI Settings" = "CAPI ayarları"; + +/* prefs.py: Configuration - Enable or disable the Fleet Carrier CAPI calls; In files: prefs.py:475; */ +"Enable Fleetcarrier CAPI Queries" = "Filo Taşıyıcı CAPI sorgulamalarını etkinleştir"; + +/* prefs.py: Hotkey/Shortcut settings prompt on OSX; In files: prefs.py:490; */ +"Keyboard shortcut" = "Klavye Kısayolu"; + +/* prefs.py: Hotkey/Shortcut settings prompt on Windows; In files: prefs.py:492; */ +"Hotkey" = "Kısayoltuşu"; + +/* prefs.py: macOS Preferences > Configuration - restart the app message; In files: prefs.py:501; */ +"Re-start {APP} to use shortcuts" = "Kısayolları kullanmak için {APP}'i yeniden başlat"; + +/* prefs.py: macOS - Configuration - need to grant the app permission for keyboard shortcuts; In files: prefs.py:510; */ +"{APP} needs permission to use shortcuts" = "{APP}'nin kısayolları kullanabilmesi için izne ihtiyacı var"; + +/* prefs.py: Shortcut settings button on OSX; In files: prefs.py:515; */ +"Open System Preferences" = "Sistem Tercihlerini Aç"; + +/* prefs.py: Configuration - Act on hotkey only when ED is in foreground; In files: prefs.py:538; */ +"Only when Elite: Dangerous is the active app" = "Sadece Elite: Dangerous aktif uygulama olduğunda"; + +/* prefs.py: Configuration - play sound when hotkey used; In files: prefs.py:549; */ +"Play sound" = "Ses çal"; + +/* prefs.py: Configuration - disable checks for app updates when in-game; In files: prefs.py:564; */ +"Disable Automatic Application Updates Check when in-game" = "Otomatik Uygulama Güncellemelerini Oyun sırasında Devre Dışı Bırak"; + +/* prefs.py: Label for preferred shipyard, system and station 'providers'; In files: prefs.py:577; */ +"Preferred websites" = "Tercih edilen web siteleri"; + +/* prefs.py: Label for Shipyard provider selection; In files: prefs.py:588; */ +"Shipyard" = "Tersane"; + +/* prefs.py: Label for checkbox to utilise alternative Coriolis URL method; In files: prefs.py:600; */ +"Use alternate URL method" = "Alternatif URL yöntemi kullan"; + +/* prefs.py: Configuration - Label for selection of Log Level; In files: prefs.py:653; */ +"Log Level" = "Günlük Seviyesi"; + +/* prefs.py: Label for 'Configuration' tab in Settings; In files: prefs.py:681; */ +"Configuration" = "Yapılandırma"; + +/* prefs.py: UI elements privacy section header in privacy tab of preferences; In files: prefs.py:690; */ +"Main UI privacy options" = "Ana Arayüz gizlilik seçenekleri"; + +/* prefs.py: Hide private group owner name from UI checkbox; In files: prefs.py:695; */ +"Hide private group name in UI" = "Özel grup ismini arayüzde gizle"; + +/* prefs.py: Hide multicrew captain name from main UI checkbox; In files: prefs.py:699; */ +"Hide multi-crew captain name" = "Çoklu-mürettebat ismini gizle"; + +/* prefs.py: Preferences privacy tab title; In files: prefs.py:703; */ +"Privacy" = "Gizlilik"; + +/* prefs.py: Label for Settings > Appeareance > selection of 'normal' text colour; In files: prefs.py:716; */ +"Normal text" = "Normal metin"; + +/* prefs.py: Label for Settings > Appeareance > selection of 'highlightes' text colour; In files: prefs.py:718; */ +"Highlighted text" = "Vurgulanan metin"; + +/* prefs.py: Appearance - Label for selection of application display language; In files: prefs.py:727; */ +"Language" = "Dil"; + +/* prefs.py: Label for Settings > Appearance > Theme selection; In files: prefs.py:737; */ +"Theme" = "Tema"; + +/* prefs.py: Label for 'Dark' theme radio button; In files: prefs.py:749; */ +"Dark" = "Karanlık"; + +/* prefs.py: Label for 'Transparent' theme radio button; In files: prefs.py:756; */ +"Transparent" = "Şeffaflık"; + +/* prefs.py: Appearance - Label for selection of UI scaling; In files: prefs.py:802; */ +"UI Scale Percentage" = "Arayüz ölçek yüzdesi"; + +/* prefs.py: Appearance - Help/hint text for UI scaling selection; In files: prefs.py:823; */ +"100 means Default{CR}Restart Required for{CR}changes to take effect!" = "100 Varsayılan değerdir. Değişikliklerin geçerli olması için {CR}Yeniden Başlatma Gereklidir{CR}!"; + +/* prefs.py: Appearance - Label for selection of main window transparency; In files: prefs.py:833; */ +"Main window transparency" = "Ana pencere şeffaflığı"; + +/* prefs.py: Appearance - Help/hint text for Main window transparency selection; In files: prefs.py:853:856; */ +"100 means fully opaque.{CR}Window is updated in real time" = "100 tamamen opak anlamına gelir.{CR}Pencere gerçek zamanlı olarak güncellenir"; + +/* prefs.py: Appearance option for Windows "minimize to system tray"; In files: prefs.py:885; */ +"Minimize to system tray" = "Simge durumuna küçült"; + +/* prefs.py: Label for Settings > Appearance tab; In files: prefs.py:893; */ +"Appearance" = "Görünüm"; + +/* prefs.py: Label for location of third-party plugins folder; In files: prefs.py:908; */ +"Plugins folder" = "Eklentiler klasörü"; + +/* prefs.py: Label on button used to open a filesystem folder; In files: prefs.py:915; */ +"Open" = "Aç"; + +/* prefs.py: Tip/label about how to disable plugins; In files: prefs.py:923; */ +"Tip: You can disable a plugin by{CR}adding '{EXT}' to its folder name" = "İpucu: Bir eklentiyi, klasör adına{CR}'{EXT}' ekleyerek devre dışı bırakabilirsiniz"; + +/* prefs.py: Label on list of enabled plugins; In files: prefs.py:934; */ +"Enabled Plugins" = "Etkin Eklentiler"; + +/* prefs.py: Plugins - Label for list of 'enabled' plugins that don't work with Python 3.x; In files: prefs.py:954; */ +"Plugins Without Python 3.x Support" = "Python 3.x Desteği Olmayan Eklentiler"; + +/* prefs.py: Plugins - Label on URL to documentation about migrating plugins from Python 2.7; In files: prefs.py:962; */ +"Information on migrating plugins" = "Eklentilerin taşınmasıyla ilgili bilgiler"; + +/* prefs.py: Plugins - Label for list of 'broken' plugins that failed to load; In files: prefs.py:1039; */ +"Broken Plugins" = "Bozuk Eklentiler"; + +/* prefs.py: Lable on list of user-disabled plugins; In files: prefs.py:977; */ +"Disabled Plugins" = "Devre Dışı Eklentiler"; + +/* stats.py: Cmdr stats; In files: stats.py:58; */ +"Balance" = "Bakiye"; + +/* stats.py: Cmdr stats; In files: stats.py:59; */ +"Loan" = "Borç"; + +/* stats.py: Top rank; In files: stats.py:63; */ +"Elite" = "Elite"; + +/* stats.py: Top rank +1; In files: stats.py:64; */ +"Elite I" = "Elite I"; + +/* stats.py: Top rank +2; In files: stats.py:65; */ +"Elite II" = "Elite II"; + +/* stats.py: Top rank +3; In files: stats.py:66; */ +"Elite III" = "Elite III"; + +/* stats.py: Top rank +4; In files: stats.py:67; */ +"Elite IV" = "Elite IV"; + +/* stats.py: Top rank +5; In files: stats.py:68; */ +"Elite V" = "Elite V"; + +/* stats.py: Ranking; In files: stats.py:74; */ +"Combat" = "Combat"; + +/* stats.py: Ranking; In files: stats.py:75; */ +"Trade" = "Trade"; + +/* stats.py: Ranking; In files: stats.py:76; */ +"Explorer" = "Explorer"; + +/* stats.py: Ranking; In files: stats.py:77; */ +"Mercenary" = "Mercenary"; + +/* stats.py: Ranking; In files: stats.py:78; */ +"Exobiologist" = "Exobiologist"; + +/* stats.py: Ranking; In files: stats.py:79; */ +"CQC" = "CQC"; + +/* stats.py: Ranking; In files: stats.py:80; */ +"Federation" = "Federation"; + +/* stats.py: Ranking; In files: stats.py:81; */ +"Empire" = "Empire"; + +/* stats.py: Ranking; In files: stats.py:82; */ +"Powerplay" = "Powerplay"; + +/* stats.py: Combat rank; In files: stats.py:91; */ +"Harmless" = "Harmless"; + +/* stats.py: Combat rank; In files: stats.py:92; */ +"Mostly Harmless" = "Mostly Harmless"; + +/* stats.py: Combat rank; In files: stats.py:93; */ +"Novice" = "Novice"; + +/* stats.py: Combat rank; In files: stats.py:94; */ +"Competent" = "Competent"; + +/* stats.py: Combat rank; In files: stats.py:95; */ +"Expert" = "Expert"; + +/* stats.py: Combat rank; stats.py: Empire rank; In files: stats.py:96; stats.py:176; */ +"Master" = "Master"; + +/* stats.py: Combat rank; In files: stats.py:97; */ +"Dangerous" = "Dangerous"; + +/* stats.py: Combat rank; In files: stats.py:98; */ +"Deadly" = "Deadly"; + +/* stats.py: Trade rank; In files: stats.py:101; */ +"Penniless" = "Penniless"; + +/* stats.py: Trade rank; In files: stats.py:102; */ +"Mostly Penniless" = "Mostly Penniless"; + +/* stats.py: Trade rank; In files: stats.py:103; */ +"Peddler" = "Peddler"; + +/* stats.py: Trade rank; In files: stats.py:104; */ +"Dealer" = "Dealer"; + +/* stats.py: Trade rank; In files: stats.py:105; */ +"Merchant" = "Merchant"; + +/* stats.py: Trade rank; In files: stats.py:106; */ +"Broker" = "Broker"; + +/* stats.py: Trade rank; In files: stats.py:107; */ +"Entrepreneur" = "Entrepreneur"; + +/* stats.py: Trade rank; In files: stats.py:108; */ +"Tycoon" = "Tycoon"; + +/* stats.py: Explorer rank; In files: stats.py:111; */ +"Aimless" = "Aimless"; + +/* stats.py: Explorer rank; In files: stats.py:112; */ +"Mostly Aimless" = "Mostly Aimless"; + +/* stats.py: Explorer rank; In files: stats.py:113; */ +"Scout" = "Scout"; + +/* stats.py: Explorer rank; In files: stats.py:114; */ +"Surveyor" = "Surveyor"; + +/* stats.py: Explorer rank; In files: stats.py:115; */ +"Trailblazer" = "Trailblazer"; + +/* stats.py: Explorer rank; In files: stats.py:116; */ +"Pathfinder" = "Pathfinder"; + +/* stats.py: Explorer rank; In files: stats.py:117; */ +"Ranger" = "Ranger"; + +/* stats.py: Explorer rank; In files: stats.py:118; */ +"Pioneer" = "Pioneer"; + +/* stats.py: Mercenary rank; In files: stats.py:122; */ +"Defenceless" = "Defenceless"; + +/* stats.py: Mercenary rank; In files: stats.py:123; */ +"Mostly Defenceless" = "Mostly Defenceless"; + +/* stats.py: Mercenary rank; In files: stats.py:124; */ +"Rookie" = "Rookie"; + +/* stats.py: Mercenary rank; In files: stats.py:125; */ +"Soldier" = "Soldier"; + +/* stats.py: Mercenary rank; In files: stats.py:126; stats.py:128; */ +"Gunslinger" = "Gunslinger"; + +/* stats.py: Mercenary rank; In files: stats.py:127; */ +"Warrior" = "Warrior"; + +/* stats.py: Mercenary rank; In files: stats.py:129; */ +"Deadeye" = "Deadeye"; + +/* stats.py: Exobiologist rank; In files: stats.py:132; */ +"Directionless" = "Directionless"; + +/* stats.py: Exobiologist rank; In files: stats.py:133; */ +"Mostly Directionless" = "Mostly Directionless"; + +/* stats.py: Exobiologist rank; In files: stats.py:134; */ +"Compiler" = "Compiler"; + +/* stats.py: Exobiologist rank; In files: stats.py:135; */ +"Collector" = "Collector"; + +/* stats.py: Exobiologist rank; In files: stats.py:136; */ +"Cataloguer" = "Cataloguer"; + +/* stats.py: Exobiologist rank; In files: stats.py:137; */ +"Taxonomist" = "Taxonomist"; + +/* stats.py: Exobiologist rank; In files: stats.py:138; */ +"Ecologist" = "Ecologist"; + +/* stats.py: Exobiologist rank; In files: stats.py:139; */ +"Geneticist" = "Geneticist"; + +/* stats.py: CQC rank; In files: stats.py:142; */ +"Helpless" = "Helpless"; + +/* stats.py: CQC rank; In files: stats.py:143; */ +"Mostly Helpless" = "Mostly Helpless"; + +/* stats.py: CQC rank; In files: stats.py:144; */ +"Amateur" = "Amateur"; + +/* stats.py: CQC rank; In files: stats.py:145; */ +"Semi Professional" = "Semi Professional"; + +/* stats.py: CQC rank; In files: stats.py:146; */ +"Professional" = "Professional"; + +/* stats.py: CQC rank; In files: stats.py:147; */ +"Champion" = "Champion"; + +/* stats.py: CQC rank; In files: stats.py:148; */ +"Hero" = "Hero"; + +/* stats.py: CQC rank; In files: stats.py:149; */ +"Gladiator" = "Gladiator"; + +/* stats.py: Federation rank; In files: stats.py:155; */ +"Recruit" = "Recruit"; + +/* stats.py: Federation rank; In files: stats.py:156; */ +"Cadet" = "Cadet"; + +/* stats.py: Federation rank; In files: stats.py:157; */ +"Midshipman" = "Midshipman"; + +/* stats.py: Federation rank; In files: stats.py:158; */ +"Petty Officer" = "Petty Officer"; + +/* stats.py: Federation rank; In files: stats.py:159; */ +"Chief Petty Officer" = "Chief Petty Officer"; + +/* stats.py: Federation rank; In files: stats.py:160; */ +"Warrant Officer" = "Warrant Officer"; + +/* stats.py: Federation rank; In files: stats.py:161; */ +"Ensign" = "Ensign"; + +/* stats.py: Federation rank; In files: stats.py:162; */ +"Lieutenant" = "Lieutenant"; + +/* stats.py: Federation rank; In files: stats.py:163; */ +"Lieutenant Commander" = "Lieutenant Commander"; + +/* stats.py: Federation rank; In files: stats.py:164; */ +"Post Commander" = "Post Commander"; + +/* stats.py: Federation rank; In files: stats.py:165; */ +"Post Captain" = "Post Captain"; + +/* stats.py: Federation rank; In files: stats.py:166; */ +"Rear Admiral" = "Rear Admiral"; + +/* stats.py: Federation rank; In files: stats.py:167; */ +"Vice Admiral" = "Vice Admiral"; + +/* stats.py: Federation rank; In files: stats.py:168; */ +"Admiral" = "Admiral"; + +/* stats.py: Empire rank; In files: stats.py:174; */ +"Outsider" = "Outsider"; + +/* stats.py: Empire rank; In files: stats.py:175; */ +"Serf" = "Serf"; + +/* stats.py: Empire rank; In files: stats.py:177; */ +"Squire" = "Squire"; + +/* stats.py: Empire rank; In files: stats.py:178; */ +"Knight" = "Knight"; + +/* stats.py: Empire rank; In files: stats.py:179; */ +"Lord" = "Lord"; + +/* stats.py: Empire rank; In files: stats.py:180; */ +"Baron" = "Baron"; + +/* stats.py: Empire rank; In files: stats.py:181; */ +"Viscount" = "Viscount"; + +/* stats.py: Empire rank; In files: stats.py:182; */ +"Count" = "Count"; + +/* stats.py: Empire rank; In files: stats.py:183; */ +"Earl" = "Earl"; + +/* stats.py: Empire rank; In files: stats.py:184; */ +"Marquis" = "Marquis"; + +/* stats.py: Empire rank; In files: stats.py:185; */ +"Duke" = "Duke"; + +/* stats.py: Empire rank; In files: stats.py:186; */ +"Prince" = "Prince"; + +/* stats.py: Empire rank; In files: stats.py:187; */ +"King" = "King"; + +/* stats.py: Power rank; In files: stats.py:193; */ +"Rating 1" = "Reyting 1"; + +/* stats.py: Power rank; In files: stats.py:194; */ +"Rating 2" = "Reyting 2"; + +/* stats.py: Power rank; In files: stats.py:195; */ +"Rating 3" = "Reyting 3"; + +/* stats.py: Power rank; In files: stats.py:196; */ +"Rating 4" = "Reyting 4"; + +/* stats.py: Power rank; In files: stats.py:197; */ +"Rating 5" = "Reyting 5"; + +/* stats.py: Current commander unknown when trying to use 'File' > 'Status'; In files: stats.py:315; */ +"Status: Don't yet know your Commander name" = "Durum: Cmdr adınızı henüz bilmiyorum"; + +/* stats.py: No Frontier CAPI data yet when trying to use 'File' > 'Status'; In files: stats.py:323; */ +"Status: No CAPI data yet" = "Durum: Henüz CAPI verisi yok"; + +/* stats.py: Status dialog subtitle - CR value of ship; In files: stats.py:409; */ +"Value" = "Değer"; + +/* stats.py: Status dialog title; In files: stats.py:418; */ +"Ships" = "Gemiler"; + +/* update.py: Update Available Text; In files: update.py:229; */ +"{NEWVER} is available" = "{NEWVER} sürüm mevcut"; diff --git a/L10n/zh-Hans.strings b/L10n/zh-Hans.strings index 2b9eb75d..03e263dd 100644 --- a/L10n/zh-Hans.strings +++ b/L10n/zh-Hans.strings @@ -226,13 +226,13 @@ /* l10n.py: The system default language choice in Settings > Appearance; prefs.py: Settings > Configuration - Label on 'reset journal files location to default' button; prefs.py: The system default language choice in Settings > Appearance; prefs.py: Label for 'Default' theme radio button; In files: l10n.py:193; prefs.py:455; prefs.py:709; prefs.py:742; */ "Default" = "默认"; -/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:74; coriolis.py:77; coriolis.py:123; coriolis.py:139; coriolis.py:145; */ +/* coriolis.py: 'Auto' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - auto; In files: coriolis.py:48; coriolis.py:74; coriolis.py:77; coriolis.py:94; coriolis.py:123; coriolis.py:139; coriolis.py:145; coriolis.py:179; coriolis.py:182; */ "Auto" = "自动"; -/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:75; coriolis.py:121; coriolis.py:137; */ +/* coriolis.py: 'Normal' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - normal; In files: coriolis.py:49; coriolis.py:75; coriolis.py:95; coriolis.py:121; coriolis.py:137; coriolis.py:180; */ "Normal" = "普通版"; -/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:76; coriolis.py:122; coriolis.py:138; */ +/* coriolis.py: 'Beta' label for Coriolis site override selection; coriolis.py: Coriolis normal/beta selection - beta; In files: coriolis.py:50; coriolis.py:76; coriolis.py:96; coriolis.py:122; coriolis.py:138; coriolis.py:181; */ "Beta" = "测试版"; /* coriolis.py: Settings>Coriolis: Help/hint for changing coriolis URLs; In files: coriolis.py:91:93; */ From 164a92092f349a1889564f480db711e90f167b7a Mon Sep 17 00:00:00 2001 From: github-actions <github-actions@github.com> Date: Wed, 17 Apr 2024 12:25:52 +0000 Subject: [PATCH 48/49] updating submodules --- FDevIDs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FDevIDs b/FDevIDs index 7cffab3d..9b3f4061 160000 --- a/FDevIDs +++ b/FDevIDs @@ -1 +1 @@ -Subproject commit 7cffab3d913b788f981923687203399c22cf358f +Subproject commit 9b3f40612017b43a8b826017e1e2befebd9074f2 From 9cd69a19e4b7a0cfeb89045044aec8a85d4dccd5 Mon Sep 17 00:00:00 2001 From: David Sangrey <rixxan@hullseals.space> Date: Wed, 17 Apr 2024 15:35:57 -0400 Subject: [PATCH 49/49] [1133] Refine Inheritence --- myNotebook.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/myNotebook.py b/myNotebook.py index 2442acbe..070b28e1 100644 --- a/myNotebook.py +++ b/myNotebook.py @@ -67,7 +67,7 @@ class EntryMenu(ttk.Entry): """Extended entry widget that includes a context menu with Copy, Cut-and-Paste commands.""" def __init__(self, *args, **kwargs) -> None: - super().__init__(*args, **kwargs) + ttk.Entry.__init__(self, *args, **kwargs) self.menu = tk.Menu(self, tearoff=False) self.menu.add_command(label="Copy", command=self.copy) @@ -120,7 +120,7 @@ class EntryMenu(ttk.Entry): pass -class Entry(EntryMenu or ttk.Entry): # type: ignore +class Entry(EntryMenu): """Custom ttk.Entry class to fix some display issues.""" # DEPRECATED: Migrate to EntryMenu. Will remove in 5.12 or later.