Repository: joinmarket-webui/jam
Pull request #573 (2022-11-30 20:11:16)

Settings subsections refined w/ translation addition
Using #524 as a reference I tuned the settings page to be better organized. Additionally I did a small amount of translation for the settings page as well added some unfinished translations in the french translation.json to make it easier to do translations moving forward where it doesn't yet exist. Finally I added little country flags to the languages.js file.  While there are only two languages now I think moving forward having a quick way for people to see the flag reference as the list of languages gets longer it could be helpful to use identifying flags.

![image](https://user-images.githubusercontent.com/108441023/204898302-53e9e2c2-2a8a-495f-81d5-22b39cf07205.png)

![image](https://user-images.githubusercontent.com/108441023/204898067-6ab2030b-2e3e-40d1-a69a-028000e2e28d.png)


benalleng: Feedback is welcome! I'll start.. Even though the user is led there by a classic cog symbol, I wonder if it would be worth keeping a main "Settings" title at the very top before the first section
theborakompanioni: Hey @benalleng!

Really nice. Thank you!

Two things from my side:
- If you are okay with it, let's remove the flags from the language dropdown. e.g.  French is spoken in many countries, not exclusively in France. Same with English and many other languages. I'd vote for removing them. Just let me know what you think.
- Some translations in `fr/translation.json`  are in English. It's easier to see the progress on Transifex, if this file only contains actually translated keys, e.g. French has 68% translated keys. Missing keys will fallback to English anyway!


> Feedback is welcome! I'll start.. Even though the user is led there by a classic cog symbol, I wonder if it would be worth keeping a main "Settings" title at the very top before the first section

My 2 sats: I think both is fine. We can keep it this way for now and if you are not happy with it, add a main header in a follow-up PR, if you so please!


What do you think? Let me know if you want to make the adaptions yourself.
Once done, I think it is ready to be merged. :rocket: 

benalleng: - Ok! sounds good to me, as I look at it more I agree that as long as we continue to use the proper script for each language, flags aren't really needed or preferred.
- sorry about the Transifex thing, I didn't realize that was the proper method to go through translations. For the future I'll make sure to help with translations there :sweat_smile:  I'll also remove the other translations that already fallback to english!
theborakompanioni: > * Ok! sounds good to me, as I look at it more I agree that as long as we continue to use the proper script for each language, flags aren't really needed or preferred.

:+1:

> 
>     * sorry about the Transifex thing, I didn't realize that was the proper method to go through translations. For the future I'll make sure to help with translations there sweat_smile  I'll also remove the other translations that already fallback to english!

Don't worry!

Two small suggestions (one typo keeping the tests from succeeding, and removing left-over untranslated keys from `fr`), then we can push it over the finish line. :muscle: 



Patch:
diff --git a/src/components/Settings.jsx b/src/components/Settings.jsx
index 4d8fae1..7176d16 100644
--- a/src/components/Settings.jsx
+++ b/src/components/Settings.jsx
@@ -92,7 +92,7 @@ export default function Settings({ wallet, stopWallet }) {
   return (
     <div className={styles.settings}>
       <div className="d-flex flex-column gap-3">
-        <div className={styles['section-title']}>{t('settings.title')}</div>
+        <div className={styles['section-title']}>{t('settings.section_title_display')}</div>
         {alert && <Alert {...alert} />}
         <ConfirmModal
           isShown={showConfirmLockModal}
@@ -161,28 +161,23 @@ export default function Settings({ wallet, stopWallet }) {
               </rb.Dropdown.Item>
             </rb.Dropdown.Menu>
           </rb.Dropdown>
-
-          <rb.Button
-            variant="outline-dark"
-            className={styles['settings-btn']}
-            onClick={(e) => setShowingFeeConfig(true)}
-          >
-            <Sprite symbol="coins" width="24" height="24" />
-            {t('settings.show_fee_config')}
-          </rb.Button>
-          {showingFeeConfig && <FeeConfigModal show={showingFeeConfig} onHide={() => setShowingFeeConfig(false)} />}
-
-          {showLogsEnabled && (
-            <>
-              <rb.Button variant="outline-dark" className={styles['settings-btn']} onClick={() => setShowingLogs(true)}>
-                <Sprite symbol="console" width="24" height="24" />
-                {t('settings.show_logs')}
-              </rb.Button>
-              <LogOverlay currentWallet={wallet} show={showingLogs} onHide={() => setShowingLogs(false)} />
-            </>
-          )}
         </div>
+        <div className={styles['section-title']}>{t('settings.section_title_market')}</div>
+        <rb.Button variant="outline-dark" className={styles['settings-btn']} onClick={(e) => setShowingFeeConfig(true)}>
+          <Sprite symbol="coins" width="24" height="24" />
+          {t('settings.show_fee_config')}
+        </rb.Button>
+        {showingFeeConfig && <FeeConfigModal show={showingFeeConfig} onHide={() => setShowingFeeConfig(false)} />}
 
+        {showLogsEnabled && (
+          <>
+            <rb.Button variant="outline-dark" className={styles['settings-btn']} onClick={() => setShowingLogs(true)}>
+              <Sprite symbol="console" width="24" height="24" />
+              {t('settings.show_logs')}
+            </rb.Button>
+            <LogOverlay currentWallet={wallet} show={showingLogs} onHide={() => setShowingLogs(false)} />
+          </>
+        )}
         <div className={styles['section-title']}>{t('settings.section_title_wallet')}</div>
         <div className={styles['settings-group-container']}>
           <rb.Button variant="outline-dark" className={styles['settings-btn']} onClick={(e) => setShowingSeed(true)}>
@@ -233,23 +228,6 @@ export default function Settings({ wallet, stopWallet }) {
 
         <div className={styles['section-title']}>{t('settings.section_title_community')}</div>
         <div className={styles['settings-links']}>
-          <a href="https://jamdocs.org" target="_blank" rel="noopener noreferrer" className="link-dark">
-            <div className="d-flex align-items-center">
-              <Sprite symbol="file" width="24" height="24" className="me-2" />
-              {t('settings.documentation')}
-            </div>
-          </a>
-          <a
-            href="https://github.com/joinmarket-webui/jam"
-            target="_blank"
-            rel="noopener noreferrer"
-            className="link-dark"
-          >
-            <div className="d-flex align-items-center">
-              <Sprite symbol="github" width="24" height="24" className="me-2 p-1" />
-              {t('settings.github')}
-            </div>
-          </a>
           <a
             href="https://matrix.to/#/%23jam:bitcoin.kyoto"
             target="_blank"
@@ -280,6 +258,26 @@ export default function Settings({ wallet, stopWallet }) {
             </div>
           </a>
         </div>
+        <div className={styles['section-title']}>{t('settings.section_title_dev')}</div>
+        <div className={styles['settings-links']}>
+          <a href="https://jamdocs.org" target="_blank" rel="noopener noreferrer" className="link-dark">
+            <div className="d-flex align-items-center">
+              <Sprite symbol="file" width="24" height="24" className="me-2" />
+              {t('settings.documentation')}
+            </div>
+          </a>
+          <a
+            href="https://github.com/joinmarket-webui/jam"
+            target="_blank"
+            rel="noopener noreferrer"
+            className="link-dark"
+          >
+            <div className="d-flex align-items-center">
+              <Sprite symbol="github" width="24" height="24" className="me-2 p-1" />
+              {t('settings.github')}
+            </div>
+          </a>
+        </div>
       </div>
     </div>
   )
diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json
index 5a73bfa..ef4f100 100644
--- a/src/i18n/locales/en/translation.json
+++ b/src/i18n/locales/en/translation.json
@@ -140,9 +140,11 @@
     "account_heading_internal_addresses": "Internal Addresses"
   },
   "settings": {
-    "title": "Settings",
+    "section_title_display": "Display",
+    "section_title_market": "Market",
     "section_title_wallet": "Wallet",
     "section_title_community": "Community",
+    "section_title_dev": "Development & Documentation",
     "show_balance": "Show balance",
     "hide_balance": "Hide balance",
     "use_sats": "Display amounts in sats",
diff --git a/src/i18n/locales/fr/translation.json b/src/i18n/locales/fr/translation.json
index 5e5cfc0..21056ad 100644
--- a/src/i18n/locales/fr/translation.json
+++ b/src/i18n/locales/fr/translation.json
@@ -131,7 +131,11 @@
     "account_heading_internal_addresses": "Adresses internes"
   },
   "settings": {
-    "title": "Paramètres",
+    "section_title_display": "Écran",
+    "section_title_market": "Marché",
+    "section_title_wallet": "Portefeuille",
+    "section_title_community": "Communauté",
+    "section_title_dev": "Développement & Documentation",
     "show_balance": "Afficher le solde",
     "hide_balance": "Cacher le solde",
     "use_sats": "Afficher les montants en sats",
@@ -144,9 +148,26 @@
     "show_seed": "Afficher la phrase graine",
     "hide_seed": "Cacher la phrase graine",
     "reveal_seed": "Révéler la phrase graine",
+    "show_logs": "Afficher les journaux",
+    "show_fee_config": "Ajuster les limites de frais",
+    "button_lock_wallet": "Verrouiller le portefeuille",
+    "button_locking_wallet": "Verrouillant...",
+    "button_create_wallet": "Créer un nouveau portefeuille",
     "button_switch_wallet": "Changer de porte-monnaie",
     "error_loading_seed_failed": "Impossible de récupérer la phrase graine.",
-    "seed_modal_info_text": "Veuillez noter votre phrase graine et votre mot de passe ! Sans ces informations, vous ne serez pas en mesure d'accéder à votre portefeuille !"
+    "seed_modal_info_text": "Veuillez noter votre phrase graine et votre mot de passe ! Sans ces informations, vous ne serez pas en mesure d'accéder à votre portefeuille !",
+    "documentation": "Documentation",
+    "github": "GitHub",
+    "matrix": "Matrix",
+    "telegram": "Telegram",
+    "jm_twitter": "JoinMarket Twitter",
+    "jam_twitter": "Jam Twitter",
+    "confirm_locking_modal_title": "Verrouiller le Portefeuille",
+    "fees": {
+      "text_button_cancel": "Annuler",
+      "text_button_submit": "Sauvegarder",
+      "text_button_submitting": "Sauvant..."
+    }
   },
   "send": {
     "loading": "Chargement",


Test patch:
diff --git a/src/components/Settings.test.jsx b/src/components/Settings.test.jsx
index 20aaa4f..a40fdef 100644
--- a/src/components/Settings.test.jsx
+++ b/src/components/Settings.test.jsx
@@ -26,7 +26,7 @@ describe('<Settings />', () => {
       })
     )
 
-    expect(screen.getByText('settings.title')).toBeVisible()
+    expect(screen.getByText('settings.section_title_display')).toBeVisible()
     expect(screen.queryByText(/settings.(show|hide)_balance/)).toBeVisible()
     expect(screen.queryByText(/settings.use_(sats|bitcoin)/)).toBeVisible()
     expect(screen.queryByText(/settings.use_(dark|light)_theme/)).toBeVisible()
@@ -37,8 +37,11 @@ describe('<Settings />', () => {
     expect(screen.queryByText(/settings.button_switch_wallet/)).toBeVisible()
 
     expect(screen.getByText('settings.section_title_community')).toBeVisible()
-    expect(screen.queryByText(/settings.github/)).toBeVisible()
     expect(screen.queryByText(/settings.telegram/)).toBeVisible()
     expect(screen.queryByText(/settings.jm_twitter/)).toBeVisible()
+
+    expect(screen.getByText('settings.section_title_community')).toBeVisible()
+    expect(screen.queryByText(/settings.documentation/)).toBeVisible()
+    expect(screen.queryByText(/settings.github/)).toBeVisible()
   })
 })