From fc87d36b6e22c11bc76fed6e4a7f10709d719ce1 Mon Sep 17 00:00:00 2001 From: Kai Azim Date: Mon, 8 Jul 2024 22:31:46 -0600 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20Improve=20localization=20contex?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Loop/Localizable.xcstrings | 1359 +++++++++++------ Loop/Luminare/Loop/AboutConfiguration.swift | 104 +- .../Behavior/BehaviorConfiguration.swift | 2 +- .../Theming/AccentColorConfiguration.swift | 81 +- Loop/Luminare/Theming/IconConfiguration.swift | 73 +- Loop/Updater/UpdateView.swift | 19 +- 6 files changed, 1081 insertions(+), 557 deletions(-) diff --git a/Loop/Localizable.xcstrings b/Loop/Localizable.xcstrings index 0e8222de..27e36401 100644 --- a/Loop/Localizable.xcstrings +++ b/Loop/Localizable.xcstrings @@ -41,46 +41,6 @@ } } }, - " " : { - "localizations" : { - "en-GB" : { - "stringUnit" : { - "state" : "translated", - "value" : " " - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : " " - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : " " - } - }, - "pt-BR" : { - "stringUnit" : { - "state" : "translated", - "value" : " " - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : " " - } - }, - "zh-HK" : { - "stringUnit" : { - "state" : "translated", - "value" : " " - } - } - } - }, "%" : { "localizations" : { "en-GB" : { @@ -326,25 +286,6 @@ } } } - }, - "🧪 %@ (%lld)" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "🧪 %1$@ (%2$lld)" - } - } - } - }, - "99 problems, updates ain't one." : { - - }, - "A penny for your... lack of updates." : { - - }, - "A watched pot never... updates." : { - }, "About" : { "localizations" : { @@ -639,15 +580,6 @@ } } } - }, - "All systems are a-go!" : { - - }, - "All work and no... no updates..." : { - - }, - "An apple a day keeps the... updates away." : { - }, "Animate window resize" : { "localizations" : { @@ -728,12 +660,6 @@ } } } - }, - "As the loops accumulate, so too will your collection of icons." : { - - }, - "Beggars can't be... updaters." : { - }, "Behavior" : { "localizations" : { @@ -1016,6 +942,7 @@ } }, "Check back next time!" : { + "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -1176,6 +1103,7 @@ } }, "Configure padding..." : { + "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -1214,6 +1142,9 @@ } } } + }, + "Configure padding…" : { + }, "Contributors on GitHub" : { "localizations" : { @@ -1655,53 +1586,6 @@ } } }, - "Default notification content" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "You will now be notified when you unlock a new icon." - } - }, - "en-GB" : { - "stringUnit" : { - "state" : "translated", - "value" : "You will now be notified when you unlock a new icon." - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Te notificaremos cuando desbloquees un nuevo icono" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Verrà inviata una notifica ogni volta che si sblocca una nuova icona." - } - }, - "pt-BR" : { - "stringUnit" : { - "state" : "translated", - "value" : "Você será notificado quando desbloquear um novo ícone." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "你将会在解锁新图标时收到通知。" - } - }, - "zh-HK" : { - "stringUnit" : { - "state" : "translated", - "value" : "你將會在解鎖新圖標時受到通知。" - } - } - } - }, "Design" : { "localizations" : { "en-GB" : { @@ -1981,15 +1865,6 @@ } } } - }, - "Each loop you complete plants the seeds for icons to grow." : { - - }, - "Engage! ...in the current version, it's the latest." : { - - }, - "Every loop brings you closer to the treasure that awaits." : { - }, "Excluded Apps" : { "localizations" : { @@ -2550,15 +2425,6 @@ } } } - }, - "I swear it was here somewhere... one sec" : { - - }, - "I... uhh... one sec I lost it" : { - - }, - "I'm giving it all she's got, Captain! No updates!" : { - }, "Icon" : { "localizations" : { @@ -2641,7 +2507,15 @@ } }, "Icon Locked" : { - + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Locked icon alert title" + } + } + } }, "Icon Name: Black" : { "extractionState" : "extracted_with_value", @@ -3301,6 +3175,17 @@ } } }, + "Icon notifications enabled" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "You will now be notified when you unlock a new icon." + } + } + } + }, "Icon Unlock Message" : { "extractionState" : "extracted_with_value", "localizations" : { @@ -3481,12 +3366,6 @@ } } } - }, - "In a galaxy far, far away... still no updates!" : { - - }, - "In due time, this icon shall be revealed to you." : { - }, "Include development versions" : { "localizations" : { @@ -3609,6 +3488,7 @@ } }, "Install" : { + "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -3687,15 +3567,6 @@ } } } - }, - "Just a small town app, same old version" : { - - }, - "Keep looping, and this icon will be yours in no time." : { - - }, - "Keep up the good work, and this icon will be your reward." : { - }, "Keybindings" : { "localizations" : { @@ -3896,103 +3767,359 @@ } } } - }, - "Like the moon's phases, your icons will reveal themselves in cycles of loops." : { - }, "Locked" : { "comment" : "When an app icon is locked" }, - "Loop" : { - "extractionState" : "stale", + "Locked icon message 1" : { + "extractionState" : "extracted_with_value", "localizations" : { - "en-GB" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "Loop" + "state" : "new", + "value" : "You don’t have that yet!" } - }, - "es" : { + } + } + }, + "Locked icon message 2" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "Loop" + "state" : "new", + "value" : "Who do you think you are, trying to access these top secret icons?" } - }, - "it" : { + } + } + }, + "Locked icon message 3" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "Loop" + "state" : "new", + "value" : "Patience is a virtue, and your key to this icon." } - }, - "pt-BR" : { + } + } + }, + "Locked icon message 4" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "Loop" + "state" : "new", + "value" : "This icon is locked, but your potential is not!" } - }, - "zh-Hans" : { + } + } + }, + "Locked icon message 5" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "Loop" + "state" : "new", + "value" : "Keep Looping, and this icon will be yours in no time." } - }, - "zh-HK" : { + } + } + }, + "Locked icon message 6" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "Loop" + "state" : "new", + "value" : "This icon is still under wraps, stay tuned!" } } } }, - "Loop after loop, your dedication carves the key to success." : { - - }, - "Loop around the obstacles; your reward is just beyond them." : { - - }, - "Loop is in its prime!" : { - - }, - "Loops left to unlock a new icon" : { + "Locked icon message 7" : { + "extractionState" : "extracted_with_value", "localizations" : { "en" : { - "variations" : { - "plural" : { - "one" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld Loop left" - } - }, - "other" : { - "stringUnit" : { - "state" : "new", - "value" : "%lld Loops left" - } - } - } + "stringUnit" : { + "state" : "new", + "value" : "Some icons are worth the wait, don't you think?" } } } }, - "May the Force be with you... next time!" : { + "Locked icon message 8" : { + "extractionState" : "extracted_with_value", "localizations" : { - "en-GB" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "May the Force be with you... next time!" + "state" : "new", + "value" : "Not yet, but you're closer than you were yesterday!" } - }, - "es" : { + } + } + }, + "Locked icon message 9" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "Que la Fuerza esté contigo... la próxima vez!" + "state" : "new", + "value" : "Unlocking this icon is just a matter of time and Loops." } - }, - "it" : { + } + } + }, + "Locked icon message 10" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "Che la Forza sia con te… la prossima volta!" + "state" : "new", + "value" : "This icon is like a fine wine, it needs more time." + } + } + } + }, + "Locked icon message 11" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Stay curious, and soon this icon will be within your reach." + } + } + } + }, + "Locked icon message 12" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Keep up the good work, and this icon will be your reward." + } + } + } + }, + "Locked icon message 13" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "This icon is reserved for the most dedicated Loopers." + } + } + } + }, + "Locked icon message 14" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Your journey is not yet complete, this icon awaits at the end." + } + } + } + }, + "Locked icon message 15" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "In due time, this icon shall be revealed to you." + } + } + } + }, + "Locked icon message 16" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Patience, young Looper, this icon is not far away." + } + } + } + }, + "Locked icon message 17" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "The journey of a thousand Loops begins with a single step." + } + } + } + }, + "Locked icon message 18" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Every Loop brings you closer to the treasure that awaits." + } + } + } + }, + "Locked icon message 19" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "With each Loop, the lock on this icon weakens." + } + } + } + }, + "Locked icon message 20" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Loop after Loop, your dedication carves the key to success." + } + } + } + }, + "Locked icon message 21" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "The icons are not just unlocked; they're earned, Loop by Loop." + } + } + } + }, + "Locked icon message 22" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "As the Loops accumulate, so too will your collection of icons." + } + } + } + }, + "Locked icon message 23" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Think of each Loop as a riddle, solving the mystery of the locked icon." + } + } + } + }, + "Locked icon message 24" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Your persistence in Looping is the master key to all icons." + } + } + } + }, + "Locked icon message 25" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Loop around the obstacles; your reward is just beyond them." + } + } + } + }, + "Locked icon message 26" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Each Loop you complete plants the seeds for icons to grow." + } + } + } + }, + "Locked icon message 27" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Like the moon's phases, your icons will reveal themselves in cycles of Loops." + } + } + } + }, + "Locked icon message 28" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "The icons await, hidden behind the veil of Loops yet to be made." + } + } + } + }, + "Loops left to unlock a new icon" : { + "localizations" : { + "en" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld Loop left" + } + }, + "other" : { + "stringUnit" : { + "state" : "new", + "value" : "%lld Loops left" + } + } + } + } + } + } + }, + "May the Force be with you... next time!" : { + "extractionState" : "stale", + "localizations" : { + "en-GB" : { + "stringUnit" : { + "state" : "translated", + "value" : "May the Force be with you... next time!" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Que la Fuerza esté contigo... la próxima vez!" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Che la Forza sia con te… la prossima volta!" } }, "pt-BR" : { @@ -4054,9 +4181,6 @@ } } } - }, - "Money can't buy... updates." : { - }, "More" : { "localizations" : { @@ -4137,9 +4261,6 @@ } } } - }, - "New version? Sorry, we're too attached to this one." : { - }, "No excluded applications" : { "localizations" : { @@ -4181,90 +4302,573 @@ } } }, - "No keybinds" : { + "No keybinds" : { + "localizations" : { + "en-GB" : { + "stringUnit" : { + "state" : "translated", + "value" : "No keybinds" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin combinaciones" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessuna scorciatoia" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem combinações" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无快捷键" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "無按鍵綁定" + } + } + } + }, + "No new intel, Commander." : { + "extractionState" : "stale", + "localizations" : { + "en-GB" : { + "stringUnit" : { + "state" : "translated", + "value" : "No new intel, Commander." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin novedad, Comandante." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessuna novità, Comandante." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem informação, Comandante" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "没有新的情报,指挥官。" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "沒有新的情報,指揮官。" + } + } + } + }, + "No updates available message 1" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Engage! …in the current version, it's the latest." + } + } + } + }, + "No updates available message 2" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "This app is more up to date than my diary entries!" + } + } + } + }, + "No updates available message 3" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "You're in the clear, no updates in the atmosphere!" + } + } + } + }, + "No updates available message 4" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "The odds are ever in your favor, no updates today!" + } + } + } + }, + "No updates available message 5" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Our app is on a digital diet. No new bytes allowed." + } + } + } + }, + "No updates available message 6" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "New version? Sorry, we're too attached to this one." + } + } + } + }, + "No updates available message 7" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Your Loop is Loopier than ever, no updates found!" + } + } + } + }, + "No updates available message 8" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "I'm giving it all she's got, Captain! No updates!" + } + } + } + }, + "No updates available message 9" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "In a galaxy far, far away… still no updates!" + } + } + } + }, + "No updates available message 10" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "You've got the precious, no updates needed!" + } + } + } + }, + "No updates available message 11" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Riding at warp speed, no updates in sight!" + } + } + } + }, + "No updates available message 12" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "This is not the update you're looking for!" + } + } + } + }, + "No updates available message 13" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "We've misplaced the 'Update' button. Oops!" + } + } + } + }, + "No updates available message 14" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "I swear it was here somewhere… one sec" + } + } + } + }, + "No updates available message 15" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "An apple a day keeps the… updates away." + } + } + } + }, + "No updates available message 16" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "May the Force be with you… next time!" + } + } + } + }, + "No updates available message 17" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "The Force is strong with this version!" + } + } + } + }, + "No updates available message 18" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Just a small town app, same old version" + } + } + } + }, + "No updates available message 19" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Winter is coming. Updates aren't yet." + } + } + } + }, + "No updates available message 20" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Sweet dreams are made of… no updates" + } + } + } + }, + "No updates available message 21" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "The update fairy skipped us this week." + } + } + } + }, + "No updates available message 22" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Stay sharp, more intel coming soon!" + } + } + } + }, + "No updates available message 23" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "You're cruising on the latest tech!" + } + } + } + }, + "No updates available message 24" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "We’ll be back. With updates… later" + } + } + } + }, + "No updates available message 25" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "A penny for your… lack of updates." + } + } + } + }, + "No updates available message 26" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "You've already got the best Loop!" + } + } + } + }, + "No updates available message 27" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "One does not simply update Loop." + } + } + } + }, + "No updates available message 28" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "All work and no… no updates…" + } + } + } + }, + "No updates available message 29" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "A watched pot never… updates." + } + } + } + }, + "No updates available message 30" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "99 problems, updates ain't one." + } + } + } + }, + "No updates available message 31" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "I… uhh… one sec I lost it" + } + } + } + }, + "No updates available message 32" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "You’ve leveled up to the max!" + } + } + } + }, + "No updates available message 33" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Beggars can't be… updaters." + } + } + } + }, + "No updates available message 34" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Money can't buy… updates." + } + } + } + }, + "No updates available message 35" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No new intel, Commander." + } + } + } + }, + "No updates available message 36" : { + "extractionState" : "extracted_with_value", "localizations" : { - "en-GB" : { - "stringUnit" : { - "state" : "translated", - "value" : "No keybinds" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Sin combinaciones" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nessuna scorciatoia" - } - }, - "pt-BR" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "Sem combinações" + "state" : "new", + "value" : "No updates? Great Scott!" } - }, - "zh-Hans" : { + } + } + }, + "No updates available message 37" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "无快捷键" + "state" : "new", + "value" : "No updates, Mr. Anderson" } - }, - "zh-HK" : { + } + } + }, + "No updates available message 38" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "無按鍵綁定" + "state" : "new", + "value" : "No updates in Ba Sing Se" } } } }, - "No new intel, Commander." : { + "No updates available message 39" : { + "extractionState" : "extracted_with_value", "localizations" : { - "en-GB" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "No new intel, Commander." + "state" : "new", + "value" : "Updates? In this economy?" } - }, - "es" : { + } + } + }, + "No updates available message 40" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "Sin novedad, Comandante." + "state" : "new", + "value" : "Check back next time!" } - }, - "it" : { + } + } + }, + "No updates available message 41" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "Nessuna novità, Comandante." + "state" : "new", + "value" : "Loop is in its prime!" } - }, - "pt-BR" : { + } + } + }, + "No updates available message 42" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "Sem informação, Comandante" + "state" : "new", + "value" : "All systems are a-go!" } - }, - "zh-Hans" : { + } + } + }, + "No updates available message 43" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "没有新的情报,指挥官。" + "state" : "new", + "value" : "You're up to date :)" } - }, - "zh-HK" : { + } + } + }, + "No updates available message 44" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { "stringUnit" : { - "state" : "translated", - "value" : "沒有新的情報,指揮官。" + "state" : "new", + "value" : "No updates yet!" } } } - }, - "No updates in Ba Sing Se" : { - }, "No updates yet!" : { + "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -4303,12 +4907,6 @@ } } } - }, - "No updates, Mr. Anderson" : { - - }, - "No updates? Great Scott!" : { - }, "None" : { "localizations" : { @@ -4349,9 +4947,6 @@ } } } - }, - "Not yet, but you're closer than you were yesterday!" : { - }, "Nothing to cycle through" : { "localizations" : { @@ -4393,6 +4988,39 @@ } } }, + "Notification permits: info" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%@'s notification permissions are currently disabled." + } + } + } + }, + "Notification permits: open notification settings" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Open Settings" + } + } + } + }, + "Notification permits: request" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Please turn them on in System Settings." + } + } + } + }, "Notification/Set Icon: Action" : { "extractionState" : "extracted_with_value", "localizations" : { @@ -4482,9 +5110,6 @@ }, "OK" : { - }, - "One does not simply update Loop." : { - }, "Options" : { "localizations" : { @@ -4525,9 +5150,6 @@ } } } - }, - "Our app is on a digital diet. No new bytes allowed." : { - }, "Padding" : { "localizations" : { @@ -4568,12 +5190,6 @@ } } } - }, - "Patience is a virtue, and your key to this icon." : { - - }, - "Patience, young looper, this icon is not far away." : { - }, "Permissions" : { "localizations" : { @@ -5295,47 +5911,6 @@ } } }, - "Resize…" : { - "extractionState" : "stale", - "localizations" : { - "en-GB" : { - "stringUnit" : { - "state" : "translated", - "value" : "Resize…" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Cambiar tamaño..." - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Ridimensiona..." - } - }, - "pt-BR" : { - "stringUnit" : { - "state" : "translated", - "value" : "Redimensionar..." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "调整大小…" - } - }, - "zh-HK" : { - "stringUnit" : { - "state" : "translated", - "value" : "調整大小…" - } - } - } - }, "Respect Stage Manager" : { "localizations" : { "en-GB" : { @@ -5377,6 +5952,7 @@ } }, "Restart to complete" : { + "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -5455,9 +6031,6 @@ } } } - }, - "Riding at warp speed, no updates in sight!" : { - }, "Right" : { "localizations" : { @@ -6105,9 +6678,6 @@ } } } - }, - "Some icons are worth the wait, don't you think?" : { - }, "Stage Manager" : { "localizations" : { @@ -6188,11 +6758,9 @@ } } } - }, - "Stay curious, and soon this icon will be within your reach." : { - }, "Stay sharp, more intel coming soon!" : { + "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -6271,15 +6839,11 @@ } } } - }, - "Sweet dreams are made of... no updates" : { - }, "Sync Wallpaper" : { }, "System" : { - "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -6440,6 +7004,7 @@ } }, "The Force is strong with this version!" : { + "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -6478,21 +7043,6 @@ } } } - }, - "The icons are not just unlocked; they're earned, loop by loop." : { - - }, - "The icons await, hidden behind the veil of loops yet to be made." : { - - }, - "The journey of a thousand loops begins with a single step." : { - - }, - "The odds are ever in your favor, no updates today!" : { - - }, - "The update fairy skipped us this week." : { - }, "Theming" : { "localizations" : { @@ -6573,12 +7123,6 @@ } } } - }, - "Think of each loop as a riddle, solving the mystery of the locked icon." : { - - }, - "This app is more up to date than my diary entries!" : { - }, "This feature is still under development." : { "localizations" : { @@ -6619,20 +7163,9 @@ } } } - }, - "This icon is like a fine wine, it needs more time." : { - - }, - "This icon is locked, but your potential is not!" : { - - }, - "This icon is reserved for the most dedicated loopers." : { - - }, - "This icon is still under wraps, stay tuned!" : { - }, "This is not the update you're looking for!" : { + "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -6831,15 +7364,9 @@ } } } - }, - "Unlocking this icon is just a matter of time and loops." : { - }, "Update…" : { - }, - "Updates? In this economy?" : { - }, "Use coordinates" : { "localizations" : { @@ -7138,13 +7665,7 @@ } } }, - "We’ll be back. With updates... later" : { - - }, - "We've misplaced the 'Update' button. Oops!" : { - - }, - "Who do you think you are, trying to access these top secret icons?" : { + "Wallpaper" : { }, "Width" : { @@ -9548,12 +10069,6 @@ } } } - }, - "Winter is coming. Updates aren't yet." : { - - }, - "With each loop, the lock on this icon weakens." : { - }, "X" : { "localizations" : { @@ -9714,17 +10229,9 @@ } } } - }, - "You don’t have that yet!" : { - - }, - "You're cruising on the latest tech!" : { - - }, - "You're in the clear, no updates in the atmosphere!" : { - }, "You're up to date :)" : { + "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -9765,6 +10272,7 @@ } }, "You've already got the best Loop!" : { + "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -9805,6 +10313,7 @@ } }, "You've got the precious, no updates needed!" : { + "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -9845,6 +10354,7 @@ } }, "You’ve leveled up to the max!" : { + "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -9924,16 +10434,7 @@ } } }, - "You've looped... uhh... I... lost count..." : { - - }, - "Your journey is not yet complete, this icon awaits at the end." : { - - }, - "Your Loop is loopier than ever, no updates found!" : { - - }, - "Your persistence in looping is the master key to all icons." : { + "You've looped… uhh… I… lost count…" : { } }, diff --git a/Loop/Luminare/Loop/AboutConfiguration.swift b/Loop/Luminare/Loop/AboutConfiguration.swift index 801fb2c5..f85c886a 100644 --- a/Loop/Luminare/Loop/AboutConfiguration.swift +++ b/Loop/Luminare/Loop/AboutConfiguration.swift @@ -12,11 +12,10 @@ import SwiftUI class AboutConfigurationModel: ObservableObject { let currentIcon = Defaults[.currentIcon] // no need for didSet since it won't change here - private var shuffledTexts: [LocalizedStringKey] = [] // Store the shuffled texts @Published var isHoveringOverVersionCopier = false - @Published var updateButtonTitle: LocalizedStringKey = "Check for updates…" + @Published var updateButtonTitle: String = .init(localized: "Check for updates…") let credits: [CreditItem] = [ .init( @@ -58,54 +57,55 @@ class AboutConfigurationModel: ObservableObject { ] // A max of 28 W's can fit in here :) - var upToDateText: [LocalizedStringKey] = [ - "Engage! ...in the current version, it's the latest.", - "This app is more up to date than my diary entries!", - "You're in the clear, no updates in the atmosphere!", - "The odds are ever in your favor, no updates today!", - "Our app is on a digital diet. No new bytes allowed.", - "New version? Sorry, we're too attached to this one.", - "Your Loop is loopier than ever, no updates found!", - "I'm giving it all she's got, Captain! No updates!", - "In a galaxy far, far away... still no updates!", - "You've got the precious, no updates needed!", - "Riding at warp speed, no updates in sight!", - "This is not the update you're looking for!", - "We've misplaced the 'Update' button. Oops!", - "I swear it was here somewhere... one sec", - "An apple a day keeps the... updates away.", - "May the Force be with you... next time!", - "The Force is strong with this version!", - "Just a small town app, same old version", - "Winter is coming. Updates aren't yet.", - "Sweet dreams are made of... no updates", - "The update fairy skipped us this week.", - "Stay sharp, more intel coming soon!", - "You're cruising on the latest tech!", - "We’ll be back. With updates... later", - "A penny for your... lack of updates.", - "You've already got the best Loop!", - "One does not simply update Loop.", - "All work and no... no updates...", - "A watched pot never... updates.", - "99 problems, updates ain't one.", - "I... uhh... one sec I lost it", - "You’ve leveled up to the max!", - "Beggars can't be... updaters.", - "Money can't buy... updates.", - "No new intel, Commander.", - "No updates? Great Scott!", - "No updates, Mr. Anderson", - "No updates in Ba Sing Se", - "Updates? In this economy?", - "Check back next time!", - "Loop is in its prime!", - "All systems are a-go!", - "You're up to date :)", - "No updates yet!" + var upToDateText: [String] = [ + .init(localized: "No updates available message 1", defaultValue: "Engage! …in the current version, it's the latest."), + .init(localized: "No updates available message 2", defaultValue: "This app is more up to date than my diary entries!"), + .init(localized: "No updates available message 3", defaultValue: "You're in the clear, no updates in the atmosphere!"), + .init(localized: "No updates available message 4", defaultValue: "The odds are ever in your favor, no updates today!"), + .init(localized: "No updates available message 5", defaultValue: "Our app is on a digital diet. No new bytes allowed."), + .init(localized: "No updates available message 6", defaultValue: "New version? Sorry, we're too attached to this one."), + .init(localized: "No updates available message 7", defaultValue: "Your Loop is Loopier than ever, no updates found!"), + .init(localized: "No updates available message 8", defaultValue: "I'm giving it all she's got, Captain! No updates!"), + .init(localized: "No updates available message 9", defaultValue: "In a galaxy far, far away… still no updates!"), + .init(localized: "No updates available message 10", defaultValue: "You've got the precious, no updates needed!"), + .init(localized: "No updates available message 11", defaultValue: "Riding at warp speed, no updates in sight!"), + .init(localized: "No updates available message 12", defaultValue: "This is not the update you're looking for!"), + .init(localized: "No updates available message 13", defaultValue: "We've misplaced the 'Update' button. Oops!"), + .init(localized: "No updates available message 14", defaultValue: "I swear it was here somewhere… one sec"), + .init(localized: "No updates available message 15", defaultValue: "An apple a day keeps the… updates away."), + .init(localized: "No updates available message 16", defaultValue: "May the Force be with you… next time!"), + .init(localized: "No updates available message 17", defaultValue: "The Force is strong with this version!"), + .init(localized: "No updates available message 18", defaultValue: "Just a small town app, same old version"), + .init(localized: "No updates available message 19", defaultValue: "Winter is coming. Updates aren't yet."), + .init(localized: "No updates available message 20", defaultValue: "Sweet dreams are made of… no updates"), + .init(localized: "No updates available message 21", defaultValue: "The update fairy skipped us this week."), + .init(localized: "No updates available message 22", defaultValue: "Stay sharp, more intel coming soon!"), + .init(localized: "No updates available message 23", defaultValue: "You're cruising on the latest tech!"), + .init(localized: "No updates available message 24", defaultValue: "We’ll be back. With updates… later"), + .init(localized: "No updates available message 25", defaultValue: "A penny for your… lack of updates."), + .init(localized: "No updates available message 26", defaultValue: "You've already got the best Loop!"), + .init(localized: "No updates available message 27", defaultValue: "One does not simply update Loop."), + .init(localized: "No updates available message 28", defaultValue: "All work and no… no updates…"), + .init(localized: "No updates available message 29", defaultValue: "A watched pot never… updates."), + .init(localized: "No updates available message 30", defaultValue: "99 problems, updates ain't one."), + .init(localized: "No updates available message 31", defaultValue: "I… uhh… one sec I lost it"), + .init(localized: "No updates available message 32", defaultValue: "You’ve leveled up to the max!"), + .init(localized: "No updates available message 33", defaultValue: "Beggars can't be… updaters."), + .init(localized: "No updates available message 34", defaultValue: "Money can't buy… updates."), + .init(localized: "No updates available message 35", defaultValue: "No new intel, Commander."), + .init(localized: "No updates available message 36", defaultValue: "No updates? Great Scott!"), + .init(localized: "No updates available message 37", defaultValue: "No updates, Mr. Anderson"), + .init(localized: "No updates available message 38", defaultValue: "No updates in Ba Sing Se"), + .init(localized: "No updates available message 39", defaultValue: "Updates? In this economy?"), + .init(localized: "No updates available message 40", defaultValue: "Check back next time!"), + .init(localized: "No updates available message 41", defaultValue: "Loop is in its prime!"), + .init(localized: "No updates available message 42", defaultValue: "All systems are a-go!"), + .init(localized: "No updates available message 43", defaultValue: "You're up to date :)"), + .init(localized: "No updates available message 44", defaultValue: "No updates yet!") ] + private var shuffledTexts: [String] = [] - func getNextUpToDateText() -> LocalizedStringKey { + func getNextUpToDateText() -> String { // If shuffledTexts is empty, fill it with a shuffled version of upToDateText if shuffledTexts.isEmpty { shuffledTexts = upToDateText.shuffled() @@ -166,7 +166,7 @@ struct AboutConfigurationView: View { Text( model.isHoveringOverVersionCopier ? "Version \(Bundle.main.appVersion ?? "Unknown") (\(Bundle.main.appBuild ?? 0))" - : (timesLooped >= 1_000_000 ? "You've looped... uhh... I... lost count..." : "You've looped \(timesLooped) times!") + : (timesLooped >= 1_000_000 ? "You've looped… uhh… I… lost count…" : "You've looped \(timesLooped) times!") ) .contentTransition(.numericText(countsDown: !model.isHoveringOverVersionCopier)) .animation(LuminareSettingsWindow.animation, value: model.isHoveringOverVersionCopier) @@ -200,7 +200,7 @@ struct AboutConfigurationView: View { let currentTitle = model.updateButtonTitle DispatchQueue.main.asyncAfter(deadline: .now() + 2) { if model.updateButtonTitle == currentTitle { - model.updateButtonTitle = "Check for updates…" + model.updateButtonTitle = .init(localized: "Check for updates…") } } } @@ -212,12 +212,12 @@ struct AboutConfigurationView: View { } .onAppear { if updater.updateState == .available { - model.updateButtonTitle = "Update…" + model.updateButtonTitle = .init(localized: "Update…") } } .onChange(of: updater.updateState) { _ in if updater.updateState == .available { - model.updateButtonTitle = "Update…" + model.updateButtonTitle = .init(localized: "Update…") } } diff --git a/Loop/Luminare/Settings/Behavior/BehaviorConfiguration.swift b/Loop/Luminare/Settings/Behavior/BehaviorConfiguration.swift index d48be1f2..7f6ac2a3 100644 --- a/Loop/Luminare/Settings/Behavior/BehaviorConfiguration.swift +++ b/Loop/Luminare/Settings/Behavior/BehaviorConfiguration.swift @@ -100,7 +100,7 @@ struct BehaviorConfigurationView: View { LuminareToggle("Include padding", isOn: $model.enablePadding) if model.enablePadding { - Button("Configure padding...") { + Button("Configure padding…") { model.isPaddingConfigurationViewPresented = true } .luminareModal(isPresented: $model.isPaddingConfigurationViewPresented) { diff --git a/Loop/Luminare/Theming/AccentColorConfiguration.swift b/Loop/Luminare/Theming/AccentColorConfiguration.swift index 526968d0..dc4a4528 100644 --- a/Loop/Luminare/Theming/AccentColorConfiguration.swift +++ b/Loop/Luminare/Theming/AccentColorConfiguration.swift @@ -9,8 +9,10 @@ import Defaults import Luminare import SwiftUI +// MARK: - Model + class AccentColorConfigurationModel: ObservableObject { - // MARK: - Defaults + // MARK: Defaults @Published var useSystemAccentColor = Defaults[.useSystemAccentColor] { didSet { Defaults[.useSystemAccentColor] = useSystemAccentColor } @@ -38,6 +40,26 @@ class AccentColorConfigurationModel: ObservableObject { } } + // MARK: Color mode helpers + + var isCustom: Bool { + useSystemAccentColor ? false : !processWallpaper + } + + var isWallpaper: Bool { + processWallpaper && !useSystemAccentColor + } + + var accentColorOption: AccentColorOption { + get { + useSystemAccentColor ? .system : (processWallpaper ? .wallpaper : .custom) + } + set { + useSystemAccentColor = newValue == .system + processWallpaper = newValue == .wallpaper + } + } + func syncWallpaper() { Task { await WallpaperProcessor.fetchLatestWallpaperColors() @@ -57,6 +79,26 @@ class AccentColorConfigurationModel: ObservableObject { } } +// MARK: - AccentColorOption + +enum AccentColorOption: LocalizedStringKey, CaseIterable { + case system = "System" + case wallpaper = "Wallpaper" + case custom = "Custom" + + var image: Image { + switch self { + case .system: Image(systemName: "apple.logo") + case .wallpaper: Image(._18PxImageDepth) + case .custom: Image(._18PxColorPalette) + } + } + + var text: LocalizedStringKey { + rawValue + } +} + // MARK: - View struct AccentColorConfigurationView: View { @@ -65,15 +107,15 @@ struct AccentColorConfigurationView: View { var body: some View { LuminareSection { LuminarePicker( - elements: ["System", "Wallpaper", "Custom"], + elements: AccentColorOption.allCases, selection: $model.accentColorOption.animation(LuminareSettingsWindow.animation), columns: 3, roundBottom: model.useSystemAccentColor ) { option in VStack(spacing: 6) { Spacer() - model.image(for: option) - Text(option) + option.image + Text(option.text) Spacer() } .font(.title3) @@ -115,34 +157,3 @@ struct AccentColorConfigurationView: View { } } } - -// MARK: - View Extension - -extension AccentColorConfigurationModel { - var isCustom: Bool { - useSystemAccentColor ? false : !processWallpaper - } - - var isWallpaper: Bool { - processWallpaper && !useSystemAccentColor - } - - var accentColorOption: String { - get { - useSystemAccentColor ? "System" : (processWallpaper ? "Wallpaper" : "Custom") - } - set { - useSystemAccentColor = newValue == "System" - processWallpaper = newValue == "Wallpaper" - } - } - - func image(for option: String) -> Image { - let imageNames = [ - "System": Image(systemName: "apple.logo"), - "Wallpaper": Image(._18PxImageDepth), - "Custom": Image(._18PxColorPalette) - ] - return imageNames[option] ?? Image(systemName: "exclamationmark.triangle") - } -} diff --git a/Loop/Luminare/Theming/IconConfiguration.swift b/Loop/Luminare/Theming/IconConfiguration.swift index 98c3a821..4ee63ab1 100644 --- a/Loop/Luminare/Theming/IconConfiguration.swift +++ b/Loop/Luminare/Theming/IconConfiguration.swift @@ -39,41 +39,44 @@ class IconConfigurationModel: ObservableObject { } @Published var showingLockedAlert = false - @Published var selectedLockedMessage: LocalizedStringKey = .init("") - let lockedMessages: [LocalizedStringKey] = [ - "You don’t have that yet!", - "Who do you think you are, trying to access these top secret icons?", - "Patience is a virtue, and your key to this icon.", - "This icon is locked, but your potential is not!", - "Keep looping, and this icon will be yours in no time.", - "This icon is still under wraps, stay tuned!", - "Some icons are worth the wait, don't you think?", - "Not yet, but you're closer than you were yesterday!", - "Unlocking this icon is just a matter of time and loops.", - "This icon is like a fine wine, it needs more time.", - "Stay curious, and soon this icon will be within your reach.", - "Keep up the good work, and this icon will be your reward.", - "This icon is reserved for the most dedicated loopers.", - "Your journey is not yet complete, this icon awaits at the end.", - "In due time, this icon shall be revealed to you.", - "Patience, young looper, this icon is not far away.", - "The journey of a thousand loops begins with a single step.", - "Every loop brings you closer to the treasure that awaits.", - "With each loop, the lock on this icon weakens.", - "Loop after loop, your dedication carves the key to success.", - "The icons are not just unlocked; they're earned, loop by loop.", - "As the loops accumulate, so too will your collection of icons.", - "Think of each loop as a riddle, solving the mystery of the locked icon.", - "Your persistence in looping is the master key to all icons.", - "Loop around the obstacles; your reward is just beyond them.", - "Each loop you complete plants the seeds for icons to grow.", - "Like the moon's phases, your icons will reveal themselves in cycles of loops.", - "The icons await, hidden behind the veil of loops yet to be made." + @Published var selectedLockedMessage: String = "" + let lockedMessages: [String] = [ + .init(localized: "Locked icon message 1", defaultValue: "You don’t have that yet!"), + .init(localized: "Locked icon message 2", defaultValue: "Who do you think you are, trying to access these top secret icons?"), + .init(localized: "Locked icon message 3", defaultValue: "Patience is a virtue, and your key to this icon."), + .init(localized: "Locked icon message 4", defaultValue: "This icon is locked, but your potential is not!"), + .init(localized: "Locked icon message 5", defaultValue: "Keep Looping, and this icon will be yours in no time."), + .init(localized: "Locked icon message 6", defaultValue: "This icon is still under wraps, stay tuned!"), + .init(localized: "Locked icon message 7", defaultValue: "Some icons are worth the wait, don't you think?"), + .init(localized: "Locked icon message 8", defaultValue: "Not yet, but you're closer than you were yesterday!"), + .init(localized: "Locked icon message 9", defaultValue: "Unlocking this icon is just a matter of time and Loops."), + .init(localized: "Locked icon message 10", defaultValue: "This icon is like a fine wine, it needs more time."), + .init(localized: "Locked icon message 11", defaultValue: "Stay curious, and soon this icon will be within your reach."), + .init(localized: "Locked icon message 12", defaultValue: "Keep up the good work, and this icon will be your reward."), + .init(localized: "Locked icon message 13", defaultValue: "This icon is reserved for the most dedicated Loopers."), + .init(localized: "Locked icon message 14", defaultValue: "Your journey is not yet complete, this icon awaits at the end."), + .init(localized: "Locked icon message 15", defaultValue: "In due time, this icon shall be revealed to you."), + .init(localized: "Locked icon message 16", defaultValue: "Patience, young Looper, this icon is not far away."), + .init(localized: "Locked icon message 17", defaultValue: "The journey of a thousand Loops begins with a single step."), + .init(localized: "Locked icon message 18", defaultValue: "Every Loop brings you closer to the treasure that awaits."), + .init(localized: "Locked icon message 19", defaultValue: "With each Loop, the lock on this icon weakens."), + .init(localized: "Locked icon message 20", defaultValue: "Loop after Loop, your dedication carves the key to success."), + .init(localized: "Locked icon message 21", defaultValue: "The icons are not just unlocked; they're earned, Loop by Loop."), + .init(localized: "Locked icon message 22", defaultValue: "As the Loops accumulate, so too will your collection of icons."), + .init(localized: "Locked icon message 23", defaultValue: "Think of each Loop as a riddle, solving the mystery of the locked icon."), + .init(localized: "Locked icon message 24", defaultValue: "Your persistence in Looping is the master key to all icons."), + .init(localized: "Locked icon message 25", defaultValue: "Loop around the obstacles; your reward is just beyond them."), + .init(localized: "Locked icon message 26", defaultValue: "Each Loop you complete plants the seeds for icons to grow."), + .init(localized: "Locked icon message 27", defaultValue: "Like the moon's phases, your icons will reveal themselves in cycles of Loops."), + .init(localized: "Locked icon message 28", defaultValue: "The icons await, hidden behind the veil of Loops yet to be made.") ] private func handleNotificationChange() { if notificationWhenIconUnlocked { - AppDelegate.sendNotification(Bundle.main.appName, "You will now be notified when you unlock a new icon.") + AppDelegate.sendNotification( + Bundle.main.appName, + .init(localized: "Icon notifications enabled", defaultValue: "You will now be notified when you unlock a new icon.") + ) if !AppDelegate.areNotificationsEnabled() { notificationWhenIconUnlocked = false userDisabledNotificationsAlert() @@ -84,9 +87,9 @@ class IconConfigurationModel: ObservableObject { private func userDisabledNotificationsAlert() { guard let window = LuminareManager.luminare else { return } let alert = NSAlert() - alert.messageText = "\(Bundle.main.appName)'s notification permissions are currently disabled." - alert.informativeText = "Please turn them on in System Settings." - alert.addButton(withTitle: "Open Settings") + alert.messageText = .init(localized: "Notification permits: info", defaultValue: "\(Bundle.main.appName)'s notification permissions are currently disabled.") + alert.informativeText = .init(localized: "Notification permits: request", defaultValue: "Please turn them on in System Settings.") + alert.addButton(withTitle: .init(localized: "Notification permits: open notification settings", defaultValue: "Open Settings")) alert.alertStyle = .warning alert.beginSheetModal(for: window) { modalResponse in @@ -119,7 +122,7 @@ struct IconConfigurationView: View { .aspectRatio(1, contentMode: .fit) .alert(isPresented: $model.showingLockedAlert) { Alert( - title: Text("Icon Locked"), + title: Text(.init(localized: "Icon Locked", defaultValue: "Locked icon alert title")), message: Text(model.selectedLockedMessage), dismissButton: .default(Text("OK")) ) diff --git a/Loop/Updater/UpdateView.swift b/Loop/Updater/UpdateView.swift index 33094b3a..22b08229 100644 --- a/Loop/Updater/UpdateView.swift +++ b/Loop/Updater/UpdateView.swift @@ -83,7 +83,8 @@ struct UpdateView: View { .padding(.horizontal, 4) } - Text(isInstalling ? " " : readyToRestart ? "Restart to complete" : "Install") + let tenSpaces = " " // This helps with alignment for the animation once the update finishes + Text(isInstalling ? tenSpaces : readyToRestart ? "Restart to complete" : "Install") .contentTransition(.numericText()) .opacity(isInstalling ? 0 : 1) } @@ -151,13 +152,21 @@ struct UpdateView: View { func versionChangeText() -> some View { HStack { if let targetRelease = updater.targetRelease, targetRelease.prerelease { - Text("🧪 \(Bundle.main.appVersion ?? "Unknown") (\(Bundle.main.appBuild ?? 0))") + let currentVersion = "🧪 \(Bundle.main.appVersion ?? "Unknown") (\(Bundle.main.appBuild ?? 0))" + Text(currentVersion) + Image(systemName: "arrow.right") - Text("🧪 \(targetRelease.tagName) (\(targetRelease.buildNumber ?? 0))") + + let newVersion = "🧪 \(targetRelease.tagName) (\(targetRelease.buildNumber ?? 0))" + Text(newVersion) } else { - Text(Bundle.main.appVersion ?? "Unknown") + let currentVersion = Bundle.main.appVersion ?? "Unknown" + Text(currentVersion) + Image(systemName: "arrow.right") - Text(updater.targetRelease?.tagName ?? "Unknown") + + let newVersion = updater.targetRelease?.tagName ?? "Unknown" + Text(newVersion) } } } From 9b5bd611d972bee6fefe9405a7e1a9686562a772 Mon Sep 17 00:00:00 2001 From: Kai Azim Date: Mon, 8 Jul 2024 22:35:43 -0600 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9C=A8=20Add=20more=20context=20with=20a?= =?UTF-8?q?ccent=20colors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Loop/Localizable.xcstrings | 84 ++++++++----------- .../Theming/AccentColorConfiguration.swift | 16 ++-- Loop/Luminare/Theming/IconConfiguration.swift | 4 +- 3 files changed, 46 insertions(+), 58 deletions(-) diff --git a/Loop/Localizable.xcstrings b/Loop/Localizable.xcstrings index 27e36401..84297dbc 100644 --- a/Loop/Localizable.xcstrings +++ b/Loop/Localizable.xcstrings @@ -367,6 +367,39 @@ } } }, + "Accent color option: Custom" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Custom" + } + } + } + }, + "Accent color option: System" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "System" + } + } + } + }, + "Accent color option: Wallpaper" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Wallpaper" + } + } + } + }, "Accessibility access" : { "localizations" : { "en-GB" : { @@ -6844,6 +6877,7 @@ }, "System" : { + "extractionState" : "stale", "localizations" : { "en-GB" : { "stringUnit" : { @@ -7568,53 +7602,6 @@ } } }, - "Version %@ (%@)" : { - "extractionState" : "stale", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Version %1$@ (%2$@)" - } - }, - "en-GB" : { - "stringUnit" : { - "state" : "translated", - "value" : "Version %1$@ (%2$@)" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Versión %1$@ (%2$@)" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Versione %1$@ (%2$@)" - } - }, - "pt-BR" : { - "stringUnit" : { - "state" : "translated", - "value" : "Versão %1$@ (%2$@)" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%1$@版本(%2$@)" - } - }, - "zh-HK" : { - "stringUnit" : { - "state" : "translated", - "value" : "%1$@版本(%2$@)" - } - } - } - }, "Version %@ (%lld)" : { "localizations" : { "en" : { @@ -7664,9 +7651,6 @@ } } } - }, - "Wallpaper" : { - }, "Width" : { "localizations" : { diff --git a/Loop/Luminare/Theming/AccentColorConfiguration.swift b/Loop/Luminare/Theming/AccentColorConfiguration.swift index dc4a4528..965dd4d3 100644 --- a/Loop/Luminare/Theming/AccentColorConfiguration.swift +++ b/Loop/Luminare/Theming/AccentColorConfiguration.swift @@ -81,10 +81,10 @@ class AccentColorConfigurationModel: ObservableObject { // MARK: - AccentColorOption -enum AccentColorOption: LocalizedStringKey, CaseIterable { - case system = "System" - case wallpaper = "Wallpaper" - case custom = "Custom" +enum AccentColorOption: CaseIterable { + case system + case wallpaper + case custom var image: Image { switch self { @@ -94,8 +94,12 @@ enum AccentColorOption: LocalizedStringKey, CaseIterable { } } - var text: LocalizedStringKey { - rawValue + var text: String { + switch self { + case .system: .init(localized: "Accent color option: System", defaultValue: "System") + case .wallpaper: .init(localized: "Accent color option: Wallpaper", defaultValue: "Wallpaper") + case .custom: .init(localized: "Accent color option: Custom", defaultValue: "Custom") + } } } diff --git a/Loop/Luminare/Theming/IconConfiguration.swift b/Loop/Luminare/Theming/IconConfiguration.swift index 4ee63ab1..46228ce8 100644 --- a/Loop/Luminare/Theming/IconConfiguration.swift +++ b/Loop/Luminare/Theming/IconConfiguration.swift @@ -163,8 +163,8 @@ struct IconVew: View { .foregroundStyle(.secondary) Text(nextUnlockCount == icon.unlockTime ? - .init(localized: "Loops left to unlock a new icon", defaultValue: "\(loopsLeft) Loops left") : - .init(localized: "Locked", comment: "When an app icon is locked") + .init(localized: "Loops left to unlock new icon", defaultValue: "\(loopsLeft) Loops left") : + .init(localized: "Locked", comment: "App icon is locked") ) .font(.caption) .foregroundColor(.secondary) From 58593d5b58988afb16b3fc970131acbf265968c8 Mon Sep 17 00:00:00 2001 From: Kai Azim Date: Mon, 8 Jul 2024 23:15:48 -0600 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=8C=90=20Remove=20useless=20strings?= =?UTF-8?q?=20+=20add=20more=20context?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xcshareddata/xcschemes/Loop.xcscheme | 2 +- Loop/Localizable.xcstrings | 211 ++++-------------- .../CustomActionConfigurationView.swift | 8 +- .../Keybind Recorder/Keycorder.swift | 20 +- .../KeybindingsConfiguration.swift | 2 +- .../CustomWindowActionUnit.swift | 6 +- 6 files changed, 64 insertions(+), 185 deletions(-) diff --git a/Loop.xcodeproj/xcshareddata/xcschemes/Loop.xcscheme b/Loop.xcodeproj/xcshareddata/xcschemes/Loop.xcscheme index ff96d07c..dfd78761 100644 --- a/Loop.xcodeproj/xcshareddata/xcschemes/Loop.xcscheme +++ b/Loop.xcodeproj/xcshareddata/xcschemes/Loop.xcscheme @@ -10,7 +10,7 @@ ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction"> = keyLimit { - errorMessage = Text( - "You can only use up to \(keyLimit) keys in a keybind, including the trigger key." - ) + errorMessage = "You can only use up to \(keyLimit) keys in a keybind, including the trigger key." shouldShake.toggle() shouldError = true } else { @@ -151,14 +149,12 @@ struct Keycorder: View { willSet = false if keybind.direction == .custom { if let name = keybind.name { - self.errorMessage = Text("That keybind is already being used by \(name).") + self.errorMessage = "That keybind is already being used by \(name)." } else { - self.errorMessage = Text("That keybind is already being used by another custom keybind.") + self.errorMessage = "That keybind is already being used by another custom keybind." } } else { - self.errorMessage = Text( - "That keybind is already being used by \(keybind.direction.name.lowercased())." - ) + self.errorMessage = "That keybind is already being used by \(keybind.direction.name.lowercased())." } self.shouldShake.toggle() self.shouldError = true diff --git a/Loop/Luminare/Settings/Keybindings/KeybindingsConfiguration.swift b/Loop/Luminare/Settings/Keybindings/KeybindingsConfiguration.swift index 54b4589f..77a189c7 100644 --- a/Loop/Luminare/Settings/Keybindings/KeybindingsConfiguration.swift +++ b/Loop/Luminare/Settings/Keybindings/KeybindingsConfiguration.swift @@ -59,7 +59,7 @@ struct KeybindingsConfigurationView: View { "Trigger delay", value: $model.triggerDelay, sliderRange: 0...1, - suffix: .init(.init(localized: "Seconds", defaultValue: "s")), + suffix: .init(.init(localized: "Measurement unit: seconds", defaultValue: "s")), step: 0.1, lowerClamp: true, decimalPlaces: 1 diff --git a/Loop/Window Management/Custom Window Sizes/CustomWindowActionUnit.swift b/Loop/Window Management/Custom Window Sizes/CustomWindowActionUnit.swift index 8503056e..2822f78d 100644 --- a/Loop/Window Management/Custom Window Sizes/CustomWindowActionUnit.swift +++ b/Loop/Window Management/Custom Window Sizes/CustomWindowActionUnit.swift @@ -13,12 +13,12 @@ enum CustomWindowActionUnit: Int, Codable, CaseIterable, Identifiable { case pixels = 0 case percentage = 1 - var suffix: LocalizedStringKey { + var suffix: String { switch self { case .pixels: - "px" + .init(localized: "Measurement unit: pixels", defaultValue: "px") case .percentage: - "%" + .init(localized: "Measurement unit: percentage", defaultValue: "%") } } }