diff --git a/ChangeLog.md b/ChangeLog.md
index e4932683..16a8eb3c 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/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é";
 
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'
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'