diff --git a/Hinge.xcodeproj/project.pbxproj b/Hinge.xcodeproj/project.pbxproj
index 3aaa85a..a2c29a4 100644
--- a/Hinge.xcodeproj/project.pbxproj
+++ b/Hinge.xcodeproj/project.pbxproj
@@ -172,6 +172,42 @@
fileRef
560737C72BC60145ADB91F3E
+ 6B2D8F1A3C5E7A9B0D1F2E30
+
+ isa
+ PBXVariantGroup
+ children
+
+ 3059B037752ACEDB91C5F511
+ AA31F262039679D2414D52C2
+ 6CE6D5AC0DB41C126672BB9D
+ 2B8E1BC7AD243AF3870134C0
+ 5AD54BB7F98474534A4C83ED
+ CCCE2CDFEC65CE9BDE7A395C
+ 6A63B12EA753108E36C52FD2
+ C705DCF21CBF7AD5F970621B
+ 24D3149B3CE03CFD94C2DD17
+ A695FBDE60D96D7150C64BDA
+ 1A3376B19763C58977411E38
+ B7AEFB7AF84345927382DF05
+ 6897C8C1DE6E11BE7321E76A
+ 931FCD7B91696BF504041199
+ 61CBDB8F979D36CA892B91C8
+ 379C3C0E9C4614AF3A01076B
+ 0278DE9A6B04F8478495CAD6
+
+ name
+ Localizable.strings
+ sourceTree
+ <group>
+
+ 8C3E9A2B4D6F8A0C1E3F5A71
+
+ isa
+ PBXBuildFile
+ fileRef
+ 6B2D8F1A3C5E7A9B0D1F2E30
+
38D78C33EBAE0C0ED96716CF
isa
@@ -218,6 +254,7 @@
560737C72BC60145ADB91F3E
38D78C33EBAE0C0ED96716CF
+ AA37C8D01B6242599BE403F1
path
Resources
@@ -305,6 +342,7 @@
51C92A1C51E552B028484AA9
F7F4970B79E37D1A4C454958
+ 8C3E9A2B4D6F8A0C1E3F5A71
runOnlyForDeploymentPostprocessing
0
@@ -514,6 +552,22 @@
en
Base
+ ar
+ de
+ es
+ fr
+ it
+ ja
+ ko
+ nl
+ pl
+ pt-BR
+ ru
+ tr
+ vi
+ zh-Hans
+ zh-Hant
+ hi
mainGroup
B28B7AF69320201D1CF206EB
@@ -528,6 +582,240 @@
0E8A3AD980EC179856012B7E
+ 3059B037752ACEDB91C5F511
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ ar
+ path
+ ar.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ AA31F262039679D2414D52C2
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ de
+ path
+ de.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ 6CE6D5AC0DB41C126672BB9D
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ es
+ path
+ es.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ 2B8E1BC7AD243AF3870134C0
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ fr
+ path
+ fr.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ 5AD54BB7F98474534A4C83ED
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ it
+ path
+ it.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ CCCE2CDFEC65CE9BDE7A395C
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ ja
+ path
+ ja.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ 6A63B12EA753108E36C52FD2
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ ko
+ path
+ ko.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ C705DCF21CBF7AD5F970621B
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ nl
+ path
+ nl.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ 24D3149B3CE03CFD94C2DD17
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ pl
+ path
+ pl.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ A695FBDE60D96D7150C64BDA
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ pt-BR
+ path
+ pt-BR.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ 1A3376B19763C58977411E38
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ ru
+ path
+ ru.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ B7AEFB7AF84345927382DF05
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ tr
+ path
+ tr.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ 6897C8C1DE6E11BE7321E76A
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ vi
+ path
+ vi.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ 931FCD7B91696BF504041199
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ zh-Hans
+ path
+ zh-Hans.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ 61CBDB8F979D36CA892B91C8
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ zh-Hant
+ path
+ zh-Hant.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ 379C3C0E9C4614AF3A01076B
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ en
+ path
+ en.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ 0278DE9A6B04F8478495CAD6
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.strings
+ name
+ hi
+ path
+ hi.lproj/Localizable.strings
+ sourceTree
+ <group>
+
+ AA37C8D01B6242599BE403F1
+
+ isa
+ PBXGroup
+ children
+
+ 6B2D8F1A3C5E7A9B0D1F2E30
+
+ path
+ Localizations
+ sourceTree
+ <group>
+
rootObject
98F54143AB4E86B28C3AFEE0
diff --git a/Info.plist b/Info.plist
index 70e2a69..443b971 100644
--- a/Info.plist
+++ b/Info.plist
@@ -2,6 +2,28 @@
+ CFBundleDevelopmentRegion
+ en
+ CFBundleLocalizations
+
+ en
+ ar
+ de
+ es
+ fr
+ it
+ ja
+ ko
+ nl
+ pl
+ pt-BR
+ ru
+ tr
+ vi
+ zh-Hans
+ zh-Hant
+ hi
+
CFBundleExecutable
Hinge
CFBundleIdentifier
diff --git a/Makefile b/Makefile
index 9399013..4927157 100644
--- a/Makefile
+++ b/Makefile
@@ -5,8 +5,9 @@ SIGN_IDENTITY ?= $(shell security find-identity -v -p codesigning 2>/dev/null |
.PHONY: build
build:
- mkdir -p "$(APP)/Contents/MacOS" "$(APP)/Contents/Resources"
+ mkdir -p "$(APP)/Contents/MacOS" "$(APP)/Contents/Resources/en.lproj"
xcrun swiftc -swift-version 5 -O -target arm64-apple-macosx14.0 $(SOURCES) -o "$(APP)/Contents/MacOS/Hinge" -framework SwiftUI -framework AppKit -framework IOKit -framework ScreenCaptureKit -framework MetalKit -framework MetalPerformanceShaders
cp Info.plist "$(APP)/Contents/Info.plist"
- cp Resources/* "$(APP)/Contents/Resources/"
+ cp Resources/*.icns Resources/*.metal "$(APP)/Contents/Resources/"
+ cp -R Resources/Localizations/*.lproj "$(APP)/Contents/Resources/"
codesign --force --sign "$(if $(SIGN_IDENTITY),$(SIGN_IDENTITY),-)" "$(APP)"
diff --git a/README.md b/README.md
index 01cc68e..a4751b4 100644
--- a/README.md
+++ b/README.md
@@ -25,8 +25,14 @@ open build/Hinge.app
Allow Screen Recording, reopen Hinge if prompted, and turn it on. It turns itself back on the next time you open it. The starting angle is 100°. Prefer something else? Get comfy and click **Set open position**. Hinge remembers.
+Hinge speaks your Mac's language: English, Simplified and Traditional Chinese, Japanese, Korean, German, French, Spanish, Italian, Brazilian Portuguese, Russian, Dutch, Turkish, Polish, Arabic, Vietnamese and Hindi. To use a different one, pick it under **Settings > Controls > Language**.
+
## Got an idea?
Feature requests are welcome. [Open an issue](https://github.com/Noveum/hinge/issues) or just shoot a PR. Small fixes, smoother motion, fun ideas: come play.
[Development checks and setup](CHECKS.md).
+
+## Translations
+
+Translations live in `Resources/Localizations/.lproj/Localizable.strings`, one file per language, including Hindi. On first launch, Hinge saves the best supported match for the system language. Later launches retain that choice until you change it in Settings. Keep the English keys identical across files and preserve format placeholders such as `%@` and `%lld`. Both Make and Xcode bundle these files directly.
diff --git a/Resources/Localizations/ar.lproj/Localizable.strings b/Resources/Localizations/ar.lproj/Localizable.strings
new file mode 100644
index 0000000..6998fb1
--- /dev/null
+++ b/Resources/Localizations/ar.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "حول";
+"Allow Hinge in Login Items to finish." = "اسمح لـ Hinge في عناصر تسجيل الدخول لإكمال الإعداد.";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "اسمح لـ Hinge في إعدادات تسجيل الشاشة، ثم أنهِه وافتحه من جديد.";
+"Allowed" = "مسموح";
+"Attention" = "تنبيه";
+"Back" = "رجوع";
+"Beside the folded desktop" = "بجانب سطح المكتب المطوي";
+"Black" = "أسود";
+"Blur" = "تمويه";
+"Connected" = "متصل";
+"Controls" = "عناصر التحكم";
+"Could not allocate the desktop texture." = "تعذر تخصيص نسيج سطح المكتب.";
+"Could not allocate the renderer warmup texture." = "تعذر تخصيص نسيج التهيئة للعرض.";
+"Could not initialize the desktop texture." = "تعذرت تهيئة نسيج سطح المكتب.";
+"Could not prepare the desktop renderer." = "تعذر تجهيز عرض سطح المكتب.";
+"Could not prepare the fold pipeline." = "تعذر تجهيز مسار عرض الطيّة.";
+"Could not update Launch at Login: %@" = "تعذر تحديث «الفتح عند تسجيل الدخول»: %@";
+"Could not update the captured windows: %@" = "تعذر تحديث النوافذ المسجلة: %@";
+"Effect strength" = "قوة التأثير";
+"Getting the desktop and the sensor ready." = "جارٍ تجهيز سطح المكتب والمستشعر.";
+"Hinge could not register ⌃⌥H (error %d)." = "تعذر على Hinge تسجيل ⌃⌥H (الخطأ %d).";
+"Hinge is on but not running yet." = "Hinge مُفعّل لكنه لا يعمل بعد.";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "يقرأ Hinge شاشتك فقط لرسم الطيّة. تبقى الإطارات في ذاكرة جهاز Mac لديك.";
+"Keyboard shortcut unavailable" = "اختصار لوحة المفاتيح غير متاح";
+"Language" = "اللغة";
+"Launch at login" = "الفتح عند تسجيل الدخول";
+"Lid angle sensor" = "مستشعر زاوية الغطاء";
+"Look" = "المظهر";
+"Metal is unavailable on this Mac." = "Metal غير متاح على جهاز Mac هذا.";
+"Needed to show your live desktop" = "مطلوب لعرض سطح المكتب المباشر";
+"No built-in MacBook display was found." = "لم يتم العثور على الشاشة المدمجة في MacBook.";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "لم تصل إطارات سطح المكتب. تحقق من إذن تسجيل الشاشة وأعد فتح Hinge.";
+"Not connected" = "غير متصل";
+"Off" = "متوقف";
+"On" = "مُفعّل";
+"Open Hinge" = "فتح Hinge";
+"Open Login Items" = "فتح عناصر تسجيل الدخول";
+"Open Settings" = "فتح الإعدادات";
+"Open position" = "وضع الفتح";
+"Open the lid to your comfortable viewing position first." = "افتح الغطاء أولًا إلى زاوية المشاهدة المريحة لك.";
+"Quit Hinge" = "إنهاء Hinge";
+"Relaunch" = "إعادة التشغيل";
+"Relaunch Hinge to switch languages." = "أعد تشغيل Hinge لتغيير اللغة.";
+"Reset effect strength to 100%" = "إعادة تعيين قوة التأثير إلى 100٪";
+"Reset effect strength to default" = "إعادة تعيين قوة التأثير إلى القيمة الافتراضية";
+"Save the lid angle you are viewing at right now" = "حفظ زاوية الغطاء التي تنظر منها الآن";
+"Screen Recording" = "تسجيل الشاشة";
+"Set" = "تعيين";
+"Set open position" = "تعيين وضع الفتح";
+"Settings" = "الإعدادات";
+"Settings…" = "الإعدادات…";
+"Sides" = "الجانبان";
+"Starting…" = "جارٍ البدء…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "يبدأ عند 100°. اضبط وضع الفتح المريح لك مرة واحدة، وسيتذكره Hinge.";
+"Status" = "الحالة";
+"System Language" = "لغة النظام";
+"The desktop renderer is missing. Rebuild the app." = "مكوّن عرض سطح المكتب مفقود. أعد بناء التطبيق.";
+"The desktop renderer stopped: %@" = "توقف عرض سطح المكتب: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "توقف مستشعر الغطاء عن الاستجابة. سيعود Hinge للعمل فور إعادة الاتصال.";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "يبدو أن جهاز Mac هذا لا يحتوي على مستشعر لزاوية الغطاء، لذا لا يستطيع Hinge تتبُّع الغطاء.";
+"Turn Hinge on or off" = "تشغيل Hinge أو إيقافه";
+"Turn Hinge on to follow the lid." = "شغّل Hinge ليتتبّع الغطاء.";
+"Turn off" = "إيقاف";
+"Turn on" = "تشغيل";
+"Waiting for the lid angle sensor." = "بانتظار مستشعر زاوية الغطاء.";
+"Waiting…" = "جارٍ الانتظار…";
+"Your desktop bends as the lid closes." = "ينحني سطح المكتب عند إغلاق الغطاء.";
+"Your desktop follows your lid." = "سطح المكتب يتبع الغطاء.";
+"⌃⌥H anywhere" = "⌃⌥H من أي مكان";
diff --git a/Resources/Localizations/de.lproj/Localizable.strings b/Resources/Localizations/de.lproj/Localizable.strings
new file mode 100644
index 0000000..9a1826c
--- /dev/null
+++ b/Resources/Localizations/de.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "Über";
+"Allow Hinge in Login Items to finish." = "Erlaube Hinge in den Anmeldeobjekten, um den Vorgang abzuschließen.";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "Erlaube Hinge in den Einstellungen für Bildschirmaufnahme, beende die App und öffne sie erneut.";
+"Allowed" = "Erlaubt";
+"Attention" = "Hinweis";
+"Back" = "Zurück";
+"Beside the folded desktop" = "Neben dem gefalteten Schreibtisch";
+"Black" = "Schwarz";
+"Blur" = "Unschärfe";
+"Connected" = "Verbunden";
+"Controls" = "Steuerung";
+"Could not allocate the desktop texture." = "Die Schreibtischtextur konnte nicht angelegt werden.";
+"Could not allocate the renderer warmup texture." = "Die Aufwärmtextur des Renderers konnte nicht angelegt werden.";
+"Could not initialize the desktop texture." = "Die Schreibtischtextur konnte nicht initialisiert werden.";
+"Could not prepare the desktop renderer." = "Der Schreibtisch-Renderer konnte nicht vorbereitet werden.";
+"Could not prepare the fold pipeline." = "Die Faltungspipeline konnte nicht vorbereitet werden.";
+"Could not update Launch at Login: %@" = "„Bei der Anmeldung öffnen“ konnte nicht aktualisiert werden: %@";
+"Could not update the captured windows: %@" = "Die aufgenommenen Fenster konnten nicht aktualisiert werden: %@";
+"Effect strength" = "Effektstärke";
+"Getting the desktop and the sensor ready." = "Schreibtisch und Sensor werden vorbereitet.";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge konnte ⌃⌥H nicht registrieren (Fehler %d).";
+"Hinge is on but not running yet." = "Hinge ist eingeschaltet, läuft aber noch nicht.";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge liest deinen Bildschirm nur, um die Faltung zu zeichnen. Die Bilder bleiben im Arbeitsspeicher deines Mac.";
+"Keyboard shortcut unavailable" = "Tastaturkurzbefehl nicht verfügbar";
+"Language" = "Sprache";
+"Launch at login" = "Bei der Anmeldung öffnen";
+"Lid angle sensor" = "Deckelwinkelsensor";
+"Look" = "Darstellung";
+"Metal is unavailable on this Mac." = "Metal ist auf diesem Mac nicht verfügbar.";
+"Needed to show your live desktop" = "Nötig, um deinen Live-Schreibtisch zu zeigen";
+"No built-in MacBook display was found." = "Kein integrierter MacBook-Bildschirm gefunden.";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "Es kamen keine Schreibtischbilder an. Prüfe die Berechtigung für Bildschirmaufnahme und öffne Hinge erneut.";
+"Not connected" = "Nicht verbunden";
+"Off" = "Aus";
+"On" = "Ein";
+"Open Hinge" = "Hinge öffnen";
+"Open Login Items" = "Anmeldeobjekte öffnen";
+"Open Settings" = "Einstellungen öffnen";
+"Open position" = "Öffnungsposition";
+"Open the lid to your comfortable viewing position first." = "Öffne den Deckel zuerst auf deinen bevorzugten Blickwinkel.";
+"Quit Hinge" = "Hinge beenden";
+"Relaunch" = "Neu starten";
+"Relaunch Hinge to switch languages." = "Starte Hinge neu, um die Sprache zu wechseln.";
+"Reset effect strength to 100%" = "Effektstärke auf 100 % zurücksetzen";
+"Reset effect strength to default" = "Effektstärke auf Standard zurücksetzen";
+"Save the lid angle you are viewing at right now" = "Speichert den Deckelwinkel, in dem du gerade auf den Bildschirm schaust";
+"Screen Recording" = "Bildschirmaufnahme";
+"Set" = "Festlegen";
+"Set open position" = "Öffnungsposition festlegen";
+"Settings" = "Einstellungen";
+"Settings…" = "Einstellungen …";
+"Sides" = "Seiten";
+"Starting…" = "Wird gestartet …";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "Standard ist 100°. Lege einmal deine bevorzugte Öffnungsposition fest, Hinge merkt sie sich.";
+"Status" = "Status";
+"System Language" = "Systemsprache";
+"The desktop renderer is missing. Rebuild the app." = "Der Schreibtisch-Renderer fehlt. Erstelle die App neu.";
+"The desktop renderer stopped: %@" = "Die Schreibtischdarstellung wurde angehalten: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "Der Deckelsensor reagiert nicht mehr. Hinge schaltet sich wieder ein, sobald er wieder verbunden ist.";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "Dieser Mac scheint keinen Deckelwinkelsensor zu haben, daher kann Hinge dem Deckel nicht folgen.";
+"Turn Hinge on or off" = "Hinge ein- oder ausschalten";
+"Turn Hinge on to follow the lid." = "Schalte Hinge ein, damit es dem Deckel folgt.";
+"Turn off" = "Ausschalten";
+"Turn on" = "Einschalten";
+"Waiting for the lid angle sensor." = "Warten auf den Deckelwinkelsensor.";
+"Waiting…" = "Warten …";
+"Your desktop bends as the lid closes." = "Dein Schreibtisch biegt sich beim Zuklappen.";
+"Your desktop follows your lid." = "Dein Schreibtisch folgt dem Deckel.";
+"⌃⌥H anywhere" = "⌃⌥H funktioniert überall";
diff --git a/Resources/Localizations/en.lproj/Localizable.strings b/Resources/Localizations/en.lproj/Localizable.strings
new file mode 100644
index 0000000..29261b2
--- /dev/null
+++ b/Resources/Localizations/en.lproj/Localizable.strings
@@ -0,0 +1,78 @@
+"About" = "About";
+"Allow Hinge in Login Items to finish." = "Allow Hinge in Login Items to finish.";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "Allow Hinge in Screen Recording settings, then quit and reopen it.";
+"Allowed" = "Allowed";
+"Attention" = "Attention";
+"Back" = "Back";
+"Beside the folded desktop" = "Beside the folded desktop";
+"Black" = "Black";
+"Blur" = "Blur";
+"Blur builds toward the top and fades out near the hinge." = "Blur builds toward the top and fades out near the hinge.";
+"Blur by distance" = "Blur by distance";
+"Blur grows with distance from the open screen, so the hinge edge stays sharp." = "Blur grows with distance from the open screen, so the hinge edge stays sharp.";
+"Connected" = "Connected";
+"Controls" = "Controls";
+"Could not allocate the desktop texture." = "Could not allocate the desktop texture.";
+"Could not allocate the renderer warmup texture." = "Could not allocate the renderer warmup texture.";
+"Could not initialize the desktop texture." = "Could not initialize the desktop texture.";
+"Could not prepare the desktop renderer." = "Could not prepare the desktop renderer.";
+"Could not prepare the fold pipeline." = "Could not prepare the fold pipeline.";
+"Could not update Launch at Login: %@" = "Could not update Launch at Login: %@";
+"Could not update the captured windows: %@" = "Could not update the captured windows: %@";
+"Crop from the top" = "Crop from the top";
+"Effect strength" = "Effect strength";
+"Getting the desktop and the sensor ready." = "Getting the desktop and the sensor ready.";
+"GitHub" = "GitHub";
+"Hinge" = "Hinge";
+"Hinge %@" = "Hinge %@";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge could not register ⌃⌥H (error %d).";
+"Hinge is on but not running yet." = "Hinge is on but not running yet.";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge reads your display only to draw the fold. Frames stay in memory on your Mac.";
+"Keyboard shortcut unavailable" = "Keyboard shortcut unavailable";
+"Language" = "Language";
+"Launch at login" = "Launch at login";
+"Lid angle sensor" = "Lid angle sensor";
+"Look" = "Look";
+"Metal is unavailable on this Mac." = "Metal is unavailable on this Mac.";
+"Needed to show your live desktop" = "Needed to show your live desktop";
+"No built-in MacBook display was found." = "No built-in MacBook display was found.";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "No desktop frames arrived. Check Screen Recording permission and reopen Hinge.";
+"Not connected" = "Not connected";
+"Off" = "Off";
+"On" = "On";
+"Open Hinge" = "Open Hinge";
+"Open Login Items" = "Open Login Items";
+"Open Settings" = "Open Settings";
+"Open position" = "Open position";
+"Open the lid to your comfortable viewing position first." = "Open the lid to your comfortable viewing position first.";
+"Quit Hinge" = "Quit Hinge";
+"Relaunch" = "Relaunch";
+"Relaunch Hinge to switch languages." = "Relaunch Hinge to switch languages.";
+"Reset effect strength to 100%" = "Reset effect strength to 100%";
+"Reset effect strength to default" = "Reset effect strength to default";
+"Save the lid angle you are viewing at right now" = "Save the lid angle you are viewing at right now";
+"Screen Recording" = "Screen Recording";
+"Set" = "Set";
+"Set open position" = "Set open position";
+"Settings" = "Settings";
+"Settings…" = "Settings…";
+"Sides" = "Sides";
+"Starting…" = "Starting…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "Starts at 100°. Set your comfortable open position once, and Hinge remembers it.";
+"Status" = "Status";
+"System Language" = "System Language";
+"The desktop renderer is missing. Rebuild the app." = "The desktop renderer is missing. Rebuild the app.";
+"The desktop renderer stopped: %@" = "The desktop renderer stopped: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "The lid sensor stopped responding. Hinge turns back on as soon as it reconnects.";
+"The top of the desktop slides out of view as the lid closes." = "The top of the desktop slides out of view as the lid closes.";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid.";
+"Turn Hinge on or off" = "Turn Hinge on or off";
+"Turn Hinge on to follow the lid." = "Turn Hinge on to follow the lid.";
+"Turn off" = "Turn off";
+"Turn on" = "Turn on";
+"Waiting for the lid angle sensor." = "Waiting for the lid angle sensor.";
+"Waiting…" = "Waiting…";
+"Your desktop bends as the lid closes." = "Your desktop bends as the lid closes.";
+"Your desktop follows your lid." = "Your desktop follows your lid.";
+"⌃⌥H" = "⌃⌥H";
+"⌃⌥H anywhere" = "⌃⌥H anywhere";
diff --git a/Resources/Localizations/es.lproj/Localizable.strings b/Resources/Localizations/es.lproj/Localizable.strings
new file mode 100644
index 0000000..94fb20b
--- /dev/null
+++ b/Resources/Localizations/es.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "Acerca de";
+"Allow Hinge in Login Items to finish." = "Permite Hinge en los ítems de inicio de sesión para terminar.";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "Permite Hinge en la configuración de Grabación de pantalla y luego ciérralo y vuelve a abrirlo.";
+"Allowed" = "Permitido";
+"Attention" = "Atención";
+"Back" = "Atrás";
+"Beside the folded desktop" = "A los lados del escritorio plegado";
+"Black" = "Negro";
+"Blur" = "Desenfoque";
+"Connected" = "Conectado";
+"Controls" = "Controles";
+"Could not allocate the desktop texture." = "No se pudo asignar la textura del escritorio.";
+"Could not allocate the renderer warmup texture." = "No se pudo asignar la textura de preparación del renderizador.";
+"Could not initialize the desktop texture." = "No se pudo inicializar la textura del escritorio.";
+"Could not prepare the desktop renderer." = "No se pudo preparar el renderizador del escritorio.";
+"Could not prepare the fold pipeline." = "No se pudo preparar la canalización del pliegue.";
+"Could not update Launch at Login: %@" = "No se pudo actualizar “Abrir al iniciar sesión”: %@";
+"Could not update the captured windows: %@" = "No se pudieron actualizar las ventanas capturadas: %@";
+"Effect strength" = "Intensidad del efecto";
+"Getting the desktop and the sensor ready." = "Preparando el escritorio y el sensor.";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge no pudo registrar ⌃⌥H (error %d).";
+"Hinge is on but not running yet." = "Hinge está activado, pero aún no se está ejecutando.";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge lee tu pantalla solo para dibujar el pliegue. Las imágenes se quedan en la memoria de tu Mac.";
+"Keyboard shortcut unavailable" = "Función rápida de teclado no disponible";
+"Language" = "Idioma";
+"Launch at login" = "Abrir al iniciar sesión";
+"Lid angle sensor" = "Sensor de ángulo de la tapa";
+"Look" = "Aspecto";
+"Metal is unavailable on this Mac." = "Metal no está disponible en este Mac.";
+"Needed to show your live desktop" = "Necesario para mostrar tu escritorio en vivo";
+"No built-in MacBook display was found." = "No se encontró la pantalla integrada del MacBook.";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "No llegaron imágenes del escritorio. Revisa el permiso de Grabación de pantalla y vuelve a abrir Hinge.";
+"Not connected" = "No conectado";
+"Off" = "Desactivado";
+"On" = "Activado";
+"Open Hinge" = "Abrir Hinge";
+"Open Login Items" = "Abrir ítems de inicio de sesión";
+"Open Settings" = "Abrir Configuración";
+"Open position" = "Posición de apertura";
+"Open the lid to your comfortable viewing position first." = "Primero abre la tapa hasta tu ángulo de visión cómodo.";
+"Quit Hinge" = "Salir de Hinge";
+"Relaunch" = "Volver a abrir";
+"Relaunch Hinge to switch languages." = "Vuelve a abrir Hinge para cambiar de idioma.";
+"Reset effect strength to 100%" = "Restablecer la intensidad del efecto al 100 %";
+"Reset effect strength to default" = "Restablecer la intensidad del efecto al valor predeterminado";
+"Save the lid angle you are viewing at right now" = "Guarda el ángulo de la tapa con el que estás mirando ahora";
+"Screen Recording" = "Grabación de pantalla";
+"Set" = "Definir";
+"Set open position" = "Definir posición de apertura";
+"Settings" = "Configuración";
+"Settings…" = "Configuración…";
+"Sides" = "Lados";
+"Starting…" = "Iniciando…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "Empieza en 100°. Ajusta una vez tu posición de apertura cómoda y Hinge la recordará.";
+"Status" = "Estado";
+"System Language" = "Idioma del sistema";
+"The desktop renderer is missing. Rebuild the app." = "Falta el renderizador del escritorio. Vuelve a compilar la app.";
+"The desktop renderer stopped: %@" = "El renderizado del escritorio se detuvo: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "El sensor de la tapa dejó de responder. Hinge se volverá a activar en cuanto se reconecte.";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "Parece que este Mac no tiene sensor de ángulo de la tapa, así que Hinge no puede seguirla.";
+"Turn Hinge on or off" = "Activar o desactivar Hinge";
+"Turn Hinge on to follow the lid." = "Activa Hinge para seguir la tapa.";
+"Turn off" = "Desactivar";
+"Turn on" = "Activar";
+"Waiting for the lid angle sensor." = "Esperando el sensor de ángulo de la tapa.";
+"Waiting…" = "Esperando…";
+"Your desktop bends as the lid closes." = "Tu escritorio se dobla al cerrar la tapa.";
+"Your desktop follows your lid." = "Tu escritorio sigue a la tapa.";
+"⌃⌥H anywhere" = "⌃⌥H desde cualquier lugar";
diff --git a/Resources/Localizations/fr.lproj/Localizable.strings b/Resources/Localizations/fr.lproj/Localizable.strings
new file mode 100644
index 0000000..e5da34b
--- /dev/null
+++ b/Resources/Localizations/fr.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "À propos";
+"Allow Hinge in Login Items to finish." = "Autorisez Hinge dans les éléments de connexion pour terminer.";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "Autorisez Hinge dans les réglages Enregistrement de l’écran, puis quittez-le et rouvrez-le.";
+"Allowed" = "Autorisé";
+"Attention" = "Attention";
+"Back" = "Retour";
+"Beside the folded desktop" = "De part et d’autre du bureau plié";
+"Black" = "Noir";
+"Blur" = "Flou";
+"Connected" = "Connecté";
+"Controls" = "Commandes";
+"Could not allocate the desktop texture." = "Impossible d’allouer la texture du bureau.";
+"Could not allocate the renderer warmup texture." = "Impossible d’allouer la texture de préchauffage du rendu.";
+"Could not initialize the desktop texture." = "Impossible d’initialiser la texture du bureau.";
+"Could not prepare the desktop renderer." = "Impossible de préparer le rendu du bureau.";
+"Could not prepare the fold pipeline." = "Impossible de préparer le pipeline de rendu du pli.";
+"Could not update Launch at Login: %@" = "Impossible de mettre à jour « Ouvrir à la connexion » : %@";
+"Could not update the captured windows: %@" = "Impossible de mettre à jour les fenêtres capturées : %@";
+"Effect strength" = "Intensité de l’effet";
+"Getting the desktop and the sensor ready." = "Préparation du bureau et du capteur.";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge n’a pas pu enregistrer ⌃⌥H (erreur %d).";
+"Hinge is on but not running yet." = "Hinge est activé mais ne fonctionne pas encore.";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge lit votre écran uniquement pour dessiner le pli. Les images restent dans la mémoire de votre Mac.";
+"Keyboard shortcut unavailable" = "Raccourci clavier indisponible";
+"Language" = "Langue";
+"Launch at login" = "Ouvrir à la connexion";
+"Lid angle sensor" = "Capteur d’angle de l’écran";
+"Look" = "Apparence";
+"Metal is unavailable on this Mac." = "Metal n’est pas disponible sur ce Mac.";
+"Needed to show your live desktop" = "Nécessaire pour afficher votre bureau en direct";
+"No built-in MacBook display was found." = "Aucun écran intégré de MacBook n’a été trouvé.";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "Aucune image du bureau n’est arrivée. Vérifiez l’autorisation d’enregistrement de l’écran et rouvrez Hinge.";
+"Not connected" = "Non connecté";
+"Off" = "Désactivé";
+"On" = "Activé";
+"Open Hinge" = "Ouvrir Hinge";
+"Open Login Items" = "Ouvrir les éléments de connexion";
+"Open Settings" = "Ouvrir les réglages";
+"Open position" = "Position ouverte";
+"Open the lid to your comfortable viewing position first." = "Ouvrez d’abord l’écran à votre angle de vue préféré.";
+"Quit Hinge" = "Quitter Hinge";
+"Relaunch" = "Relancer";
+"Relaunch Hinge to switch languages." = "Relancez Hinge pour changer de langue.";
+"Reset effect strength to 100%" = "Rétablir l’intensité de l’effet à 100 %";
+"Reset effect strength to default" = "Rétablir l’intensité de l’effet par défaut";
+"Save the lid angle you are viewing at right now" = "Enregistre l’angle d’ouverture que vous utilisez en ce moment";
+"Screen Recording" = "Enregistrement de l’écran";
+"Set" = "Définir";
+"Set open position" = "Définir la position ouverte";
+"Settings" = "Réglages";
+"Settings…" = "Réglages…";
+"Sides" = "Côtés";
+"Starting…" = "Démarrage…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "100° par défaut. Réglez une fois votre position d’ouverture préférée, Hinge s’en souviendra.";
+"Status" = "État";
+"System Language" = "Langue du système";
+"The desktop renderer is missing. Rebuild the app." = "Le moteur de rendu du bureau est introuvable. Recompilez l’app.";
+"The desktop renderer stopped: %@" = "Le rendu du bureau s’est arrêté : %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "Le capteur d’angle ne répond plus. Hinge se réactivera dès qu’il sera reconnecté.";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "Ce Mac ne semble pas avoir de capteur d’angle d’écran, Hinge ne peut donc pas suivre l’écran.";
+"Turn Hinge on or off" = "Activer ou désactiver Hinge";
+"Turn Hinge on to follow the lid." = "Activez Hinge pour suivre l’écran.";
+"Turn off" = "Désactiver";
+"Turn on" = "Activer";
+"Waiting for the lid angle sensor." = "En attente du capteur d’angle de l’écran.";
+"Waiting…" = "En attente…";
+"Your desktop bends as the lid closes." = "Votre bureau se plie quand vous rabattez l’écran.";
+"Your desktop follows your lid." = "Votre bureau suit l’écran.";
+"⌃⌥H anywhere" = "⌃⌥H depuis n’importe où";
diff --git a/Resources/Localizations/hi.lproj/Localizable.strings b/Resources/Localizations/hi.lproj/Localizable.strings
new file mode 100644
index 0000000..08b63bc
--- /dev/null
+++ b/Resources/Localizations/hi.lproj/Localizable.strings
@@ -0,0 +1,78 @@
+"About" = "परिचय";
+"Allow Hinge in Login Items to finish." = "पूरा करने के लिए लॉगिन आइटम में Hinge को अनुमति दें।";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "स्क्रीन रिकॉर्डिंग सेटिंग्स में Hinge को अनुमति दें, फिर इसे बंद करके दोबारा खोलें।";
+"Allowed" = "अनुमति है";
+"Attention" = "ध्यान दें";
+"Back" = "वापस";
+"Beside the folded desktop" = "मुड़े हुए डेस्कटॉप के किनारों पर";
+"Black" = "काला";
+"Blur" = "धुंधलापन";
+"Blur builds toward the top and fades out near the hinge." = "ऊपर की ओर धुंधलापन बढ़ता है और हिंज के पास कम होता जाता है।";
+"Blur by distance" = "दूरी के अनुसार धुंधलापन";
+"Blur grows with distance from the open screen, so the hinge edge stays sharp." = "खुली स्क्रीन से दूरी बढ़ने पर धुंधलापन बढ़ता है, इसलिए हिंज वाला किनारा साफ़ रहता है।";
+"Connected" = "जुड़ा हुआ";
+"Controls" = "नियंत्रण";
+"Could not allocate the desktop texture." = "डेस्कटॉप टेक्सचर के लिए मेमोरी आवंटित नहीं हो सकी।";
+"Could not allocate the renderer warmup texture." = "रेंडरर के शुरुआती टेक्सचर के लिए मेमोरी आवंटित नहीं हो सकी।";
+"Could not initialize the desktop texture." = "डेस्कटॉप टेक्सचर शुरू नहीं हो सका।";
+"Could not prepare the desktop renderer." = "डेस्कटॉप रेंडरर तैयार नहीं हो सका।";
+"Could not prepare the fold pipeline." = "फ़ोल्ड पाइपलाइन तैयार नहीं हो सकी।";
+"Could not update Launch at Login: %@" = "लॉगिन पर खोलने की सेटिंग अपडेट नहीं हो सकी: %@";
+"Could not update the captured windows: %@" = "कैप्चर की गई विंडो अपडेट नहीं हो सकीं: %@";
+"Crop from the top" = "ऊपर से काटें";
+"Effect strength" = "प्रभाव की तीव्रता";
+"Getting the desktop and the sensor ready." = "डेस्कटॉप और सेंसर तैयार किए जा रहे हैं।";
+"GitHub" = "GitHub";
+"Hinge" = "Hinge";
+"Hinge %@" = "Hinge %@";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge, ⌃⌥H को पंजीकृत नहीं कर सका (त्रुटि %d)।";
+"Hinge is on but not running yet." = "Hinge चालू है, लेकिन अभी काम नहीं कर रहा है।";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge केवल मोड़ का प्रभाव दिखाने के लिए आपकी स्क्रीन पढ़ता है। फ़्रेम आपके Mac की मेमोरी में ही रहते हैं।";
+"Keyboard shortcut unavailable" = "कीबोर्ड शॉर्टकट उपलब्ध नहीं है";
+"Language" = "भाषा";
+"Launch at login" = "लॉगिन पर खोलें";
+"Lid angle sensor" = "ढक्कन के कोण का सेंसर";
+"Look" = "दिखावट";
+"Metal is unavailable on this Mac." = "इस Mac पर Metal उपलब्ध नहीं है।";
+"Needed to show your live desktop" = "आपका लाइव डेस्कटॉप दिखाने के लिए ज़रूरी है";
+"No built-in MacBook display was found." = "MacBook की अंतर्निर्मित स्क्रीन नहीं मिली।";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "डेस्कटॉप का कोई फ़्रेम नहीं मिला। स्क्रीन रिकॉर्डिंग की अनुमति जाँचें और Hinge दोबारा खोलें।";
+"Not connected" = "जुड़ा नहीं है";
+"Off" = "बंद";
+"On" = "चालू";
+"Open Hinge" = "Hinge खोलें";
+"Open Login Items" = "लॉगिन आइटम खोलें";
+"Open Settings" = "सेटिंग्स खोलें";
+"Open position" = "खुली स्थिति";
+"Open the lid to your comfortable viewing position first." = "पहले ढक्कन को अपनी सुविधाजनक देखने की स्थिति तक खोलें।";
+"Quit Hinge" = "Hinge बंद करें";
+"Relaunch" = "दोबारा खोलें";
+"Relaunch Hinge to switch languages." = "भाषा बदलने के लिए Hinge दोबारा खोलें।";
+"Reset effect strength to 100%" = "प्रभाव की तीव्रता 100% पर रीसेट करें";
+"Reset effect strength to default" = "प्रभाव की तीव्रता डिफ़ॉल्ट पर रीसेट करें";
+"Save the lid angle you are viewing at right now" = "ढक्कन का मौजूदा कोण सहेजें";
+"Screen Recording" = "स्क्रीन रिकॉर्डिंग";
+"Set" = "सेट करें";
+"Set open position" = "खुली स्थिति सेट करें";
+"Settings" = "सेटिंग्स";
+"Settings…" = "सेटिंग्स…";
+"Sides" = "किनारे";
+"Starting…" = "शुरू हो रहा है…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "शुरुआती कोण 100° है। अपनी सुविधाजनक खुली स्थिति एक बार सेट करें, Hinge उसे याद रखेगा।";
+"Status" = "स्थिति";
+"System Language" = "सिस्टम की भाषा";
+"The desktop renderer is missing. Rebuild the app." = "डेस्कटॉप रेंडरर नहीं मिला। ऐप दोबारा बिल्ड करें।";
+"The desktop renderer stopped: %@" = "डेस्कटॉप रेंडरर रुक गया: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "ढक्कन के सेंसर ने जवाब देना बंद कर दिया है। दोबारा जुड़ते ही Hinge चालू हो जाएगा।";
+"The top of the desktop slides out of view as the lid closes." = "ढक्कन बंद होने पर डेस्कटॉप का ऊपरी हिस्सा नज़र से बाहर खिसक जाता है।";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "इस Mac में ढक्कन के कोण का सेंसर नहीं लगता है, इसलिए Hinge ढक्कन की हलचल के अनुसार काम नहीं कर सकता।";
+"Turn Hinge on or off" = "Hinge चालू या बंद करें";
+"Turn Hinge on to follow the lid." = "ढक्कन की हलचल के अनुसार प्रभाव दिखाने के लिए Hinge चालू करें।";
+"Turn off" = "बंद करें";
+"Turn on" = "चालू करें";
+"Waiting for the lid angle sensor." = "ढक्कन के कोण के सेंसर का इंतज़ार है।";
+"Waiting…" = "इंतज़ार है…";
+"Your desktop bends as the lid closes." = "ढक्कन बंद होने पर आपका डेस्कटॉप मुड़ता है।";
+"Your desktop follows your lid." = "आपका डेस्कटॉप ढक्कन की हलचल के साथ बदलता है।";
+"⌃⌥H" = "⌃⌥H";
+"⌃⌥H anywhere" = "कहीं भी ⌃⌥H";
diff --git a/Resources/Localizations/it.lproj/Localizable.strings b/Resources/Localizations/it.lproj/Localizable.strings
new file mode 100644
index 0000000..4d8a956
--- /dev/null
+++ b/Resources/Localizations/it.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "Info";
+"Allow Hinge in Login Items to finish." = "Consenti Hinge in Elementi login per completare.";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "Consenti Hinge nelle impostazioni di Registrazione schermo, poi chiudila e riaprila.";
+"Allowed" = "Consentita";
+"Attention" = "Attenzione";
+"Back" = "Indietro";
+"Beside the folded desktop" = "Ai lati della scrivania piegata";
+"Black" = "Nero";
+"Blur" = "Sfocatura";
+"Connected" = "Collegato";
+"Controls" = "Controlli";
+"Could not allocate the desktop texture." = "Impossibile allocare la texture della scrivania.";
+"Could not allocate the renderer warmup texture." = "Impossibile allocare la texture di preriscaldamento del renderer.";
+"Could not initialize the desktop texture." = "Impossibile inizializzare la texture della scrivania.";
+"Could not prepare the desktop renderer." = "Impossibile preparare il renderer della scrivania.";
+"Could not prepare the fold pipeline." = "Impossibile preparare la pipeline della piega.";
+"Could not update Launch at Login: %@" = "Impossibile aggiornare “Apri al login”: %@";
+"Could not update the captured windows: %@" = "Impossibile aggiornare le finestre registrate: %@";
+"Effect strength" = "Intensità dell’effetto";
+"Getting the desktop and the sensor ready." = "Preparazione della scrivania e del sensore.";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge non è riuscita a registrare ⌃⌥H (errore %d).";
+"Hinge is on but not running yet." = "Hinge è attivo ma non è ancora in esecuzione.";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge legge lo schermo solo per disegnare la piega. I fotogrammi restano nella memoria del Mac.";
+"Keyboard shortcut unavailable" = "Abbreviazione da tastiera non disponibile";
+"Language" = "Lingua";
+"Launch at login" = "Apri al login";
+"Lid angle sensor" = "Sensore dell’angolo dello schermo";
+"Look" = "Aspetto";
+"Metal is unavailable on this Mac." = "Metal non è disponibile su questo Mac.";
+"Needed to show your live desktop" = "Necessaria per mostrare la scrivania in tempo reale";
+"No built-in MacBook display was found." = "Nessun display integrato del MacBook trovato.";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "Non sono arrivati fotogrammi della scrivania. Controlla il permesso di Registrazione schermo e riapri Hinge.";
+"Not connected" = "Non collegato";
+"Off" = "Disattivo";
+"On" = "Attivo";
+"Open Hinge" = "Apri Hinge";
+"Open Login Items" = "Apri Elementi login";
+"Open Settings" = "Apri Impostazioni";
+"Open position" = "Posizione di apertura";
+"Open the lid to your comfortable viewing position first." = "Apri prima lo schermo all’angolazione di visione che preferisci.";
+"Quit Hinge" = "Esci da Hinge";
+"Relaunch" = "Riapri";
+"Relaunch Hinge to switch languages." = "Riapri Hinge per cambiare lingua.";
+"Reset effect strength to 100%" = "Riporta l’intensità dell’effetto al 100%";
+"Reset effect strength to default" = "Riporta l’intensità dell’effetto al valore predefinito";
+"Save the lid angle you are viewing at right now" = "Salva l’angolo dello schermo con cui stai guardando adesso";
+"Screen Recording" = "Registrazione schermo";
+"Set" = "Imposta";
+"Set open position" = "Imposta posizione di apertura";
+"Settings" = "Impostazioni";
+"Settings…" = "Impostazioni…";
+"Sides" = "Lati";
+"Starting…" = "Avvio in corso…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "Parte da 100°. Imposta una volta la tua posizione di apertura preferita e Hinge la ricorderà.";
+"Status" = "Stato";
+"System Language" = "Lingua di sistema";
+"The desktop renderer is missing. Rebuild the app." = "Il renderer della scrivania non è presente. Ricompila l’app.";
+"The desktop renderer stopped: %@" = "Il rendering della scrivania si è interrotto: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "Il sensore dello schermo ha smesso di rispondere. Hinge si riattiverà appena si ricollega.";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "Sembra che questo Mac non abbia un sensore dell’angolo dello schermo, quindi Hinge non può seguirlo.";
+"Turn Hinge on or off" = "Attiva o disattiva Hinge";
+"Turn Hinge on to follow the lid." = "Attiva Hinge per seguire lo schermo.";
+"Turn off" = "Disattiva";
+"Turn on" = "Attiva";
+"Waiting for the lid angle sensor." = "In attesa del sensore dell’angolo dello schermo.";
+"Waiting…" = "In attesa…";
+"Your desktop bends as the lid closes." = "La scrivania si piega quando chiudi lo schermo.";
+"Your desktop follows your lid." = "La tua scrivania segue lo schermo.";
+"⌃⌥H anywhere" = "⌃⌥H ovunque";
diff --git a/Resources/Localizations/ja.lproj/Localizable.strings b/Resources/Localizations/ja.lproj/Localizable.strings
new file mode 100644
index 0000000..29bf7a5
--- /dev/null
+++ b/Resources/Localizations/ja.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "情報";
+"Allow Hinge in Login Items to finish." = "設定を完了するには、ログイン項目でHingeを許可してください。";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "「画面収録」設定でHingeを許可してから、Hingeを終了して開き直してください。";
+"Allowed" = "許可済み";
+"Attention" = "注意";
+"Back" = "戻る";
+"Beside the folded desktop" = "折りたたんだデスクトップの両サイド";
+"Black" = "黒";
+"Blur" = "ぼかし";
+"Connected" = "接続済み";
+"Controls" = "操作";
+"Could not allocate the desktop texture." = "デスクトップのテクスチャを確保できませんでした。";
+"Could not allocate the renderer warmup texture." = "描画のウォームアップ用テクスチャを確保できませんでした。";
+"Could not initialize the desktop texture." = "デスクトップのテクスチャを初期化できませんでした。";
+"Could not prepare the desktop renderer." = "デスクトップの描画を準備できませんでした。";
+"Could not prepare the fold pipeline." = "折り目の描画パイプラインを準備できませんでした。";
+"Could not update Launch at Login: %@" = "「ログイン時に開く」を更新できませんでした: %@";
+"Could not update the captured windows: %@" = "収録するウインドウを更新できませんでした: %@";
+"Effect strength" = "エフェクトの強さ";
+"Getting the desktop and the sensor ready." = "デスクトップとセンサーを準備しています。";
+"Hinge could not register ⌃⌥H (error %d)." = "Hingeは⌃⌥Hを登録できませんでした(エラー %d)。";
+"Hinge is on but not running yet." = "Hingeはオンですが、まだ動作していません。";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hingeが画面を読み取るのは折り目を描くためだけです。フレームはMacのメモリ内にのみ保持されます。";
+"Keyboard shortcut unavailable" = "キーボードショートカットを使用できません";
+"Language" = "言語";
+"Launch at login" = "ログイン時に開く";
+"Lid angle sensor" = "ふたの角度センサー";
+"Look" = "外観";
+"Metal is unavailable on this Mac." = "このMacではMetalを使用できません。";
+"Needed to show your live desktop" = "ライブのデスクトップを表示するのに必要です";
+"No built-in MacBook display was found." = "MacBookの内蔵ディスプレイが見つかりませんでした。";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "デスクトップの画像が届きませんでした。画面収録の許可を確認して、Hingeを開き直してください。";
+"Not connected" = "未接続";
+"Off" = "オフ";
+"On" = "オン";
+"Open Hinge" = "Hingeを開く";
+"Open Login Items" = "ログイン項目を開く";
+"Open Settings" = "設定を開く";
+"Open position" = "開いた位置";
+"Open the lid to your comfortable viewing position first." = "先に、見やすい角度までふたを開いてください。";
+"Quit Hinge" = "Hingeを終了";
+"Relaunch" = "再起動";
+"Relaunch Hinge to switch languages." = "言語を切り替えるには、Hingeを再起動してください。";
+"Reset effect strength to 100%" = "エフェクトの強さを100%に戻す";
+"Reset effect strength to default" = "エフェクトの強さをデフォルトに戻す";
+"Save the lid angle you are viewing at right now" = "いま見ているふたの角度を保存します";
+"Screen Recording" = "画面収録";
+"Set" = "設定";
+"Set open position" = "開いた位置を設定";
+"Settings" = "設定";
+"Settings…" = "設定…";
+"Sides" = "両サイド";
+"Starting…" = "起動中…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "初期値は100°です。見やすい開き具合を一度設定すると、Hingeが記憶します。";
+"Status" = "状況";
+"System Language" = "システムの言語";
+"The desktop renderer is missing. Rebuild the app." = "デスクトップの描画コンポーネントが見つかりません。アプリをビルドし直してください。";
+"The desktop renderer stopped: %@" = "デスクトップの描画が停止しました: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "ふたの角度センサーが応答しなくなりました。再接続されるとHingeは自動的にオンに戻ります。";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "このMacにはふたの角度センサーがないようです。そのため、Hingeはふたの動きに追従できません。";
+"Turn Hinge on or off" = "Hingeのオン/オフ";
+"Turn Hinge on to follow the lid." = "ふたの動きに追従するには、Hingeをオンにしてください。";
+"Turn off" = "オフにする";
+"Turn on" = "オンにする";
+"Waiting for the lid angle sensor." = "ふたの角度センサーを待機しています。";
+"Waiting…" = "待機中…";
+"Your desktop bends as the lid closes." = "ふたを閉じるとデスクトップが折れ曲がります。";
+"Your desktop follows your lid." = "デスクトップがふたの動きに追従します。";
+"⌃⌥H anywhere" = "どこからでも⌃⌥H";
diff --git a/Resources/Localizations/ko.lproj/Localizable.strings b/Resources/Localizations/ko.lproj/Localizable.strings
new file mode 100644
index 0000000..55516f0
--- /dev/null
+++ b/Resources/Localizations/ko.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "정보";
+"Allow Hinge in Login Items to finish." = "설정을 완료하려면 로그인 항목에서 Hinge를 허용하십시오.";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "'화면 기록' 설정에서 Hinge를 허용한 다음, 종료하고 다시 여십시오.";
+"Allowed" = "허용됨";
+"Attention" = "주의";
+"Back" = "뒤로";
+"Beside the folded desktop" = "접힌 데스크탑의 양옆";
+"Black" = "검은색";
+"Blur" = "흐림";
+"Connected" = "연결됨";
+"Controls" = "제어";
+"Could not allocate the desktop texture." = "데스크탑 텍스처를 할당할 수 없습니다.";
+"Could not allocate the renderer warmup texture." = "렌더러 준비용 텍스처를 할당할 수 없습니다.";
+"Could not initialize the desktop texture." = "데스크탑 텍스처를 초기화할 수 없습니다.";
+"Could not prepare the desktop renderer." = "데스크탑 렌더러를 준비할 수 없습니다.";
+"Could not prepare the fold pipeline." = "접힘 렌더링 파이프라인을 준비할 수 없습니다.";
+"Could not update Launch at Login: %@" = "'로그인 시 열기'를 업데이트할 수 없습니다: %@";
+"Could not update the captured windows: %@" = "기록할 윈도우를 업데이트할 수 없습니다: %@";
+"Effect strength" = "효과 강도";
+"Getting the desktop and the sensor ready." = "데스크탑과 센서를 준비하는 중입니다.";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge가 ⌃⌥H를 등록할 수 없습니다(오류 %d).";
+"Hinge is on but not running yet." = "Hinge가 켜져 있지만 아직 실행되지 않았습니다.";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge는 접힘 효과를 그리기 위해서만 화면을 읽습니다. 프레임은 Mac의 메모리에만 머무릅니다.";
+"Keyboard shortcut unavailable" = "키보드 단축키를 사용할 수 없음";
+"Language" = "언어";
+"Launch at login" = "로그인 시 열기";
+"Lid angle sensor" = "덮개 각도 센서";
+"Look" = "모양";
+"Metal is unavailable on this Mac." = "이 Mac에서는 Metal을 사용할 수 없습니다.";
+"Needed to show your live desktop" = "실시간 데스크탑을 표시하는 데 필요합니다";
+"No built-in MacBook display was found." = "내장 MacBook 디스플레이를 찾을 수 없습니다.";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "데스크탑 프레임이 도착하지 않았습니다. 화면 기록 권한을 확인하고 Hinge를 다시 여십시오.";
+"Not connected" = "연결 안 됨";
+"Off" = "끔";
+"On" = "켬";
+"Open Hinge" = "Hinge 열기";
+"Open Login Items" = "로그인 항목 열기";
+"Open Settings" = "설정 열기";
+"Open position" = "열림 위치";
+"Open the lid to your comfortable viewing position first." = "먼저 편하게 보는 각도로 덮개를 여십시오.";
+"Quit Hinge" = "Hinge 종료";
+"Relaunch" = "다시 실행";
+"Relaunch Hinge to switch languages." = "언어를 바꾸려면 Hinge를 다시 실행하십시오.";
+"Reset effect strength to 100%" = "효과 강도를 100%로 재설정";
+"Reset effect strength to default" = "효과 강도를 기본값으로 재설정";
+"Save the lid angle you are viewing at right now" = "지금 보고 있는 덮개 각도를 저장합니다";
+"Screen Recording" = "화면 기록";
+"Set" = "설정";
+"Set open position" = "열림 위치 설정";
+"Settings" = "설정";
+"Settings…" = "설정…";
+"Sides" = "양옆";
+"Starting…" = "시작하는 중…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "기본값은 100°입니다. 편한 열림 위치를 한 번 설정하면 Hinge가 기억합니다.";
+"Status" = "상태";
+"System Language" = "시스템 언어";
+"The desktop renderer is missing. Rebuild the app." = "데스크탑 렌더러가 없습니다. 앱을 다시 빌드하십시오.";
+"The desktop renderer stopped: %@" = "데스크탑 렌더러가 멈췄습니다: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "덮개 각도 센서가 응답하지 않습니다. 다시 연결되면 Hinge가 자동으로 다시 켜집니다.";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "이 Mac에는 덮개 각도 센서가 없는 것 같습니다. 따라서 Hinge가 덮개를 따라갈 수 없습니다.";
+"Turn Hinge on or off" = "Hinge 켜기 또는 끄기";
+"Turn Hinge on to follow the lid." = "덮개를 따라가려면 Hinge를 켜십시오.";
+"Turn off" = "끄기";
+"Turn on" = "켜기";
+"Waiting for the lid angle sensor." = "덮개 각도 센서를 기다리는 중입니다.";
+"Waiting…" = "기다리는 중…";
+"Your desktop bends as the lid closes." = "덮개를 닫으면 데스크탑이 휘어집니다.";
+"Your desktop follows your lid." = "데스크탑이 덮개를 따라 움직입니다.";
+"⌃⌥H anywhere" = "어디서나 ⌃⌥H";
diff --git a/Resources/Localizations/nl.lproj/Localizable.strings b/Resources/Localizations/nl.lproj/Localizable.strings
new file mode 100644
index 0000000..5734ea3
--- /dev/null
+++ b/Resources/Localizations/nl.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "Over";
+"Allow Hinge in Login Items to finish." = "Sta Hinge toe bij inlogonderdelen om af te ronden.";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "Sta Hinge toe in de instellingen voor schermopname, stop de app en open hem opnieuw.";
+"Allowed" = "Toegestaan";
+"Attention" = "Let op";
+"Back" = "Terug";
+"Beside the folded desktop" = "Naast het gevouwen bureaublad";
+"Black" = "Zwart";
+"Blur" = "Vervaging";
+"Connected" = "Verbonden";
+"Controls" = "Bediening";
+"Could not allocate the desktop texture." = "Kan de bureaubladtextuur niet toewijzen.";
+"Could not allocate the renderer warmup texture." = "Kan de opwarmtextuur van de renderer niet toewijzen.";
+"Could not initialize the desktop texture." = "Kan de bureaubladtextuur niet initialiseren.";
+"Could not prepare the desktop renderer." = "Kan de bureaubladrenderer niet voorbereiden.";
+"Could not prepare the fold pipeline." = "Kan de vouwpipeline niet voorbereiden.";
+"Could not update Launch at Login: %@" = "Kan ‘Open bij inloggen’ niet bijwerken: %@";
+"Could not update the captured windows: %@" = "Kan de opgenomen vensters niet bijwerken: %@";
+"Effect strength" = "Effectsterkte";
+"Getting the desktop and the sensor ready." = "Bureaublad en sensor worden voorbereid.";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge kon ⌃⌥H niet registreren (fout %d).";
+"Hinge is on but not running yet." = "Hinge staat aan maar is nog niet actief.";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge leest je scherm alleen om de vouw te tekenen. De beelden blijven in het geheugen van je Mac.";
+"Keyboard shortcut unavailable" = "Toetscombinatie niet beschikbaar";
+"Language" = "Taal";
+"Launch at login" = "Open bij inloggen";
+"Lid angle sensor" = "Klephoeksensor";
+"Look" = "Weergave";
+"Metal is unavailable on this Mac." = "Metal is niet beschikbaar op deze Mac.";
+"Needed to show your live desktop" = "Nodig om je live bureaublad te tonen";
+"No built-in MacBook display was found." = "Er is geen ingebouwd MacBook-beeldscherm gevonden.";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "Er kwamen geen beelden van het bureaublad binnen. Controleer de toestemming voor schermopname en open Hinge opnieuw.";
+"Not connected" = "Niet verbonden";
+"Off" = "Uit";
+"On" = "Aan";
+"Open Hinge" = "Open Hinge";
+"Open Login Items" = "Open inlogonderdelen";
+"Open Settings" = "Open Instellingen";
+"Open position" = "Openstand";
+"Open the lid to your comfortable viewing position first." = "Open de klep eerst tot je favoriete kijkhoek.";
+"Quit Hinge" = "Stop Hinge";
+"Relaunch" = "Opnieuw starten";
+"Relaunch Hinge to switch languages." = "Start Hinge opnieuw om van taal te wisselen.";
+"Reset effect strength to 100%" = "Zet effectsterkte terug naar 100%";
+"Reset effect strength to default" = "Zet effectsterkte terug naar standaard";
+"Save the lid angle you are viewing at right now" = "Bewaar de klephoek waarmee je nu kijkt";
+"Screen Recording" = "Schermopname";
+"Set" = "Stel in";
+"Set open position" = "Stel openstand in";
+"Settings" = "Instellingen";
+"Settings…" = "Instellingen…";
+"Sides" = "Zijkanten";
+"Starting…" = "Starten…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "Begint bij 100°. Stel één keer je favoriete openstand in en Hinge onthoudt die.";
+"Status" = "Status";
+"System Language" = "Systeemtaal";
+"The desktop renderer is missing. Rebuild the app." = "De bureaubladrenderer ontbreekt. Bouw de app opnieuw.";
+"The desktop renderer stopped: %@" = "De weergave van het bureaublad is gestopt: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "De klepsensor reageert niet meer. Hinge gaat weer aan zodra de sensor opnieuw verbonden is.";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "Deze Mac lijkt geen klephoeksensor te hebben, dus Hinge kan de klep niet volgen.";
+"Turn Hinge on or off" = "Schakel Hinge in of uit";
+"Turn Hinge on to follow the lid." = "Zet Hinge aan om de klep te volgen.";
+"Turn off" = "Zet uit";
+"Turn on" = "Zet aan";
+"Waiting for the lid angle sensor." = "Wachten op de klephoeksensor.";
+"Waiting…" = "Wachten…";
+"Your desktop bends as the lid closes." = "Je bureaublad buigt mee als de klep dichtgaat.";
+"Your desktop follows your lid." = "Je bureaublad volgt de klep.";
+"⌃⌥H anywhere" = "⌃⌥H werkt overal";
diff --git a/Resources/Localizations/pl.lproj/Localizable.strings b/Resources/Localizations/pl.lproj/Localizable.strings
new file mode 100644
index 0000000..692aac4
--- /dev/null
+++ b/Resources/Localizations/pl.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "Informacje";
+"Allow Hinge in Login Items to finish." = "Pozwól na Hinge w rzeczach otwieranych podczas logowania, aby dokończyć.";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "Pozwól na Hinge w ustawieniach nagrywania ekranu, a potem zakończ i otwórz aplikację ponownie.";
+"Allowed" = "Dozwolone";
+"Attention" = "Uwaga";
+"Back" = "Wstecz";
+"Beside the folded desktop" = "Po bokach złożonego biurka";
+"Black" = "Czarne";
+"Blur" = "Rozmycie";
+"Connected" = "Połączony";
+"Controls" = "Sterowanie";
+"Could not allocate the desktop texture." = "Nie można przydzielić tekstury biurka.";
+"Could not allocate the renderer warmup texture." = "Nie można przydzielić tekstury rozgrzewającej renderera.";
+"Could not initialize the desktop texture." = "Nie można zainicjować tekstury biurka.";
+"Could not prepare the desktop renderer." = "Nie można przygotować renderera biurka.";
+"Could not prepare the fold pipeline." = "Nie można przygotować potoku renderowania zagięcia.";
+"Could not update Launch at Login: %@" = "Nie można zaktualizować „Otwieraj przy logowaniu”: %@";
+"Could not update the captured windows: %@" = "Nie można zaktualizować nagrywanych okien: %@";
+"Effect strength" = "Siła efektu";
+"Getting the desktop and the sensor ready." = "Przygotowywanie biurka i czujnika.";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge nie może zarejestrować ⌃⌥H (błąd %d).";
+"Hinge is on but not running yet." = "Hinge jest włączony, ale jeszcze nie działa.";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge odczytuje ekran tylko po to, by narysować zagięcie. Klatki pozostają w pamięci Maca.";
+"Keyboard shortcut unavailable" = "Skrót klawiszowy niedostępny";
+"Language" = "Język";
+"Launch at login" = "Otwieraj przy logowaniu";
+"Lid angle sensor" = "Czujnik kąta pokrywy";
+"Look" = "Wygląd";
+"Metal is unavailable on this Mac." = "Metal jest niedostępny na tym Macu.";
+"Needed to show your live desktop" = "Wymagane do pokazywania biurka na żywo";
+"No built-in MacBook display was found." = "Nie znaleziono wbudowanego ekranu MacBooka.";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "Nie dotarły żadne klatki biurka. Sprawdź uprawnienie do nagrywania ekranu i otwórz Hinge ponownie.";
+"Not connected" = "Niepołączony";
+"Off" = "Wyłączone";
+"On" = "Włączone";
+"Open Hinge" = "Otwórz Hinge";
+"Open Login Items" = "Otwórz rzeczy logowania";
+"Open Settings" = "Otwórz Ustawienia";
+"Open position" = "Pozycja otwarcia";
+"Open the lid to your comfortable viewing position first." = "Najpierw otwórz pokrywę pod wygodnym kątem patrzenia.";
+"Quit Hinge" = "Zakończ Hinge";
+"Relaunch" = "Uruchom ponownie";
+"Relaunch Hinge to switch languages." = "Uruchom ponownie Hinge, aby zmienić język.";
+"Reset effect strength to 100%" = "Przywróć siłę efektu do 100%";
+"Reset effect strength to default" = "Przywróć domyślną siłę efektu";
+"Save the lid angle you are viewing at right now" = "Zapisz kąt pokrywy, pod którym teraz patrzysz";
+"Screen Recording" = "Nagrywanie ekranu";
+"Set" = "Ustaw";
+"Set open position" = "Ustaw pozycję otwarcia";
+"Settings" = "Ustawienia";
+"Settings…" = "Ustawienia…";
+"Sides" = "Boki";
+"Starting…" = "Uruchamianie…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "Domyślnie 100°. Ustaw raz wygodną pozycję otwarcia, a Hinge ją zapamięta.";
+"Status" = "Stan";
+"System Language" = "Język systemu";
+"The desktop renderer is missing. Rebuild the app." = "Brakuje renderera biurka. Zbuduj aplikację ponownie.";
+"The desktop renderer stopped: %@" = "Renderowanie biurka zostało zatrzymane: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "Czujnik pokrywy przestał odpowiadać. Hinge włączy się ponownie, gdy tylko czujnik się połączy.";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "Ten Mac prawdopodobnie nie ma czujnika kąta pokrywy, więc Hinge nie może za nią podążać.";
+"Turn Hinge on or off" = "Włącz lub wyłącz Hinge";
+"Turn Hinge on to follow the lid." = "Włącz Hinge, aby podążał za pokrywą.";
+"Turn off" = "Wyłącz";
+"Turn on" = "Włącz";
+"Waiting for the lid angle sensor." = "Oczekiwanie na czujnik kąta pokrywy.";
+"Waiting…" = "Oczekiwanie…";
+"Your desktop bends as the lid closes." = "Biurko wygina się, gdy zamykasz pokrywę.";
+"Your desktop follows your lid." = "Twoje biurko podąża za pokrywą.";
+"⌃⌥H anywhere" = "⌃⌥H działa wszędzie";
diff --git a/Resources/Localizations/pt-BR.lproj/Localizable.strings b/Resources/Localizations/pt-BR.lproj/Localizable.strings
new file mode 100644
index 0000000..41b8f33
--- /dev/null
+++ b/Resources/Localizations/pt-BR.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "Sobre";
+"Allow Hinge in Login Items to finish." = "Permita o Hinge em Itens de Início para concluir.";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "Permita o Hinge nos ajustes de Gravação de Tela e depois encerre e reabra o app.";
+"Allowed" = "Permitido";
+"Attention" = "Atenção";
+"Back" = "Voltar";
+"Beside the folded desktop" = "Nas laterais da mesa dobrada";
+"Black" = "Preto";
+"Blur" = "Desfoque";
+"Connected" = "Conectado";
+"Controls" = "Controles";
+"Could not allocate the desktop texture." = "Não foi possível alocar a textura da mesa.";
+"Could not allocate the renderer warmup texture." = "Não foi possível alocar a textura de aquecimento do renderizador.";
+"Could not initialize the desktop texture." = "Não foi possível inicializar a textura da mesa.";
+"Could not prepare the desktop renderer." = "Não foi possível preparar o renderizador da mesa.";
+"Could not prepare the fold pipeline." = "Não foi possível preparar o pipeline da dobra.";
+"Could not update Launch at Login: %@" = "Não foi possível atualizar “Abrir ao iniciar sessão”: %@";
+"Could not update the captured windows: %@" = "Não foi possível atualizar as janelas capturadas: %@";
+"Effect strength" = "Intensidade do efeito";
+"Getting the desktop and the sensor ready." = "Preparando a mesa e o sensor.";
+"Hinge could not register ⌃⌥H (error %d)." = "O Hinge não conseguiu registrar ⌃⌥H (erro %d).";
+"Hinge is on but not running yet." = "O Hinge está ativado, mas ainda não está em execução.";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "O Hinge lê sua tela só para desenhar a dobra. Os quadros ficam na memória do seu Mac.";
+"Keyboard shortcut unavailable" = "Atalho de teclado indisponível";
+"Language" = "Idioma";
+"Launch at login" = "Abrir ao iniciar sessão";
+"Lid angle sensor" = "Sensor de ângulo da tampa";
+"Look" = "Aparência";
+"Metal is unavailable on this Mac." = "O Metal não está disponível neste Mac.";
+"Needed to show your live desktop" = "Necessário para mostrar sua mesa ao vivo";
+"No built-in MacBook display was found." = "Nenhuma tela integrada do MacBook foi encontrada.";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "Nenhum quadro da mesa chegou. Verifique a permissão de Gravação de Tela e reabra o Hinge.";
+"Not connected" = "Não conectado";
+"Off" = "Desativado";
+"On" = "Ativado";
+"Open Hinge" = "Abrir o Hinge";
+"Open Login Items" = "Abrir Itens de Início";
+"Open Settings" = "Abrir Ajustes";
+"Open position" = "Posição aberta";
+"Open the lid to your comfortable viewing position first." = "Primeiro abra a tampa no ângulo de visão que for confortável para você.";
+"Quit Hinge" = "Encerrar Hinge";
+"Relaunch" = "Reabrir";
+"Relaunch Hinge to switch languages." = "Reabra o Hinge para trocar de idioma.";
+"Reset effect strength to 100%" = "Redefinir a intensidade do efeito para 100%";
+"Reset effect strength to default" = "Redefinir a intensidade do efeito para o padrão";
+"Save the lid angle you are viewing at right now" = "Salva o ângulo da tampa em que você está olhando agora";
+"Screen Recording" = "Gravação de Tela";
+"Set" = "Definir";
+"Set open position" = "Definir posição aberta";
+"Settings" = "Ajustes";
+"Settings…" = "Ajustes…";
+"Sides" = "Laterais";
+"Starting…" = "Iniciando…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "Começa em 100°. Defina uma vez sua posição de abertura preferida, e o Hinge vai lembrar dela.";
+"Status" = "Estado";
+"System Language" = "Idioma do Sistema";
+"The desktop renderer is missing. Rebuild the app." = "O renderizador da mesa está faltando. Compile o app novamente.";
+"The desktop renderer stopped: %@" = "A renderização da mesa parou: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "O sensor da tampa parou de responder. O Hinge será reativado assim que ele se reconectar.";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "Este Mac parece não ter um sensor de ângulo da tampa, então o Hinge não consegue acompanhá-la.";
+"Turn Hinge on or off" = "Ativar ou desativar o Hinge";
+"Turn Hinge on to follow the lid." = "Ative o Hinge para seguir a tampa.";
+"Turn off" = "Desativar";
+"Turn on" = "Ativar";
+"Waiting for the lid angle sensor." = "Aguardando o sensor de ângulo da tampa.";
+"Waiting…" = "Aguardando…";
+"Your desktop bends as the lid closes." = "Sua mesa se dobra quando a tampa fecha.";
+"Your desktop follows your lid." = "Sua mesa acompanha a tampa.";
+"⌃⌥H anywhere" = "⌃⌥H em qualquer lugar";
diff --git a/Resources/Localizations/ru.lproj/Localizable.strings b/Resources/Localizations/ru.lproj/Localizable.strings
new file mode 100644
index 0000000..66830d3
--- /dev/null
+++ b/Resources/Localizations/ru.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "О программе";
+"Allow Hinge in Login Items to finish." = "Разрешите Hinge в объектах входа, чтобы завершить.";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "Разрешите Hinge в настройках записи экрана, затем завершите и снова откройте его.";
+"Allowed" = "Разрешено";
+"Attention" = "Внимание";
+"Back" = "Назад";
+"Beside the folded desktop" = "По бокам сложенного рабочего стола";
+"Black" = "Чёрный";
+"Blur" = "Размытие";
+"Connected" = "Подключён";
+"Controls" = "Управление";
+"Could not allocate the desktop texture." = "Не удалось выделить текстуру рабочего стола.";
+"Could not allocate the renderer warmup texture." = "Не удалось выделить текстуру для прогрева отрисовки.";
+"Could not initialize the desktop texture." = "Не удалось инициализировать текстуру рабочего стола.";
+"Could not prepare the desktop renderer." = "Не удалось подготовить отрисовку рабочего стола.";
+"Could not prepare the fold pipeline." = "Не удалось подготовить конвейер отрисовки сгиба.";
+"Could not update Launch at Login: %@" = "Не удалось обновить «Открывать при входе»: %@";
+"Could not update the captured windows: %@" = "Не удалось обновить захватываемые окна: %@";
+"Effect strength" = "Сила эффекта";
+"Getting the desktop and the sensor ready." = "Подготовка рабочего стола и датчика.";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge не удалось зарегистрировать ⌃⌥H (ошибка %d).";
+"Hinge is on but not running yet." = "Hinge включен, но еще не работает.";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge считывает экран только для отрисовки сгиба. Кадры остаются в памяти вашего Mac.";
+"Keyboard shortcut unavailable" = "Сочетание клавиш недоступно";
+"Language" = "Язык";
+"Launch at login" = "Открывать при входе";
+"Lid angle sensor" = "Датчик угла крышки";
+"Look" = "Внешний вид";
+"Metal is unavailable on this Mac." = "Metal недоступен на этом Mac.";
+"Needed to show your live desktop" = "Нужно, чтобы показывать рабочий стол в реальном времени";
+"No built-in MacBook display was found." = "Встроенный дисплей MacBook не найден.";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "Кадры рабочего стола не поступили. Проверьте разрешение на запись экрана и снова откройте Hinge.";
+"Not connected" = "Не подключён";
+"Off" = "Выключено";
+"On" = "Включено";
+"Open Hinge" = "Открыть Hinge";
+"Open Login Items" = "Открыть объекты входа";
+"Open Settings" = "Открыть настройки";
+"Open position" = "Положение открытия";
+"Open the lid to your comfortable viewing position first." = "Сначала откройте крышку до удобного угла обзора.";
+"Quit Hinge" = "Завершить Hinge";
+"Relaunch" = "Перезапустить";
+"Relaunch Hinge to switch languages." = "Перезапустите Hinge, чтобы сменить язык.";
+"Reset effect strength to 100%" = "Вернуть силу эффекта к 100 %";
+"Reset effect strength to default" = "Вернуть силу эффекта по умолчанию";
+"Save the lid angle you are viewing at right now" = "Сохранить угол крышки, под которым вы смотрите сейчас";
+"Screen Recording" = "Запись экрана";
+"Set" = "Задать";
+"Set open position" = "Задать положение открытия";
+"Settings" = "Настройки";
+"Settings…" = "Настройки…";
+"Sides" = "Края";
+"Starting…" = "Запуск…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "По умолчанию 100°. Задайте удобное положение открытия один раз, и Hinge его запомнит.";
+"Status" = "Состояние";
+"System Language" = "Язык системы";
+"The desktop renderer is missing. Rebuild the app." = "Модуль отрисовки рабочего стола отсутствует. Пересоберите приложение.";
+"The desktop renderer stopped: %@" = "Отрисовка рабочего стола остановилась: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "Датчик крышки перестал отвечать. Hinge снова включится, как только он переподключится.";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "Похоже, на этом Mac нет датчика угла крышки, поэтому Hinge не может следовать за ней.";
+"Turn Hinge on or off" = "Включить или выключить Hinge";
+"Turn Hinge on to follow the lid." = "Включите Hinge, чтобы он следовал за крышкой.";
+"Turn off" = "Выключить";
+"Turn on" = "Включить";
+"Waiting for the lid angle sensor." = "Ожидание датчика угла крышки.";
+"Waiting…" = "Ожидание…";
+"Your desktop bends as the lid closes." = "Рабочий стол изгибается, когда вы закрываете крышку.";
+"Your desktop follows your lid." = "Рабочий стол следует за крышкой.";
+"⌃⌥H anywhere" = "⌃⌥H работает везде";
diff --git a/Resources/Localizations/tr.lproj/Localizable.strings b/Resources/Localizations/tr.lproj/Localizable.strings
new file mode 100644
index 0000000..2680c7e
--- /dev/null
+++ b/Resources/Localizations/tr.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "Hakkında";
+"Allow Hinge in Login Items to finish." = "Tamamlamak için Giriş Öğeleri’nde Hinge’e izin verin.";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "Ekran Kaydı ayarlarında Hinge’e izin verin, ardından uygulamadan çıkıp yeniden açın.";
+"Allowed" = "İzin verildi";
+"Attention" = "Dikkat";
+"Back" = "Geri";
+"Beside the folded desktop" = "Katlanmış masaüstünün yanları";
+"Black" = "Siyah";
+"Blur" = "Bulanık";
+"Connected" = "Bağlı";
+"Controls" = "Denetimler";
+"Could not allocate the desktop texture." = "Masaüstü dokusu ayrılamadı.";
+"Could not allocate the renderer warmup texture." = "Görüntüleyici ısınma dokusu ayrılamadı.";
+"Could not initialize the desktop texture." = "Masaüstü dokusu başlatılamadı.";
+"Could not prepare the desktop renderer." = "Masaüstü görüntüleyici hazırlanamadı.";
+"Could not prepare the fold pipeline." = "Katlama işlem hattı hazırlanamadı.";
+"Could not update Launch at Login: %@" = "“Oturum açıldığında aç” güncellenemedi: %@";
+"Could not update the captured windows: %@" = "Kaydedilen pencereler güncellenemedi: %@";
+"Effect strength" = "Efekt gücü";
+"Getting the desktop and the sensor ready." = "Masaüstü ve sensör hazırlanıyor.";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge ⌃⌥H kestirmesini kaydedemedi (hata %d).";
+"Hinge is on but not running yet." = "Hinge açık ancak henüz çalışmıyor.";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge ekranınızı yalnızca katlamayı çizmek için okur. Kareler Mac’inizin belleğinde kalır.";
+"Keyboard shortcut unavailable" = "Klavye kestirmesi kullanılamıyor";
+"Language" = "Dil";
+"Launch at login" = "Oturum açıldığında aç";
+"Lid angle sensor" = "Kapak açısı sensörü";
+"Look" = "Görünüm";
+"Metal is unavailable on this Mac." = "Metal bu Mac’te kullanılamıyor.";
+"Needed to show your live desktop" = "Canlı masaüstünüzü göstermek için gerekli";
+"No built-in MacBook display was found." = "Dahili MacBook ekranı bulunamadı.";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "Masaüstü karesi gelmedi. Ekran Kaydı iznini kontrol edin ve Hinge’i yeniden açın.";
+"Not connected" = "Bağlı değil";
+"Off" = "Kapalı";
+"On" = "Açık";
+"Open Hinge" = "Hinge’i Aç";
+"Open Login Items" = "Giriş Öğeleri’ni Aç";
+"Open Settings" = "Ayarlar’ı Aç";
+"Open position" = "Açık konum";
+"Open the lid to your comfortable viewing position first." = "Önce kapağı rahat görüş açınıza kadar açın.";
+"Quit Hinge" = "Hinge’den Çık";
+"Relaunch" = "Yeniden Başlat";
+"Relaunch Hinge to switch languages." = "Dili değiştirmek için Hinge’i yeniden başlatın.";
+"Reset effect strength to 100%" = "Efekt gücünü %100’e sıfırla";
+"Reset effect strength to default" = "Efekt gücünü varsayılana sıfırla";
+"Save the lid angle you are viewing at right now" = "Şu anda baktığınız kapak açısını kaydeder";
+"Screen Recording" = "Ekran Kaydı";
+"Set" = "Ayarla";
+"Set open position" = "Açık konumu ayarla";
+"Settings" = "Ayarlar";
+"Settings…" = "Ayarlar…";
+"Sides" = "Kenarlar";
+"Starting…" = "Başlatılıyor…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "100° ile başlar. Rahat açık konumunuzu bir kez ayarlayın, Hinge onu hatırlar.";
+"Status" = "Durum";
+"System Language" = "Sistem Dili";
+"The desktop renderer is missing. Rebuild the app." = "Masaüstü görüntüleyici eksik. Uygulamayı yeniden derleyin.";
+"The desktop renderer stopped: %@" = "Masaüstü görüntüleme durdu: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "Kapak sensörü yanıt vermiyor. Hinge, sensör yeniden bağlanır bağlanmaz tekrar açılır.";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "Bu Mac’te kapak açısı sensörü yok gibi görünüyor, bu yüzden Hinge kapağı takip edemiyor.";
+"Turn Hinge on or off" = "Hinge’i aç veya kapat";
+"Turn Hinge on to follow the lid." = "Kapağı takip etmesi için Hinge’i açın.";
+"Turn off" = "Kapat";
+"Turn on" = "Aç";
+"Waiting for the lid angle sensor." = "Kapak açısı sensörü bekleniyor.";
+"Waiting…" = "Bekleniyor…";
+"Your desktop bends as the lid closes." = "Kapak kapanırken masaüstünüz bükülür.";
+"Your desktop follows your lid." = "Masaüstünüz kapağınızı takip eder.";
+"⌃⌥H anywhere" = "Her yerden ⌃⌥H";
diff --git a/Resources/Localizations/vi.lproj/Localizable.strings b/Resources/Localizations/vi.lproj/Localizable.strings
new file mode 100644
index 0000000..74bff60
--- /dev/null
+++ b/Resources/Localizations/vi.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "Giới thiệu";
+"Allow Hinge in Login Items to finish." = "Cho phép Hinge trong Mục đăng nhập để hoàn tất.";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "Cho phép Hinge trong cài đặt Ghi màn hình, sau đó thoát và mở lại.";
+"Allowed" = "Đã cho phép";
+"Attention" = "Chú ý";
+"Back" = "Quay lại";
+"Beside the folded desktop" = "Hai bên màn hình nền đã gập";
+"Black" = "Đen";
+"Blur" = "Mờ";
+"Connected" = "Đã kết nối";
+"Controls" = "Điều khiển";
+"Could not allocate the desktop texture." = "Không thể cấp phát texture màn hình nền.";
+"Could not allocate the renderer warmup texture." = "Không thể cấp phát texture khởi động của bộ hiển thị.";
+"Could not initialize the desktop texture." = "Không thể khởi tạo texture màn hình nền.";
+"Could not prepare the desktop renderer." = "Không thể chuẩn bị bộ hiển thị màn hình nền.";
+"Could not prepare the fold pipeline." = "Không thể chuẩn bị quy trình hiển thị nếp gập.";
+"Could not update Launch at Login: %@" = "Không thể cập nhật “Mở khi đăng nhập”: %@";
+"Could not update the captured windows: %@" = "Không thể cập nhật các cửa sổ được ghi: %@";
+"Effect strength" = "Cường độ hiệu ứng";
+"Getting the desktop and the sensor ready." = "Đang chuẩn bị màn hình nền và cảm biến.";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge không thể đăng ký ⌃⌥H (lỗi %d).";
+"Hinge is on but not running yet." = "Hinge đang bật nhưng chưa chạy.";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge chỉ đọc màn hình để vẽ nếp gập. Các khung hình chỉ nằm trong bộ nhớ của máy Mac.";
+"Keyboard shortcut unavailable" = "Phím tắt không khả dụng";
+"Language" = "Ngôn ngữ";
+"Launch at login" = "Mở khi đăng nhập";
+"Lid angle sensor" = "Cảm biến góc nắp";
+"Look" = "Giao diện";
+"Metal is unavailable on this Mac." = "Metal không khả dụng trên máy Mac này.";
+"Needed to show your live desktop" = "Cần để hiển thị màn hình nền trực tiếp";
+"No built-in MacBook display was found." = "Không tìm thấy màn hình tích hợp của MacBook.";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "Không nhận được khung hình màn hình nền. Hãy kiểm tra quyền Ghi màn hình và mở lại Hinge.";
+"Not connected" = "Chưa kết nối";
+"Off" = "Tắt";
+"On" = "Bật";
+"Open Hinge" = "Mở Hinge";
+"Open Login Items" = "Mở Mục đăng nhập";
+"Open Settings" = "Mở Cài đặt";
+"Open position" = "Vị trí mở";
+"Open the lid to your comfortable viewing position first." = "Hãy mở nắp đến góc nhìn thoải mái của bạn trước.";
+"Quit Hinge" = "Thoát Hinge";
+"Relaunch" = "Mở lại";
+"Relaunch Hinge to switch languages." = "Mở lại Hinge để đổi ngôn ngữ.";
+"Reset effect strength to 100%" = "Đặt lại cường độ hiệu ứng về 100%";
+"Reset effect strength to default" = "Đặt lại cường độ hiệu ứng về mặc định";
+"Save the lid angle you are viewing at right now" = "Lưu góc nắp bạn đang nhìn lúc này";
+"Screen Recording" = "Ghi màn hình";
+"Set" = "Đặt";
+"Set open position" = "Đặt vị trí mở";
+"Settings" = "Cài đặt";
+"Settings…" = "Cài đặt…";
+"Sides" = "Hai bên";
+"Starting…" = "Đang khởi động…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "Mặc định là 100°. Đặt vị trí mở thoải mái của bạn một lần, Hinge sẽ ghi nhớ.";
+"Status" = "Trạng thái";
+"System Language" = "Ngôn ngữ hệ thống";
+"The desktop renderer is missing. Rebuild the app." = "Thiếu bộ hiển thị màn hình nền. Hãy dựng lại ứng dụng.";
+"The desktop renderer stopped: %@" = "Quá trình hiển thị màn hình nền đã dừng: %@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "Cảm biến nắp đã ngừng phản hồi. Hinge sẽ tự bật lại ngay khi kết nối lại.";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "Máy Mac này có vẻ không có cảm biến góc nắp, nên Hinge không thể theo nắp máy.";
+"Turn Hinge on or off" = "Bật hoặc tắt Hinge";
+"Turn Hinge on to follow the lid." = "Bật Hinge để theo nắp máy.";
+"Turn off" = "Tắt";
+"Turn on" = "Bật";
+"Waiting for the lid angle sensor." = "Đang chờ cảm biến góc nắp.";
+"Waiting…" = "Đang chờ…";
+"Your desktop bends as the lid closes." = "Màn hình nền uốn cong khi bạn gập nắp.";
+"Your desktop follows your lid." = "Màn hình nền chuyển động theo nắp máy.";
+"⌃⌥H anywhere" = "⌃⌥H ở bất kỳ đâu";
diff --git a/Resources/Localizations/zh-Hans.lproj/Localizable.strings b/Resources/Localizations/zh-Hans.lproj/Localizable.strings
new file mode 100644
index 0000000..6845c2e
--- /dev/null
+++ b/Resources/Localizations/zh-Hans.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "关于";
+"Allow Hinge in Login Items to finish." = "请在登录项中允许 Hinge 以完成设置。";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "请在“屏幕录制”设置中允许 Hinge,然后退出并重新打开。";
+"Allowed" = "已允许";
+"Attention" = "注意";
+"Back" = "返回";
+"Beside the folded desktop" = "折叠后桌面的两侧";
+"Black" = "黑色";
+"Blur" = "模糊";
+"Connected" = "已连接";
+"Controls" = "控制";
+"Could not allocate the desktop texture." = "无法分配桌面纹理。";
+"Could not allocate the renderer warmup texture." = "无法分配渲染器预热纹理。";
+"Could not initialize the desktop texture." = "无法初始化桌面纹理。";
+"Could not prepare the desktop renderer." = "无法准备桌面渲染器。";
+"Could not prepare the fold pipeline." = "无法准备折叠渲染管线。";
+"Could not update Launch at Login: %@" = "无法更新“登录时打开”:%@";
+"Could not update the captured windows: %@" = "无法更新录制的窗口:%@";
+"Effect strength" = "效果强度";
+"Getting the desktop and the sensor ready." = "正在准备桌面和传感器。";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge 无法注册 ⌃⌥H(错误 %d)。";
+"Hinge is on but not running yet." = "Hinge 已开启,但尚未运行。";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge 读取屏幕内容只为绘制折叠效果,画面只保存在你的 Mac 内存中。";
+"Keyboard shortcut unavailable" = "键盘快捷键不可用";
+"Language" = "语言";
+"Launch at login" = "登录时打开";
+"Lid angle sensor" = "屏幕开合角度传感器";
+"Look" = "外观";
+"Metal is unavailable on this Mac." = "这台 Mac 无法使用 Metal。";
+"Needed to show your live desktop" = "显示实时桌面需要此权限";
+"No built-in MacBook display was found." = "未找到 MacBook 内建显示器。";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "没有收到桌面画面。请检查屏幕录制权限并重新打开 Hinge。";
+"Not connected" = "未连接";
+"Off" = "已关闭";
+"On" = "已开启";
+"Open Hinge" = "打开 Hinge";
+"Open Login Items" = "打开登录项";
+"Open Settings" = "打开设置";
+"Open position" = "打开角度";
+"Open the lid to your comfortable viewing position first." = "请先把屏幕打开到你习惯的观看角度。";
+"Quit Hinge" = "退出 Hinge";
+"Relaunch" = "重新打开";
+"Relaunch Hinge to switch languages." = "重新打开 Hinge 以切换语言。";
+"Reset effect strength to 100%" = "将效果强度恢复为 100%";
+"Reset effect strength to default" = "将效果强度恢复为默认值";
+"Save the lid angle you are viewing at right now" = "保存你当前观看时的屏幕角度";
+"Screen Recording" = "屏幕录制";
+"Set" = "设定";
+"Set open position" = "设为打开角度";
+"Settings" = "设置";
+"Settings…" = "设置…";
+"Sides" = "两侧";
+"Starting…" = "正在启动…";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "默认 100°。设定一次你习惯的打开角度,Hinge 会记住它。";
+"Status" = "状态";
+"System Language" = "系统语言";
+"The desktop renderer is missing. Rebuild the app." = "缺少桌面渲染组件。请重新构建应用。";
+"The desktop renderer stopped: %@" = "桌面渲染已停止:%@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "屏幕开合角度传感器停止响应。重新连接后 Hinge 会自动重新开启。";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "这台 Mac 似乎没有屏幕开合角度传感器,因此 Hinge 无法跟随屏幕开合。";
+"Turn Hinge on or off" = "开启或关闭 Hinge";
+"Turn Hinge on to follow the lid." = "开启 Hinge 以跟随屏幕开合。";
+"Turn off" = "关闭";
+"Turn on" = "开启";
+"Waiting for the lid angle sensor." = "正在等待屏幕开合角度传感器。";
+"Waiting…" = "正在等待…";
+"Your desktop bends as the lid closes." = "合上屏幕时桌面会随之弯折。";
+"Your desktop follows your lid." = "你的桌面随屏幕开合而动。";
+"⌃⌥H anywhere" = "随时按 ⌃⌥H";
diff --git a/Resources/Localizations/zh-Hant.lproj/Localizable.strings b/Resources/Localizations/zh-Hant.lproj/Localizable.strings
new file mode 100644
index 0000000..4a2a532
--- /dev/null
+++ b/Resources/Localizations/zh-Hant.lproj/Localizable.strings
@@ -0,0 +1,69 @@
+"About" = "關於";
+"Allow Hinge in Login Items to finish." = "請在登入項目中允許 Hinge 以完成設定。";
+"Allow Hinge in Screen Recording settings, then quit and reopen it." = "請在「螢幕錄製」設定中允許 Hinge,然後結束並重新開啟。";
+"Allowed" = "已允許";
+"Attention" = "注意";
+"Back" = "返回";
+"Beside the folded desktop" = "折疊後桌面的兩側";
+"Black" = "黑色";
+"Blur" = "模糊";
+"Connected" = "已連接";
+"Controls" = "控制";
+"Could not allocate the desktop texture." = "無法配置桌面紋理。";
+"Could not allocate the renderer warmup texture." = "無法配置繪製器預熱紋理。";
+"Could not initialize the desktop texture." = "無法初始化桌面紋理。";
+"Could not prepare the desktop renderer." = "無法準備桌面繪製器。";
+"Could not prepare the fold pipeline." = "無法準備摺疊繪製管線。";
+"Could not update Launch at Login: %@" = "無法更新「登入時開啟」:%@";
+"Could not update the captured windows: %@" = "無法更新錄製的視窗:%@";
+"Effect strength" = "效果強度";
+"Getting the desktop and the sensor ready." = "正在準備桌面和感測器。";
+"Hinge could not register ⌃⌥H (error %d)." = "Hinge 無法註冊 ⌃⌥H(錯誤 %d)。";
+"Hinge is on but not running yet." = "Hinge 已開啟,但尚未執行。";
+"Hinge reads your display only to draw the fold. Frames stay in memory on your Mac." = "Hinge 讀取螢幕內容只為繪製摺疊效果,畫面只保存在你的 Mac 記憶體中。";
+"Keyboard shortcut unavailable" = "無法使用鍵盤快速鍵";
+"Language" = "語言";
+"Launch at login" = "登入時開啟";
+"Lid angle sensor" = "螢幕開合角度感測器";
+"Look" = "外觀";
+"Metal is unavailable on this Mac." = "這部 Mac 無法使用 Metal。";
+"Needed to show your live desktop" = "顯示即時桌面需要此權限";
+"No built-in MacBook display was found." = "找不到 MacBook 內建顯示器。";
+"No desktop frames arrived. Check Screen Recording permission and reopen Hinge." = "沒有收到桌面畫面。請檢查螢幕錄製權限並重新開啟 Hinge。";
+"Not connected" = "未連接";
+"Off" = "已關閉";
+"On" = "已開啟";
+"Open Hinge" = "打開 Hinge";
+"Open Login Items" = "打開登入項目";
+"Open Settings" = "打開設定";
+"Open position" = "開啟角度";
+"Open the lid to your comfortable viewing position first." = "請先把螢幕打開到你習慣的觀看角度。";
+"Quit Hinge" = "結束 Hinge";
+"Relaunch" = "重新開啟";
+"Relaunch Hinge to switch languages." = "重新開啟 Hinge 以切換語言。";
+"Reset effect strength to 100%" = "將效果強度重置為 100%";
+"Reset effect strength to default" = "將效果強度重置為預設值";
+"Save the lid angle you are viewing at right now" = "儲存你目前觀看時的螢幕角度";
+"Screen Recording" = "螢幕錄製";
+"Set" = "設定";
+"Set open position" = "設為開啟角度";
+"Settings" = "設定";
+"Settings…" = "設定⋯";
+"Sides" = "兩側";
+"Starting…" = "正在啟動⋯";
+"Starts at 100°. Set your comfortable open position once, and Hinge remembers it." = "預設為 100°。設定一次你習慣的開啟角度,Hinge 會記住它。";
+"Status" = "狀態";
+"System Language" = "系統語言";
+"The desktop renderer is missing. Rebuild the app." = "缺少桌面繪製元件。請重新建置 App。";
+"The desktop renderer stopped: %@" = "桌面繪製已停止:%@";
+"The lid sensor stopped responding. Hinge turns back on as soon as it reconnects." = "螢幕開合角度感測器沒有回應。重新連接後 Hinge 會自動重新開啟。";
+"This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid." = "這部 Mac 似乎沒有螢幕開合角度感測器,因此 Hinge 無法跟隨螢幕開合。";
+"Turn Hinge on or off" = "開啟或關閉 Hinge";
+"Turn Hinge on to follow the lid." = "開啟 Hinge 以跟隨螢幕開合。";
+"Turn off" = "關閉";
+"Turn on" = "開啟";
+"Waiting for the lid angle sensor." = "正在等待螢幕開合角度感測器。";
+"Waiting…" = "正在等待⋯";
+"Your desktop bends as the lid closes." = "闔上螢幕時桌面會隨之彎折。";
+"Your desktop follows your lid." = "你的桌面隨螢幕開合而動。";
+"⌃⌥H anywhere" = "隨時按 ⌃⌥H";
diff --git a/Sources/DesktopRenderer.swift b/Sources/DesktopRenderer.swift
index 6c1cdf1..a7c40b2 100644
--- a/Sources/DesktopRenderer.swift
+++ b/Sources/DesktopRenderer.swift
@@ -53,7 +53,7 @@ final class DesktopRenderer: NSObject, MTKViewDelegate {
init(resources: Bundle, motion: LidMotion) throws {
guard let device = MTLCreateSystemDefaultDevice(), let queue = device.makeCommandQueue() else {
- throw DesktopError.message("Metal is unavailable on this Mac.")
+ throw DesktopError.message(String(localized: "Metal is unavailable on this Mac."))
}
self.device = device
self.queue = queue
@@ -62,7 +62,8 @@ final class DesktopRenderer: NSObject, MTKViewDelegate {
self.extend = MPSImageBilinearScale(device: device)
self.extend.edgeMode = .clamp
guard let sourceURL = resources.url(forResource: "Fold", withExtension: "metal") else {
- throw DesktopError.message("The desktop renderer is missing. Rebuild the app.")
+ throw DesktopError.message(
+ String(localized: "The desktop renderer is missing. Rebuild the app."))
}
let library = try device.makeLibrary(
source: String(contentsOf: sourceURL, encoding: .utf8), options: nil)
@@ -94,19 +95,20 @@ final class DesktopRenderer: NSObject, MTKViewDelegate {
guard self.prepareBlur(width: width, height: height),
let command = self.queue.makeCommandBuffer()
else {
- throw DesktopError.message("Could not prepare the desktop renderer.")
+ throw DesktopError.message(String(localized: "Could not prepare the desktop renderer."))
}
let descriptor = MTLTextureDescriptor.texture2DDescriptor(
pixelFormat: .bgra8Unorm, width: width, height: height, mipmapped: false)
descriptor.storageMode = .private
descriptor.usage = [.shaderRead, .renderTarget]
guard let source = self.device.makeTexture(descriptor: descriptor) else {
- throw DesktopError.message("Could not allocate the desktop texture.")
+ throw DesktopError.message(String(localized: "Could not allocate the desktop texture."))
}
descriptor.width = 32
descriptor.height = 32
guard let destination = self.device.makeTexture(descriptor: descriptor) else {
- throw DesktopError.message("Could not allocate the renderer warmup texture.")
+ throw DesktopError.message(
+ String(localized: "Could not allocate the renderer warmup texture."))
}
let sourcePass = MTLRenderPassDescriptor()
sourcePass.colorAttachments[0].texture = source
@@ -114,11 +116,11 @@ final class DesktopRenderer: NSObject, MTKViewDelegate {
sourcePass.colorAttachments[0].storeAction = .store
sourcePass.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 1)
guard let clear = command.makeRenderCommandEncoder(descriptor: sourcePass) else {
- throw DesktopError.message("Could not initialize the desktop texture.")
+ throw DesktopError.message(String(localized: "Could not initialize the desktop texture."))
}
clear.endEncoding()
guard self.encodeBlur(command: command, texture: source) else {
- throw DesktopError.message("Could not prepare the desktop renderer.")
+ throw DesktopError.message(String(localized: "Could not prepare the desktop renderer."))
}
let pass = MTLRenderPassDescriptor()
pass.colorAttachments[0].texture = destination
@@ -127,7 +129,7 @@ final class DesktopRenderer: NSObject, MTKViewDelegate {
guard
self.encodeFold(command: command, pass: pass, texture: source, progress: 0.5, opacity: 1)
else {
- throw DesktopError.message("Could not prepare the fold pipeline.")
+ throw DesktopError.message(String(localized: "Could not prepare the fold pipeline."))
}
command.addCompletedHandler { command in
if let error = command.error {
diff --git a/Sources/HingeApp.swift b/Sources/HingeApp.swift
index fefbd92..8fd278f 100644
--- a/Sources/HingeApp.swift
+++ b/Sources/HingeApp.swift
@@ -8,6 +8,10 @@ struct HingeApp: App {
@StateObject private var desktop = LiveDesktop()
@StateObject private var navigator = Navigator()
+ init() {
+ _ = AppLanguage.atLaunch
+ }
+
var body: some Scene {
Window("Hinge", id: "main") {
MainView(desktop: desktop, navigator: navigator)
@@ -87,8 +91,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
private func showHotKeyError(_ status: OSStatus) {
let alert = NSAlert()
- alert.messageText = "Keyboard shortcut unavailable"
- alert.informativeText = "Hinge could not register ⌃⌥H (error \(status))."
+ alert.messageText = String(localized: "Keyboard shortcut unavailable")
+ alert.informativeText = String(localized: "Hinge could not register ⌃⌥H (error \(status)).")
alert.alertStyle = .warning
alert.runModal()
}
@@ -104,7 +108,7 @@ struct HingeMenu: View {
desktop.setEnabled(!desktop.isEnabled)
} label: {
HStack {
- Text(desktop.isEnabled ? "Turn off" : "Turn on")
+ Text(desktop.isEnabled ? String(localized: "Turn off") : String(localized: "Turn on"))
Spacer()
Text("⌃⌥H").foregroundStyle(.secondary)
}
diff --git a/Sources/LiveDesktop.swift b/Sources/LiveDesktop.swift
index de02906..b631205 100644
--- a/Sources/LiveDesktop.swift
+++ b/Sources/LiveDesktop.swift
@@ -42,9 +42,13 @@ final class LiveDesktop: NSObject, ObservableObject {
@Published private(set) var needsPermission = false
@Published private(set) var isEnabled = UserDefaults.standard.bool(forKey: "effectEnabled")
private static let missingSensorMessage =
- "This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid."
+ String(
+ localized:
+ "This Mac doesn't appear to have a lid angle sensor, so Hinge can't follow the lid.")
private static let sensorDroppedMessage =
- "The lid sensor stopped responding. Hinge turns back on as soon as it reconnects."
+ String(
+ localized:
+ "The lid sensor stopped responding. Hinge turns back on as soon as it reconnects.")
private let sensor = LidSensor()
private var sensorMissing = false
private let motion: LidMotion
@@ -153,7 +157,7 @@ final class LiveDesktop: NSObject, ObservableObject {
func setOpenPosition() {
guard let angle = motion.calibrate() else {
- error = "Open the lid to your comfortable viewing position first."
+ error = String(localized: "Open the lid to your comfortable viewing position first.")
return
}
openAngle = angle
@@ -203,7 +207,8 @@ final class LiveDesktop: NSObject, ObservableObject {
CGPreflightScreenCaptureAccess() || (promptForPermission && CGRequestScreenCaptureAccess())
guard hasScreenAccess else {
needsPermission = true
- error = "Allow Hinge in Screen Recording settings, then quit and reopen it."
+ error = String(
+ localized: "Allow Hinge in Screen Recording settings, then quit and reopen it.")
return
}
isStarting = true
@@ -225,7 +230,7 @@ final class LiveDesktop: NSObject, ObservableObject {
== display.displayID
})
else {
- throw DesktopError.message("No built-in MacBook display was found.")
+ throw DesktopError.message(String(localized: "No built-in MacBook display was found."))
}
let ownApplications = content.applications.filter {
$0.processID == ProcessInfo.processInfo.processIdentifier
@@ -271,7 +276,8 @@ final class LiveDesktop: NSObject, ObservableObject {
guard let self, self.session == session else { return }
if let failure {
self.stop()
- self.error = "The desktop renderer stopped: \(failure.localizedDescription)"
+ self.error = String(
+ localized: "The desktop renderer stopped: \(failure.localizedDescription)")
}
}
renderer.onRest = { [weak self] in self?.restOverlay() }
@@ -287,7 +293,9 @@ final class LiveDesktop: NSObject, ObservableObject {
guard CACurrentMediaTime() < deadline else {
needsPermission = true
throw DesktopError.message(
- "No desktop frames arrived. Check Screen Recording permission and reopen Hinge.")
+ String(
+ localized:
+ "No desktop frames arrived. Check Screen Recording permission and reopen Hinge."))
}
try await Task.sleep(for: .milliseconds(10))
}
@@ -334,7 +342,8 @@ final class LiveDesktop: NSObject, ObservableObject {
} catch {
guard session == currentSession else { return }
stop()
- self.error = "Could not update the captured windows: \(error.localizedDescription)"
+ self.error = String(
+ localized: "Could not update the captured windows: \(error.localizedDescription)")
}
}
diff --git a/Sources/MainView.swift b/Sources/MainView.swift
index ca5e20f..1aeb234 100644
--- a/Sources/MainView.swift
+++ b/Sources/MainView.swift
@@ -30,16 +30,18 @@ struct MainView: View {
private var header: some View {
ZStack {
- Text(navigator.screen == .main ? "Hinge" : "Settings")
+ Text(navigator.screen == .main ? "Hinge" : String(localized: "Settings"))
.font(.system(size: 13, weight: .semibold))
HStack(spacing: 0) {
if navigator.screen == .settings {
- HeaderButton(symbol: "chevron.left", help: "Back") { navigator.screen = .main }
- .keyboardShortcut(.escape, modifiers: [])
+ HeaderButton(symbol: "chevron.left", help: String(localized: "Back")) {
+ navigator.screen = .main
+ }
+ .keyboardShortcut(.escape, modifiers: [])
}
Spacer(minLength: 0)
if navigator.screen == .main {
- HeaderButton(symbol: "gearshape.fill", help: "Settings") {
+ HeaderButton(symbol: "gearshape.fill", help: String(localized: "Settings")) {
navigator.screen = .settings
}
.keyboardShortcut(",", modifiers: .command)
@@ -101,7 +103,7 @@ struct MainView: View {
.multilineTextAlignment(.center)
.fixedSize(horizontal: false, vertical: true)
}
- Button(desktop.isEnabled ? "Turn off" : "Turn on") {
+ Button(desktop.isEnabled ? String(localized: "Turn off") : String(localized: "Turn on")) {
desktop.setEnabled(!desktop.isEnabled)
}
.buttonStyle(.borderedProminent)
@@ -116,11 +118,15 @@ struct MainView: View {
private var positionCard: some View {
SettingsGroup(
- title: "Open position",
- footnote: "Starts at 100°. Set your comfortable open position once, and Hinge remembers it."
+ title: String(localized: "Open position"),
+ footnote: String(
+ localized:
+ "Starts at 100°. Set your comfortable open position once, and Hinge remembers it.")
) {
SettingsRow(
- "angle", tint: .indigo, title: "Open position", subtitle: "\(Int(desktop.openAngle))°"
+ "angle", tint: .indigo, title: String(localized: "Open position"),
+ subtitle: Measurement(value: desktop.openAngle, unit: UnitAngle.degrees).formatted(
+ .measurement(width: .narrow, numberFormatStyle: .number.precision(.fractionLength(0))))
) {
Button("Set") { desktop.setOpenPosition() }
.controlSize(.small)
@@ -131,7 +137,7 @@ struct MainView: View {
}
private func errorCard(_ message: String) -> some View {
- SettingsGroup(title: "Attention") {
+ SettingsGroup(title: String(localized: "Attention")) {
SettingsRow("exclamationmark.triangle.fill", tint: .orange, title: message) {
if desktop.needsPermission {
Button("Open Settings", action: openScreenRecordingSettings)
@@ -142,17 +148,17 @@ struct MainView: View {
}
private var title: String {
- if desktop.isActive { return "On" }
- if desktop.isStarting { return "Starting…" }
- return desktop.isEnabled ? "Waiting…" : "Off"
+ if desktop.isActive { return String(localized: "On") }
+ if desktop.isStarting { return String(localized: "Starting…") }
+ return desktop.isEnabled ? String(localized: "Waiting…") : String(localized: "Off")
}
private var subtitle: String {
- if desktop.isActive { return "Your desktop bends as the lid closes." }
- if desktop.isStarting { return "Getting the desktop and the sensor ready." }
- if !desktop.sensorAvailable { return "Waiting for the lid angle sensor." }
- if desktop.isEnabled { return "Hinge is on but not running yet." }
- return "Turn Hinge on to follow the lid."
+ if desktop.isActive { return String(localized: "Your desktop bends as the lid closes.") }
+ if desktop.isStarting { return String(localized: "Getting the desktop and the sensor ready.") }
+ if !desktop.sensorAvailable { return String(localized: "Waiting for the lid angle sensor.") }
+ if desktop.isEnabled { return String(localized: "Hinge is on but not running yet.") }
+ return String(localized: "Turn Hinge on to follow the lid.")
}
}
diff --git a/Sources/SettingsView.swift b/Sources/SettingsView.swift
index e146926..b4383f7 100644
--- a/Sources/SettingsView.swift
+++ b/Sources/SettingsView.swift
@@ -5,6 +5,7 @@ struct SettingsView: View {
@ObservedObject var desktop: LiveDesktop
@State private var loginItemStatus = SMAppService.mainApp.status
@State private var loginItemError: String?
+ @State private var language = AppLanguage.current
var body: some View {
SettingsPage {
@@ -20,10 +21,10 @@ struct SettingsView: View {
}
private var look: some View {
- SettingsGroup(title: "Look") {
+ SettingsGroup(title: String(localized: "Look")) {
SettingsRow(
- "slider.horizontal.3", tint: .orange, title: "Effect strength",
- subtitle: "\(Int(desktop.effectStrength * 100))%"
+ "slider.horizontal.3", tint: .orange, title: String(localized: "Effect strength"),
+ subtitle: strength
) {
HStack(spacing: 8) {
Slider(
@@ -34,19 +35,22 @@ struct SettingsView: View {
)
.frame(width: 110)
.accessibilityLabel("Effect strength")
- .accessibilityValue("\(Int(desktop.effectStrength * 100)) percent")
- Button("Default") { desktop.setEffectStrength(1) }
- .controlSize(.small)
- .fixedSize()
- .disabled(desktop.effectStrength == 1)
- .help("Reset effect strength to 100%")
- .accessibilityLabel("Reset effect strength to default")
+ .accessibilityValue(strength)
+ Button {
+ desktop.setEffectStrength(1)
+ } label: {
+ Image(systemName: "arrow.counterclockwise")
+ }
+ .controlSize(.small)
+ .disabled(desktop.effectStrength == 1)
+ .help(String(localized: "Reset effect strength to 100%"))
+ .accessibilityLabel("Reset effect strength to default")
}
}
SettingsDivider()
SettingsRow(
- "square.lefthalf.filled", tint: .indigo, title: "Sides",
- subtitle: "Beside the folded desktop"
+ "square.lefthalf.filled", tint: .indigo, title: String(localized: "Sides"),
+ subtitle: String(localized: "Beside the folded desktop")
) {
Picker(
"Sides",
@@ -62,8 +66,8 @@ struct SettingsView: View {
}
SettingsDivider()
SettingsRow(
- "crop", tint: .teal, title: "Crop from the top",
- subtitle: "The top of the desktop slides out of view as the lid closes."
+ "crop", tint: .teal, title: String(localized: "Crop from the top"),
+ subtitle: String(localized: "The top of the desktop slides out of view as the lid closes.")
) {
Toggle(
"Crop from the top",
@@ -75,10 +79,12 @@ struct SettingsView: View {
}
SettingsDivider()
SettingsRow(
- "camera.aperture", tint: .purple, title: "Blur by distance",
+ "camera.aperture", tint: .purple, title: String(localized: "Blur by distance"),
subtitle: desktop.blursByDistance
- ? "Blur grows with distance from the open screen, so the hinge edge stays sharp."
- : "Blur builds toward the top and fades out near the hinge."
+ ? String(
+ localized:
+ "Blur grows with distance from the open screen, so the hinge edge stays sharp.")
+ : String(localized: "Blur builds toward the top and fades out near the hinge.")
) {
Toggle(
"Blur by distance",
@@ -92,9 +98,10 @@ struct SettingsView: View {
}
private var controls: some View {
- SettingsGroup(title: "Controls") {
+ SettingsGroup(title: String(localized: "Controls")) {
SettingsRow(
- "power", tint: .blue, title: "Launch at login", subtitle: loginItemError ?? loginItemNote
+ "power", tint: .blue, title: String(localized: "Launch at login"),
+ subtitle: loginItemError ?? loginItemNote
) {
if loginItemStatus == .requiresApproval {
Button("Open Login Items") { SMAppService.openSystemSettingsLoginItems() }
@@ -106,7 +113,7 @@ struct SettingsView: View {
.labelsHidden()
}
SettingsDivider()
- SettingsRow("keyboard", tint: .gray, title: "Turn Hinge on or off") {
+ SettingsRow("keyboard", tint: .gray, title: String(localized: "Turn Hinge on or off")) {
Text("⌃⌥H")
.font(.system(size: 12, weight: .medium))
.foregroundStyle(.secondary)
@@ -114,19 +121,48 @@ struct SettingsView: View {
.padding(.vertical, 3)
.background(Color.primary.opacity(0.07), in: RoundedRectangle(cornerRadius: 5))
}
+ SettingsDivider()
+ SettingsRow(
+ "globe", tint: .indigo, title: String(localized: "Language"),
+ subtitle: language == AppLanguage.atLaunch
+ ? nil : String(localized: "Relaunch Hinge to switch languages.")
+ ) {
+ if language != AppLanguage.atLaunch {
+ Button("Relaunch", action: AppLanguage.relaunch)
+ .controlSize(.small)
+ }
+ Picker(
+ "Language",
+ selection: Binding(
+ get: { language },
+ set: {
+ language = $0
+ AppLanguage.choose($0)
+ })
+ ) {
+ ForEach(AppLanguage.available, id: \.self) { code in
+ Text(verbatim: AppLanguage.name(of: code)).tag(code)
+ }
+ }
+ .labelsHidden()
+ .fixedSize()
+ .controlSize(.small)
+ }
}
}
private var status: some View {
SettingsGroup(
- title: "Status",
- footnote:
- "Hinge reads your display only to draw the fold. Frames stay in memory on your Mac."
+ title: String(localized: "Status"),
+ footnote: String(
+ localized:
+ "Hinge reads your display only to draw the fold. Frames stay in memory on your Mac.")
) {
let allowed = CGPreflightScreenCaptureAccess()
SettingsRow(
- "rectangle.dashed.badge.record", tint: .red, title: "Screen Recording",
- subtitle: allowed ? "Allowed" : "Needed to show your live desktop"
+ "rectangle.dashed.badge.record", tint: .red, title: String(localized: "Screen Recording"),
+ subtitle: allowed
+ ? String(localized: "Allowed") : String(localized: "Needed to show your live desktop")
) {
if allowed {
Image(systemName: "checkmark.circle.fill").foregroundStyle(.green)
@@ -137,8 +173,9 @@ struct SettingsView: View {
}
SettingsDivider()
SettingsRow(
- "laptopcomputer", tint: .teal, title: "Lid angle sensor",
- subtitle: desktop.sensorAvailable ? "Connected" : "Not connected"
+ "laptopcomputer", tint: .teal, title: String(localized: "Lid angle sensor"),
+ subtitle: desktop.sensorAvailable
+ ? String(localized: "Connected") : String(localized: "Not connected")
) {
Circle()
.fill(desktop.sensorAvailable ? Color.green : Color.orange)
@@ -148,9 +185,9 @@ struct SettingsView: View {
}
private var about: some View {
- SettingsGroup(title: "About") {
+ SettingsGroup(title: String(localized: "About")) {
SettingsRow(
- title: "Hinge \(version)", subtitle: "Your desktop follows your lid.",
+ title: "Hinge \(version)", subtitle: String(localized: "Your desktop follows your lid."),
leading: { Image(nsImage: NSApp.applicationIconImage).resizable() },
trailing: {
if let project = URL(string: "https://github.com/Noveum/hinge") {
@@ -161,7 +198,8 @@ struct SettingsView: View {
}
private var loginItemNote: String? {
- loginItemStatus == .requiresApproval ? "Allow Hinge in Login Items to finish." : nil
+ loginItemStatus == .requiresApproval
+ ? String(localized: "Allow Hinge in Login Items to finish.") : nil
}
private var launchAtLogin: Binding {
@@ -181,12 +219,55 @@ struct SettingsView: View {
}
loginItemError = nil
} catch {
- loginItemError = "Could not update Launch at Login: \(error.localizedDescription)"
+ loginItemError = String(
+ localized: "Could not update Launch at Login: \(error.localizedDescription)")
}
loginItemStatus = SMAppService.mainApp.status
}
+ private var strength: String {
+ desktop.effectStrength.formatted(.percent.precision(.fractionLength(0)))
+ }
+
private var version: String {
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""
}
}
+
+enum AppLanguage {
+ static let atLaunch = current
+
+ static var current: String {
+ let domain = UserDefaults.standard.persistentDomain(forName: Bundle.main.bundleIdentifier ?? "")
+ if let saved = (domain?["AppleLanguages"] as? [String])?.first, !saved.isEmpty {
+ return saved
+ }
+ let detected =
+ Bundle.preferredLocalizations(
+ from: available, forPreferences: Locale.preferredLanguages
+ ).first ?? "en"
+ choose(detected)
+ return detected
+ }
+
+ static let available = Set(Bundle.main.localizations).subtracting(["Base"]).sorted {
+ name(of: $0).localizedStandardCompare(name(of: $1)) == .orderedAscending
+ }
+
+ static func name(of code: String) -> String {
+ let locale = Locale(identifier: code)
+ return locale.localizedString(forIdentifier: code)?.capitalized(with: locale) ?? code
+ }
+
+ static func choose(_ code: String) {
+ UserDefaults.standard.set([code], forKey: "AppleLanguages")
+ }
+
+ static func relaunch() {
+ let reopen = Process()
+ reopen.executableURL = URL(fileURLWithPath: "/bin/sh")
+ reopen.arguments = ["-c", "sleep 0.5; /usr/bin/open \"$0\"", Bundle.main.bundlePath]
+ try? reopen.run()
+ NSApp.terminate(nil)
+ }
+}
diff --git a/scripts/check.py b/scripts/check.py
index 5bb90fb..a057ade 100644
--- a/scripts/check.py
+++ b/scripts/check.py
@@ -47,6 +47,8 @@ def lexer_for(path):
return get_lexer_by_name("xml")
if path.suffix == ".metal":
return get_lexer_by_name("cpp")
+ if path.suffix == ".strings":
+ return get_lexer_by_name("c")
if path.name == ".swift-format":
return get_lexer_by_name("json")
return get_lexer_for_filename(path.name)
@@ -187,7 +189,7 @@ def native():
)
run([*formatter, "lint", "--strict", *swift])
for path in files:
- if path.suffix in {".plist", ".pbxproj"}:
+ if path.suffix in {".plist", ".pbxproj", ".strings"}:
run(["plutil", "-lint", str(path)])
shell = [str(p) for p in files if p.suffix == ".sh"]
if shell: