diff --git a/src/SharpEmu.GUI/Languages/ar.json b/src/SharpEmu.GUI/Languages/ar.json index 06d51125..3d9ffaf4 100644 --- a/src/SharpEmu.GUI/Languages/ar.json +++ b/src/SharpEmu.GUI/Languages/ar.json @@ -168,5 +168,34 @@ "Updater.Status.Timeout": "انتهت مهلة التحقق من التحديثات بعد 10 ثوانٍ.", "Updater.Status.Failed": "تعذر التحقق من التحديثات.", "Updater.Status.ChecksumFailed": "فشل التحديث المنزَّل في اجتياز تحقق SHA-256.", - "Updater.Status.Unsupported": "يتطلب التحديث التلقائي إصدار x64 لنظام Windows أو Linux أو macOS." + "Updater.Status.Unsupported": "يتطلب التحديث التلقائي إصدار x64 لنظام Windows أو Linux أو macOS.", + "Options.Graphics": "الرسومات", + "Options.Section.Rendering": "التصيير", + "Options.Section.Display": "العرض", + "Options.RenderResolution.Label": "الدقة الداخلية", + "Options.RenderResolution.Desc": "تصيير الأهداف خارج الشاشة بدقة أقل من الدقة الأصلية ثم رفع دقتها عند العرض. تمنح القيم الأقل مساحة أكبر لوحدة معالجة الرسوميات مقابل جودة الصورة؛ يُطبق عند التشغيل التالي.", + "Options.RenderResolution.Native": "100% (أصلية)", + "Options.WindowMode.Label": "وضع النافذة", + "Options.WindowMode.Desc": "نافذة عادية، أو سطح مكتب بلا حدود، أو ملء شاشة حصري.", + "Options.WindowMode.Windowed": "نافذة", + "Options.WindowMode.Borderless": "بلا حدود", + "Options.WindowMode.Exclusive": "حصري", + "Options.Resolution.Label": "الدقة", + "Options.Resolution.Desc": "حجم النافذة الأولي أو دقة ملء الشاشة الحصرية.", + "Options.Display.Label": "الشاشة", + "Options.Display.Desc": "الشاشة المستخدمة للتوسيط وملء الشاشة.", + "Options.RefreshRate.Label": "معدل التحديث", + "Options.RefreshRate.Desc": "معدل تحديث ملء الشاشة الحصري. يختار الوضع التلقائي أقرب نمط.", + "Options.RefreshRate.Automatic": "تلقائي", + "Options.Scaling.Label": "التحجيم", + "Options.Scaling.Desc": "تحجيم صورة النظام الضيف الأصلية دون تغيير دقتها الداخلية.", + "Options.Scaling.Fit": "ملاءمة", + "Options.Scaling.Cover": "تغطية", + "Options.Scaling.Stretch": "تمديد", + "Options.Scaling.Integer": "عدد صحيح", + "Options.VSync.Label": "VSync", + "Options.VSync.Desc": "استخدام عرض FIFO لإخراج خالٍ من تمزق الصورة.", + "Options.Hdr.Label": "إخراج HDR", + "Options.Hdr.Desc": "استخدام HDR عندما تدعمه الشاشة المحددة وواجهة الرسومات. يعود الوضع التلقائي إلى SDR.", + "Options.Hdr.Auto": "تلقائي" } diff --git a/src/SharpEmu.GUI/Languages/br.json b/src/SharpEmu.GUI/Languages/br.json index 351f287d..6b24abac 100644 --- a/src/SharpEmu.GUI/Languages/br.json +++ b/src/SharpEmu.GUI/Languages/br.json @@ -169,5 +169,34 @@ "Updater.Status.Timeout": "A verificação de atualizações expirou após 10 segundos.", "Updater.Status.Failed": "Não foi possível verificar as atualizações.", "Updater.Status.ChecksumFailed": "A atualização baixada falhou na verificação SHA-256.", - "Updater.Status.Unsupported": "A atualização automática requer um build x64 para Windows, Linux ou macOS." + "Updater.Status.Unsupported": "A atualização automática requer um build x64 para Windows, Linux ou macOS.", + "Options.Graphics": "Gráficos", + "Options.Section.Rendering": "RENDERIZAÇÃO", + "Options.Section.Display": "TELA", + "Options.RenderResolution.Label": "Resolução interna", + "Options.RenderResolution.Desc": "Renderiza alvos fora da tela abaixo da resolução nativa e amplia na apresentação. Valores menores trocam qualidade de imagem por folga da GPU; entra em vigor na próxima inicialização.", + "Options.RenderResolution.Native": "100% (nativa)", + "Options.WindowMode.Label": "Modo de janela", + "Options.WindowMode.Desc": "Janela normal, área de trabalho sem bordas ou tela cheia exclusiva.", + "Options.WindowMode.Windowed": "Em janela", + "Options.WindowMode.Borderless": "Sem bordas", + "Options.WindowMode.Exclusive": "Exclusiva", + "Options.Resolution.Label": "Resolução", + "Options.Resolution.Desc": "Tamanho inicial da janela ou resolução de tela cheia exclusiva.", + "Options.Display.Label": "Tela", + "Options.Display.Desc": "Monitor usado para centralização e tela cheia.", + "Options.RefreshRate.Label": "Taxa de atualização", + "Options.RefreshRate.Desc": "Taxa de atualização da tela cheia exclusiva. O modo automático seleciona o modo mais próximo.", + "Options.RefreshRate.Automatic": "Automática", + "Options.Scaling.Label": "Escala", + "Options.Scaling.Desc": "Dimensiona a imagem nativa do sistema convidado sem alterar sua resolução interna.", + "Options.Scaling.Fit": "Ajustar", + "Options.Scaling.Cover": "Preencher", + "Options.Scaling.Stretch": "Esticar", + "Options.Scaling.Integer": "Inteira", + "Options.VSync.Label": "VSync", + "Options.VSync.Desc": "Usa apresentação FIFO para evitar cortes na imagem.", + "Options.Hdr.Label": "Saída HDR", + "Options.Hdr.Desc": "Usa HDR quando a tela selecionada e o backend gráfico oferecem suporte. O modo automático retorna ao SDR.", + "Options.Hdr.Auto": "Automático" } diff --git a/src/SharpEmu.GUI/Languages/de.json b/src/SharpEmu.GUI/Languages/de.json index 2cedbca0..b9d8f55f 100644 --- a/src/SharpEmu.GUI/Languages/de.json +++ b/src/SharpEmu.GUI/Languages/de.json @@ -168,5 +168,34 @@ "Updater.Status.Timeout": "Die Updateprüfung ist nach 10 Sekunden abgelaufen.", "Updater.Status.Failed": "Updates konnten nicht geprüft werden.", "Updater.Status.ChecksumFailed": "Das heruntergeladene Update hat die SHA-256-Prüfung nicht bestanden.", - "Updater.Status.Unsupported": "Automatische Updates erfordern einen x64-Build für Windows, Linux oder macOS." + "Updater.Status.Unsupported": "Automatische Updates erfordern einen x64-Build für Windows, Linux oder macOS.", + "Options.Graphics": "Grafik", + "Options.Section.Rendering": "DARSTELLUNG", + "Options.Section.Display": "ANZEIGE", + "Options.RenderResolution.Label": "Interne Auflösung", + "Options.RenderResolution.Desc": "Offscreen-Ziele unterhalb der nativen Auflösung rendern und bei der Ausgabe hochskalieren. Niedrigere Werte tauschen Bildqualität gegen GPU-Reserven; wird beim nächsten Start wirksam.", + "Options.RenderResolution.Native": "100 % (nativ)", + "Options.WindowMode.Label": "Fenstermodus", + "Options.WindowMode.Desc": "Normales Fenster, randloser Desktop oder exklusiver Vollbildmodus.", + "Options.WindowMode.Windowed": "Fenster", + "Options.WindowMode.Borderless": "Randlos", + "Options.WindowMode.Exclusive": "Exklusiv", + "Options.Resolution.Label": "Auflösung", + "Options.Resolution.Desc": "Anfängliche Fenstergröße oder exklusive Vollbildauflösung.", + "Options.Display.Label": "Anzeige", + "Options.Display.Desc": "Monitor für Zentrierung und Vollbilddarstellung.", + "Options.RefreshRate.Label": "Bildwiederholrate", + "Options.RefreshRate.Desc": "Bildwiederholrate im exklusiven Vollbildmodus. Automatisch wählt den nächstgelegenen Modus.", + "Options.RefreshRate.Automatic": "Automatisch", + "Options.Scaling.Label": "Skalierung", + "Options.Scaling.Desc": "Das native Gastbild skalieren, ohne seine interne Auflösung zu ändern.", + "Options.Scaling.Fit": "Einpassen", + "Options.Scaling.Cover": "Ausfüllen", + "Options.Scaling.Stretch": "Strecken", + "Options.Scaling.Integer": "Ganzzahlig", + "Options.VSync.Label": "VSync", + "Options.VSync.Desc": "FIFO-Präsentation für eine Ausgabe ohne Tearing verwenden.", + "Options.Hdr.Label": "HDR-Ausgabe", + "Options.Hdr.Desc": "HDR verwenden, wenn die ausgewählte Anzeige und das Grafik-Backend es unterstützen. Automatisch fällt auf SDR zurück.", + "Options.Hdr.Auto": "Automatisch" } diff --git a/src/SharpEmu.GUI/Languages/dk.json b/src/SharpEmu.GUI/Languages/dk.json index 448e4504..e435fcb3 100644 --- a/src/SharpEmu.GUI/Languages/dk.json +++ b/src/SharpEmu.GUI/Languages/dk.json @@ -168,5 +168,34 @@ "Updater.Status.Timeout": "Opdateringstjekket fik timeout efter 10 sekunder.", "Updater.Status.Failed": "Kunne ikke søge efter opdateringer.", "Updater.Status.ChecksumFailed": "Den downloadede opdatering bestod ikke SHA-256-verifikationen.", - "Updater.Status.Unsupported": "Automatisk opdatering kræver et x64-build til Windows, Linux eller macOS." + "Updater.Status.Unsupported": "Automatisk opdatering kræver et x64-build til Windows, Linux eller macOS.", + "Options.Graphics": "Grafik", + "Options.Section.Rendering": "GENGIVELSE", + "Options.Section.Display": "SKÆRM", + "Options.RenderResolution.Label": "Intern opløsning", + "Options.RenderResolution.Desc": "Render offscreen-mål under den oprindelige opløsning, og opskaler dem ved visning. Lavere værdier bytter billedkvalitet for GPU-kapacitet; træder i kraft ved næste start.", + "Options.RenderResolution.Native": "100 % (oprindelig)", + "Options.WindowMode.Label": "Vinduestilstand", + "Options.WindowMode.Desc": "Normalt vindue, kantløst skrivebord eller eksklusiv fuldskærm.", + "Options.WindowMode.Windowed": "Vindue", + "Options.WindowMode.Borderless": "Kantløs", + "Options.WindowMode.Exclusive": "Eksklusiv", + "Options.Resolution.Label": "Opløsning", + "Options.Resolution.Desc": "Oprindelig vinduesstørrelse eller opløsning i eksklusiv fuldskærm.", + "Options.Display.Label": "Skærm", + "Options.Display.Desc": "Skærm, der bruges til centrering og fuldskærm.", + "Options.RefreshRate.Label": "Opdateringshastighed", + "Options.RefreshRate.Desc": "Opdateringshastighed i eksklusiv fuldskærm. Automatisk vælger den nærmeste tilstand.", + "Options.RefreshRate.Automatic": "Automatisk", + "Options.Scaling.Label": "Skalering", + "Options.Scaling.Desc": "Skaler det oprindelige gæstebillede uden at ændre dets interne opløsning.", + "Options.Scaling.Fit": "Tilpas", + "Options.Scaling.Cover": "Udfyld", + "Options.Scaling.Stretch": "Stræk", + "Options.Scaling.Integer": "Heltal", + "Options.VSync.Label": "VSync", + "Options.VSync.Desc": "Brug FIFO-præsentation for output uden tearing.", + "Options.Hdr.Label": "HDR-output", + "Options.Hdr.Desc": "Brug HDR, når den valgte skærm og grafik-backend understøtter det. Automatisk falder tilbage til SDR.", + "Options.Hdr.Auto": "Automatisk" } diff --git a/src/SharpEmu.GUI/Languages/en.json b/src/SharpEmu.GUI/Languages/en.json index 2f160af5..416b24d9 100644 --- a/src/SharpEmu.GUI/Languages/en.json +++ b/src/SharpEmu.GUI/Languages/en.json @@ -41,11 +41,18 @@ "Options.Section.Emulation": "EMULATION", "Options.Section.Logging": "LOGGING", "Options.Section.Launcher": "LAUNCHER", + "Options.Section.Rendering": "RENDERING", "Options.Section.Display": "DISPLAY", "Options.Graphics": "Graphics", + "Options.RenderResolution.Label": "Internal resolution", + "Options.RenderResolution.Desc": "Render offscreen targets below native resolution and upscale on present. Lower values trade image quality for GPU headroom; takes effect on next launch.", + "Options.RenderResolution.Native": "100% (native)", "Options.WindowMode.Label": "Window mode", "Options.WindowMode.Desc": "Regular window, desktop borderless, or exclusive fullscreen.", + "Options.WindowMode.Windowed": "Windowed", + "Options.WindowMode.Borderless": "Borderless", + "Options.WindowMode.Exclusive": "Exclusive", "Options.Resolution.Label": "Resolution", "Options.Resolution.Desc": "Initial window size or exclusive fullscreen resolution.", "Options.Display.Label": "Display", @@ -55,10 +62,15 @@ "Options.RefreshRate.Automatic": "Automatic", "Options.Scaling.Label": "Scaling", "Options.Scaling.Desc": "Scale the native guest image without changing its internal resolution.", + "Options.Scaling.Fit": "Fit", + "Options.Scaling.Cover": "Cover", + "Options.Scaling.Stretch": "Stretch", + "Options.Scaling.Integer": "Integer", "Options.VSync.Label": "VSync", "Options.VSync.Desc": "Use FIFO presentation for tear-free output.", "Options.Hdr.Label": "HDR output", "Options.Hdr.Desc": "Use HDR when the selected display and graphics backend support it. Auto falls back to SDR.", + "Options.Hdr.Auto": "Auto", "Options.CpuEngine.Label": "CPU engine", "Options.CpuEngine.Desc": "Execution engine used to run game code.", diff --git a/src/SharpEmu.GUI/Languages/es.json b/src/SharpEmu.GUI/Languages/es.json index 573ac2db..e2d652d7 100644 --- a/src/SharpEmu.GUI/Languages/es.json +++ b/src/SharpEmu.GUI/Languages/es.json @@ -169,5 +169,34 @@ "Updater.Status.Timeout": "La comprobación de actualizaciones caducó tras 10 segundos.", "Updater.Status.Failed": "No se pudieron comprobar las actualizaciones.", "Updater.Status.ChecksumFailed": "La actualización descargada no superó la verificación SHA-256.", - "Updater.Status.Unsupported": "La actualización automática requiere un build x64 de Windows, Linux o macOS." + "Updater.Status.Unsupported": "La actualización automática requiere un build x64 de Windows, Linux o macOS.", + "Options.Graphics": "Gráficos", + "Options.Section.Rendering": "RENDERIZADO", + "Options.Section.Display": "PANTALLA", + "Options.RenderResolution.Label": "Resolución interna", + "Options.RenderResolution.Desc": "Renderiza objetivos fuera de pantalla por debajo de la resolución nativa y los reescala al presentar. Los valores inferiores sacrifican calidad de imagen para liberar carga de la GPU; se aplica en el próximo inicio.", + "Options.RenderResolution.Native": "100 % (nativa)", + "Options.WindowMode.Label": "Modo de ventana", + "Options.WindowMode.Desc": "Ventana normal, escritorio sin bordes o pantalla completa exclusiva.", + "Options.WindowMode.Windowed": "En ventana", + "Options.WindowMode.Borderless": "Sin bordes", + "Options.WindowMode.Exclusive": "Exclusiva", + "Options.Resolution.Label": "Resolución", + "Options.Resolution.Desc": "Tamaño inicial de la ventana o resolución de pantalla completa exclusiva.", + "Options.Display.Label": "Pantalla", + "Options.Display.Desc": "Monitor utilizado para centrar y mostrar a pantalla completa.", + "Options.RefreshRate.Label": "Frecuencia de actualización", + "Options.RefreshRate.Desc": "Frecuencia de actualización de la pantalla completa exclusiva. El modo automático selecciona el modo más cercano.", + "Options.RefreshRate.Automatic": "Automática", + "Options.Scaling.Label": "Escalado", + "Options.Scaling.Desc": "Escala la imagen nativa del sistema invitado sin cambiar su resolución interna.", + "Options.Scaling.Fit": "Ajustar", + "Options.Scaling.Cover": "Cubrir", + "Options.Scaling.Stretch": "Estirar", + "Options.Scaling.Integer": "Entero", + "Options.VSync.Label": "VSync", + "Options.VSync.Desc": "Usa presentación FIFO para evitar el desgarro de imagen.", + "Options.Hdr.Label": "Salida HDR", + "Options.Hdr.Desc": "Usa HDR cuando la pantalla seleccionada y el backend gráfico sean compatibles. El modo automático vuelve a SDR.", + "Options.Hdr.Auto": "Automático" } diff --git a/src/SharpEmu.GUI/Languages/fr.json b/src/SharpEmu.GUI/Languages/fr.json index b2f09911..81739dd2 100644 --- a/src/SharpEmu.GUI/Languages/fr.json +++ b/src/SharpEmu.GUI/Languages/fr.json @@ -169,5 +169,34 @@ "Updater.Status.Timeout": "La vérification des mises à jour a expiré après 10 secondes.", "Updater.Status.Failed": "Impossible de vérifier les mises à jour.", "Updater.Status.ChecksumFailed": "La mise à jour téléchargée a échoué à la vérification SHA-256.", - "Updater.Status.Unsupported": "La mise à jour automatique nécessite un build x64 pour Windows, Linux ou macOS." + "Updater.Status.Unsupported": "La mise à jour automatique nécessite un build x64 pour Windows, Linux ou macOS.", + "Options.Graphics": "Graphismes", + "Options.Section.Rendering": "RENDU", + "Options.Section.Display": "AFFICHAGE", + "Options.RenderResolution.Label": "Résolution interne", + "Options.RenderResolution.Desc": "Effectuer le rendu des cibles hors écran sous la résolution native et les mettre à l’échelle lors de l’affichage. Les valeurs inférieures réduisent la qualité d’image pour libérer des ressources GPU ; prend effet au prochain lancement.", + "Options.RenderResolution.Native": "100 % (native)", + "Options.WindowMode.Label": "Mode fenêtre", + "Options.WindowMode.Desc": "Fenêtre standard, bureau sans bordures ou plein écran exclusif.", + "Options.WindowMode.Windowed": "Fenêtré", + "Options.WindowMode.Borderless": "Sans bordures", + "Options.WindowMode.Exclusive": "Exclusif", + "Options.Resolution.Label": "Résolution", + "Options.Resolution.Desc": "Taille initiale de la fenêtre ou résolution du plein écran exclusif.", + "Options.Display.Label": "Écran", + "Options.Display.Desc": "Moniteur utilisé pour le centrage et le plein écran.", + "Options.RefreshRate.Label": "Fréquence de rafraîchissement", + "Options.RefreshRate.Desc": "Fréquence de rafraîchissement du plein écran exclusif. Le mode automatique sélectionne le mode le plus proche.", + "Options.RefreshRate.Automatic": "Automatique", + "Options.Scaling.Label": "Mise à l’échelle", + "Options.Scaling.Desc": "Mettre à l’échelle l’image native du système invité sans modifier sa résolution interne.", + "Options.Scaling.Fit": "Ajuster", + "Options.Scaling.Cover": "Remplir", + "Options.Scaling.Stretch": "Étirer", + "Options.Scaling.Integer": "Entier", + "Options.VSync.Label": "VSync", + "Options.VSync.Desc": "Utiliser la présentation FIFO pour un affichage sans déchirement.", + "Options.Hdr.Label": "Sortie HDR", + "Options.Hdr.Desc": "Utiliser le HDR lorsque l’écran sélectionné et le backend graphique le prennent en charge. Le mode automatique revient au SDR.", + "Options.Hdr.Auto": "Automatique" } diff --git a/src/SharpEmu.GUI/Languages/hu.json b/src/SharpEmu.GUI/Languages/hu.json index 4bd76e0c..1d014873 100644 --- a/src/SharpEmu.GUI/Languages/hu.json +++ b/src/SharpEmu.GUI/Languages/hu.json @@ -169,5 +169,34 @@ "Updater.Status.Timeout": "A frissítés-ellenőrzés 10 másodperc után túllépte az időkorlátot.", "Updater.Status.Failed": "Nem sikerült frissítéseket keresni.", "Updater.Status.ChecksumFailed": "A letöltött frissítés nem ment át az SHA-256-ellenőrzésen.", - "Updater.Status.Unsupported": "Az automatikus frissítéshez Windows, Linux vagy macOS x64 build szükséges." + "Updater.Status.Unsupported": "Az automatikus frissítéshez Windows, Linux vagy macOS x64 build szükséges.", + "Options.Graphics": "Grafika", + "Options.Section.Rendering": "RENDERELÉS", + "Options.Section.Display": "KIJELZŐ", + "Options.RenderResolution.Label": "Belső felbontás", + "Options.RenderResolution.Desc": "A képernyőn kívüli célok renderelése a natívnál kisebb felbontáson, majd felskálázás megjelenítéskor. Az alacsonyabb értékek képminőséget cserélnek GPU-tartalékra; a következő indításkor lép érvénybe.", + "Options.RenderResolution.Native": "100% (natív)", + "Options.WindowMode.Label": "Ablakmód", + "Options.WindowMode.Desc": "Normál ablak, keret nélküli asztal vagy kizárólagos teljes képernyő.", + "Options.WindowMode.Windowed": "Ablakos", + "Options.WindowMode.Borderless": "Keret nélküli", + "Options.WindowMode.Exclusive": "Kizárólagos", + "Options.Resolution.Label": "Felbontás", + "Options.Resolution.Desc": "Kezdeti ablakméret vagy kizárólagos teljes képernyős felbontás.", + "Options.Display.Label": "Kijelző", + "Options.Display.Desc": "A középre igazításhoz és teljes képernyőhöz használt monitor.", + "Options.RefreshRate.Label": "Frissítési gyakoriság", + "Options.RefreshRate.Desc": "A kizárólagos teljes képernyő frissítési gyakorisága. Az automatikus mód a legközelebbi módot választja.", + "Options.RefreshRate.Automatic": "Automatikus", + "Options.Scaling.Label": "Méretezés", + "Options.Scaling.Desc": "A natív vendégkép méretezése a belső felbontás módosítása nélkül.", + "Options.Scaling.Fit": "Illesztés", + "Options.Scaling.Cover": "Kitöltés", + "Options.Scaling.Stretch": "Nyújtás", + "Options.Scaling.Integer": "Egész szám", + "Options.VSync.Label": "VSync", + "Options.VSync.Desc": "FIFO megjelenítés használata képtörésmentes kimenethez.", + "Options.Hdr.Label": "HDR-kimenet", + "Options.Hdr.Desc": "HDR használata, ha a kiválasztott kijelző és grafikus backend támogatja. Az automatikus mód SDR-re vált vissza.", + "Options.Hdr.Auto": "Automatikus" } diff --git a/src/SharpEmu.GUI/Languages/it.json b/src/SharpEmu.GUI/Languages/it.json index f4661e96..d727aa1d 100644 --- a/src/SharpEmu.GUI/Languages/it.json +++ b/src/SharpEmu.GUI/Languages/it.json @@ -173,5 +173,34 @@ "Updater.Status.Timeout": "Il controllo degli aggiornamenti è scaduto dopo 10 secondi.", "Updater.Status.Failed": "Impossibile controllare gli aggiornamenti.", "Updater.Status.ChecksumFailed": "L'aggiornamento scaricato non ha superato la verifica SHA-256.", - "Updater.Status.Unsupported": "L'aggiornamento automatico richiede un build x64 per Windows, Linux o macOS." + "Updater.Status.Unsupported": "L'aggiornamento automatico richiede un build x64 per Windows, Linux o macOS.", + "Options.Graphics": "Grafica", + "Options.Section.Rendering": "RENDERING", + "Options.Section.Display": "SCHERMO", + "Options.RenderResolution.Label": "Risoluzione interna", + "Options.RenderResolution.Desc": "Renderizza i target fuori schermo sotto la risoluzione nativa e li ridimensiona in fase di presentazione. Valori inferiori sacrificano la qualità dell'immagine per lasciare margine alla GPU; ha effetto al prossimo avvio.", + "Options.RenderResolution.Native": "100% (nativa)", + "Options.WindowMode.Label": "Modalità finestra", + "Options.WindowMode.Desc": "Finestra normale, desktop senza bordi o schermo intero esclusivo.", + "Options.WindowMode.Windowed": "In finestra", + "Options.WindowMode.Borderless": "Senza bordi", + "Options.WindowMode.Exclusive": "Esclusiva", + "Options.Resolution.Label": "Risoluzione", + "Options.Resolution.Desc": "Dimensione iniziale della finestra o risoluzione dello schermo intero esclusivo.", + "Options.Display.Label": "Schermo", + "Options.Display.Desc": "Monitor utilizzato per il centraggio e lo schermo intero.", + "Options.RefreshRate.Label": "Frequenza di aggiornamento", + "Options.RefreshRate.Desc": "Frequenza di aggiornamento dello schermo intero esclusivo. La modalità automatica seleziona la modalità più vicina.", + "Options.RefreshRate.Automatic": "Automatica", + "Options.Scaling.Label": "Ridimensionamento", + "Options.Scaling.Desc": "Ridimensiona l'immagine nativa del sistema guest senza modificarne la risoluzione interna.", + "Options.Scaling.Fit": "Adatta", + "Options.Scaling.Cover": "Riempi", + "Options.Scaling.Stretch": "Estendi", + "Options.Scaling.Integer": "Intero", + "Options.VSync.Label": "VSync", + "Options.VSync.Desc": "Usa la presentazione FIFO per evitare lo screen tearing.", + "Options.Hdr.Label": "Output HDR", + "Options.Hdr.Desc": "Usa HDR quando lo schermo selezionato e il backend grafico lo supportano. La modalità automatica torna a SDR.", + "Options.Hdr.Auto": "Automatico" } diff --git a/src/SharpEmu.GUI/Languages/ja.json b/src/SharpEmu.GUI/Languages/ja.json index d383753a..94eb96e3 100644 --- a/src/SharpEmu.GUI/Languages/ja.json +++ b/src/SharpEmu.GUI/Languages/ja.json @@ -168,5 +168,34 @@ "Updater.Status.Timeout": "アップデートの確認が10秒でタイムアウトしました。", "Updater.Status.Failed": "アップデートを確認できませんでした。", "Updater.Status.ChecksumFailed": "ダウンロードしたアップデートはSHA-256検証に失敗しました。", - "Updater.Status.Unsupported": "自動アップデートにはWindows、Linux、またはmacOSのx64ビルドが必要です。" + "Updater.Status.Unsupported": "自動アップデートにはWindows、Linux、またはmacOSのx64ビルドが必要です。", + "Options.Graphics": "グラフィックス", + "Options.Section.Rendering": "レンダリング", + "Options.Section.Display": "ディスプレイ", + "Options.RenderResolution.Label": "内部解像度", + "Options.RenderResolution.Desc": "ネイティブ解像度より低い解像度でオフスクリーンターゲットを描画し、表示時にアップスケールします。値を下げると画質と引き換えにGPU負荷を軽減します。次回起動時に適用されます。", + "Options.RenderResolution.Native": "100%(ネイティブ)", + "Options.WindowMode.Label": "ウィンドウモード", + "Options.WindowMode.Desc": "通常ウィンドウ、デスクトップのボーダーレス、または排他フルスクリーン。", + "Options.WindowMode.Windowed": "ウィンドウ", + "Options.WindowMode.Borderless": "ボーダーレス", + "Options.WindowMode.Exclusive": "排他", + "Options.Resolution.Label": "解像度", + "Options.Resolution.Desc": "初期ウィンドウサイズまたは排他フルスクリーンの解像度。", + "Options.Display.Label": "ディスプレイ", + "Options.Display.Desc": "中央配置とフルスクリーンに使用するモニター。", + "Options.RefreshRate.Label": "リフレッシュレート", + "Options.RefreshRate.Desc": "排他フルスクリーンのリフレッシュレート。自動では最も近いモードを選択します。", + "Options.RefreshRate.Automatic": "自動", + "Options.Scaling.Label": "スケーリング", + "Options.Scaling.Desc": "内部解像度を変更せずにゲストのネイティブ画像を拡大縮小します。", + "Options.Scaling.Fit": "フィット", + "Options.Scaling.Cover": "カバー", + "Options.Scaling.Stretch": "引き伸ばし", + "Options.Scaling.Integer": "整数倍", + "Options.VSync.Label": "VSync", + "Options.VSync.Desc": "ティアリングのない表示のためFIFOプレゼンテーションを使用します。", + "Options.Hdr.Label": "HDR出力", + "Options.Hdr.Desc": "選択したディスプレイとグラフィックスバックエンドが対応している場合にHDRを使用します。自動ではSDRにフォールバックします。", + "Options.Hdr.Auto": "自動" } diff --git a/src/SharpEmu.GUI/Languages/ko.json b/src/SharpEmu.GUI/Languages/ko.json index 7b9851bd..12509ec1 100644 --- a/src/SharpEmu.GUI/Languages/ko.json +++ b/src/SharpEmu.GUI/Languages/ko.json @@ -168,5 +168,34 @@ "Updater.Status.Timeout": "업데이트 확인이 10초 후 시간 초과되었습니다.", "Updater.Status.Failed": "업데이트를 확인할 수 없습니다.", "Updater.Status.ChecksumFailed": "다운로드한 업데이트가 SHA-256 검증에 실패했습니다.", - "Updater.Status.Unsupported": "자동 업데이트에는 Windows, Linux 또는 macOS x64 빌드가 필요합니다." + "Updater.Status.Unsupported": "자동 업데이트에는 Windows, Linux 또는 macOS x64 빌드가 필요합니다.", + "Options.Graphics": "그래픽", + "Options.Section.Rendering": "렌더링", + "Options.Section.Display": "디스플레이", + "Options.RenderResolution.Label": "내부 해상도", + "Options.RenderResolution.Desc": "네이티브 해상도보다 낮은 해상도로 오프스크린 대상을 렌더링한 뒤 표시할 때 업스케일합니다. 값이 낮을수록 화질을 희생해 GPU 여유를 확보하며 다음 실행부터 적용됩니다.", + "Options.RenderResolution.Native": "100% (네이티브)", + "Options.WindowMode.Label": "창 모드", + "Options.WindowMode.Desc": "일반 창, 데스크톱 테두리 없음 또는 독점 전체 화면.", + "Options.WindowMode.Windowed": "창", + "Options.WindowMode.Borderless": "테두리 없음", + "Options.WindowMode.Exclusive": "독점", + "Options.Resolution.Label": "해상도", + "Options.Resolution.Desc": "초기 창 크기 또는 독점 전체 화면 해상도.", + "Options.Display.Label": "디스플레이", + "Options.Display.Desc": "가운데 배치와 전체 화면에 사용할 모니터.", + "Options.RefreshRate.Label": "새로 고침 빈도", + "Options.RefreshRate.Desc": "독점 전체 화면의 새로 고침 빈도입니다. 자동은 가장 가까운 모드를 선택합니다.", + "Options.RefreshRate.Automatic": "자동", + "Options.Scaling.Label": "스케일링", + "Options.Scaling.Desc": "내부 해상도를 변경하지 않고 게스트의 네이티브 이미지를 확대 또는 축소합니다.", + "Options.Scaling.Fit": "맞춤", + "Options.Scaling.Cover": "채우기", + "Options.Scaling.Stretch": "늘이기", + "Options.Scaling.Integer": "정수배", + "Options.VSync.Label": "VSync", + "Options.VSync.Desc": "티어링 없는 출력을 위해 FIFO 프레젠테이션을 사용합니다.", + "Options.Hdr.Label": "HDR 출력", + "Options.Hdr.Desc": "선택한 디스플레이와 그래픽 백엔드가 지원하는 경우 HDR을 사용합니다. 자동 모드는 SDR로 대체됩니다.", + "Options.Hdr.Auto": "자동" } diff --git a/src/SharpEmu.GUI/Languages/nl.json b/src/SharpEmu.GUI/Languages/nl.json index 3ce38bcb..b76352fb 100644 --- a/src/SharpEmu.GUI/Languages/nl.json +++ b/src/SharpEmu.GUI/Languages/nl.json @@ -168,5 +168,34 @@ "Updater.Status.Timeout": "De updatecontrole is na 10 seconden verlopen.", "Updater.Status.Failed": "Kon niet controleren op updates.", "Updater.Status.ChecksumFailed": "De gedownloade update is niet door de SHA-256-verificatie gekomen.", - "Updater.Status.Unsupported": "Automatisch updaten vereist een x64-build voor Windows, Linux of macOS." + "Updater.Status.Unsupported": "Automatisch updaten vereist een x64-build voor Windows, Linux of macOS.", + "Options.Graphics": "Grafisch", + "Options.Section.Rendering": "RENDERING", + "Options.Section.Display": "BEELDSCHERM", + "Options.RenderResolution.Label": "Interne resolutie", + "Options.RenderResolution.Desc": "Render offscreen-doelen onder de oorspronkelijke resolutie en schaal ze bij presentatie op. Lagere waarden ruilen beeldkwaliteit in voor GPU-marge; wordt bij de volgende start toegepast.", + "Options.RenderResolution.Native": "100% (native)", + "Options.WindowMode.Label": "Venstermodus", + "Options.WindowMode.Desc": "Normaal venster, randloos bureaublad of exclusief volledig scherm.", + "Options.WindowMode.Windowed": "Venster", + "Options.WindowMode.Borderless": "Randloos", + "Options.WindowMode.Exclusive": "Exclusief", + "Options.Resolution.Label": "Resolutie", + "Options.Resolution.Desc": "Initiële venstergrootte of resolutie voor exclusief volledig scherm.", + "Options.Display.Label": "Beeldscherm", + "Options.Display.Desc": "Monitor die wordt gebruikt voor centrering en volledig scherm.", + "Options.RefreshRate.Label": "Verversingssnelheid", + "Options.RefreshRate.Desc": "Verversingssnelheid voor exclusief volledig scherm. Automatisch selecteert de dichtstbijzijnde modus.", + "Options.RefreshRate.Automatic": "Automatisch", + "Options.Scaling.Label": "Schaling", + "Options.Scaling.Desc": "Schaal de oorspronkelijke gastafbeelding zonder de interne resolutie te wijzigen.", + "Options.Scaling.Fit": "Passend", + "Options.Scaling.Cover": "Vullend", + "Options.Scaling.Stretch": "Uitrekken", + "Options.Scaling.Integer": "Geheel getal", + "Options.VSync.Label": "VSync", + "Options.VSync.Desc": "Gebruik FIFO-presentatie voor uitvoer zonder tearing.", + "Options.Hdr.Label": "HDR-uitvoer", + "Options.Hdr.Desc": "Gebruik HDR wanneer het geselecteerde beeldscherm en de grafische backend dit ondersteunen. Automatisch valt terug op SDR.", + "Options.Hdr.Auto": "Automatisch" } diff --git a/src/SharpEmu.GUI/Languages/pt.json b/src/SharpEmu.GUI/Languages/pt.json index c45f0fcd..e3cabce4 100644 --- a/src/SharpEmu.GUI/Languages/pt.json +++ b/src/SharpEmu.GUI/Languages/pt.json @@ -169,5 +169,34 @@ "Updater.Status.Timeout": "A verificação de atualizações expirou após 10 segundos.", "Updater.Status.Failed": "Não foi possível procurar atualizações.", "Updater.Status.ChecksumFailed": "A atualização transferida falhou a verificação SHA-256.", - "Updater.Status.Unsupported": "A atualização automática requer um build x64 para Windows, Linux ou macOS." + "Updater.Status.Unsupported": "A atualização automática requer um build x64 para Windows, Linux ou macOS.", + "Options.Graphics": "Gráficos", + "Options.Section.Rendering": "RENDERIZAÇÃO", + "Options.Section.Display": "ECRÃ", + "Options.RenderResolution.Label": "Resolução interna", + "Options.RenderResolution.Desc": "Renderiza alvos fora do ecrã abaixo da resolução nativa e amplia-os na apresentação. Valores inferiores trocam qualidade de imagem por margem da GPU; entra em vigor no próximo arranque.", + "Options.RenderResolution.Native": "100% (nativa)", + "Options.WindowMode.Label": "Modo de janela", + "Options.WindowMode.Desc": "Janela normal, ambiente de trabalho sem margens ou ecrã inteiro exclusivo.", + "Options.WindowMode.Windowed": "Em janela", + "Options.WindowMode.Borderless": "Sem margens", + "Options.WindowMode.Exclusive": "Exclusivo", + "Options.Resolution.Label": "Resolução", + "Options.Resolution.Desc": "Tamanho inicial da janela ou resolução de ecrã inteiro exclusivo.", + "Options.Display.Label": "Ecrã", + "Options.Display.Desc": "Monitor utilizado para centrar e apresentar em ecrã inteiro.", + "Options.RefreshRate.Label": "Taxa de atualização", + "Options.RefreshRate.Desc": "Taxa de atualização do ecrã inteiro exclusivo. O modo automático seleciona o modo mais próximo.", + "Options.RefreshRate.Automatic": "Automática", + "Options.Scaling.Label": "Escala", + "Options.Scaling.Desc": "Dimensiona a imagem nativa do sistema convidado sem alterar a respetiva resolução interna.", + "Options.Scaling.Fit": "Ajustar", + "Options.Scaling.Cover": "Preencher", + "Options.Scaling.Stretch": "Esticar", + "Options.Scaling.Integer": "Inteira", + "Options.VSync.Label": "VSync", + "Options.VSync.Desc": "Utiliza apresentação FIFO para evitar cortes na imagem.", + "Options.Hdr.Label": "Saída HDR", + "Options.Hdr.Desc": "Utiliza HDR quando o ecrã selecionado e o backend gráfico o suportam. O modo automático regressa a SDR.", + "Options.Hdr.Auto": "Automático" } diff --git a/src/SharpEmu.GUI/Languages/ru.json b/src/SharpEmu.GUI/Languages/ru.json index abce73a3..6239569b 100644 --- a/src/SharpEmu.GUI/Languages/ru.json +++ b/src/SharpEmu.GUI/Languages/ru.json @@ -41,6 +41,36 @@ "Options.Section.Emulation": "ЭМУЛЯЦИЯ", "Options.Section.Logging": "ЛОГГИРОВАНИЕ", "Options.Section.Launcher": "ЛАУНЧЕР", + "Options.Section.Rendering": "РЕНДЕРИНГ", + "Options.Section.Display": "ЭКРАН", + "Options.Graphics": "Графика", + + "Options.RenderResolution.Label": "Внутреннее разрешение", + "Options.RenderResolution.Desc": "Рендерить внеэкранные буферы ниже нативного разрешения и масштабировать при выводе. Меньшие значения снижают качество изображения, но уменьшают нагрузку на GPU; применяется при следующем запуске.", + "Options.RenderResolution.Native": "100% (нативное)", + "Options.WindowMode.Label": "Режим окна", + "Options.WindowMode.Desc": "Обычное окно, безрамочный режим рабочего стола или эксклюзивный полноэкранный режим.", + "Options.WindowMode.Windowed": "Оконный", + "Options.WindowMode.Borderless": "Без рамки", + "Options.WindowMode.Exclusive": "Эксклюзивный", + "Options.Resolution.Label": "Разрешение", + "Options.Resolution.Desc": "Начальный размер окна или разрешение эксклюзивного полноэкранного режима.", + "Options.Display.Label": "Монитор", + "Options.Display.Desc": "Монитор, используемый для центрирования окна и полноэкранного режима.", + "Options.RefreshRate.Label": "Частота обновления", + "Options.RefreshRate.Desc": "Частота обновления эксклюзивного полноэкранного режима. Автоматический режим выбирает ближайшее значение.", + "Options.RefreshRate.Automatic": "Автоматически", + "Options.Scaling.Label": "Масштабирование", + "Options.Scaling.Desc": "Масштабировать нативное изображение игры без изменения внутреннего разрешения.", + "Options.Scaling.Fit": "Вписать", + "Options.Scaling.Cover": "Заполнить", + "Options.Scaling.Stretch": "Растянуть", + "Options.Scaling.Integer": "Целочисленное", + "Options.VSync.Label": "VSync", + "Options.VSync.Desc": "Использовать режим представления FIFO для вывода без разрывов изображения.", + "Options.Hdr.Label": "HDR-вывод", + "Options.Hdr.Desc": "Использовать HDR, если выбранный монитор и графический бэкенд его поддерживают. Автоматический режим при необходимости переключается на SDR.", + "Options.Hdr.Auto": "Авто", "Options.CpuEngine.Label": "Движок ЦП", "Options.CpuEngine.Desc": "Движок выполнения, используемый для запуска игрового кода.", @@ -51,12 +81,12 @@ "Options.LogLevel.Label": "Уровень логгирования", "Options.LogLevel.Desc": "Подробность вывода в консоль эмулятора.", - "Options.LogLevel.Trace": "Trace", - "Options.LogLevel.Debug": "Debug", - "Options.LogLevel.Info": "Info", - "Options.LogLevel.Warning": "Warning", - "Options.LogLevel.Error": "Error", - "Options.LogLevel.Critical": "Critical", + "Options.LogLevel.Trace": "Трассировка", + "Options.LogLevel.Debug": "Отладка", + "Options.LogLevel.Info": "Информация", + "Options.LogLevel.Warning": "Предупреждение", + "Options.LogLevel.Error": "Ошибка", + "Options.LogLevel.Critical": "Критический", "Options.TraceImports.Label": "Лимит трассировки импортов", "Options.TraceImports.Desc": "Трассировать первые N импортов в каждом модуле (0 - выключено).", @@ -87,6 +117,8 @@ "PerGame.Title": "Настройки игры — {0} ({1})", "PerGame.InheritNote": "Неотмеченные строки наследуют глобальные настройки.", + "PerGame.Tab.General": "Основные", + "PerGame.Tab.Graphics": "Графика", "PerGame.EnvToggles.Label": "Переключатели окружения", "PerGame.EnvToggles.Desc": "Переопределить глобальный набор переключателей SHARPEMU_* для этой игры.", diff --git a/src/SharpEmu.GUI/Languages/tr.json b/src/SharpEmu.GUI/Languages/tr.json index 3797d376..98efd7a8 100644 --- a/src/SharpEmu.GUI/Languages/tr.json +++ b/src/SharpEmu.GUI/Languages/tr.json @@ -189,5 +189,17 @@ "About.Discord.Label": "Discord", "About.Discord.Desc": "Topluluğa katılın, destek alın ve geliştirmeyi takip edin.", "About.GithubButton": "GitHub'da katkıda bulun!", - "About.DiscordButton": "Discord'umuza katıl!" + "About.DiscordButton": "Discord'umuza katıl!", + "Options.Section.Rendering": "GÖRÜNTÜ İŞLEME", + "Options.RenderResolution.Label": "Dahili çözünürlük", + "Options.RenderResolution.Desc": "Ekran dışı hedefleri doğal çözünürlüğün altında işle ve sunum sırasında ölçeklendir. Daha düşük değerler GPU payı karşılığında görüntü kalitesini azaltır; bir sonraki başlatmada etkili olur.", + "Options.RenderResolution.Native": "%100 (doğal)", + "Options.WindowMode.Windowed": "Pencereli", + "Options.WindowMode.Borderless": "Kenarlıksız", + "Options.WindowMode.Exclusive": "Özel", + "Options.Scaling.Fit": "Sığdır", + "Options.Scaling.Cover": "Kapla", + "Options.Scaling.Stretch": "Uzat", + "Options.Scaling.Integer": "Tam sayı", + "Options.Hdr.Auto": "Otomatik" } diff --git a/src/SharpEmu.GUI/Localization.cs b/src/SharpEmu.GUI/Localization.cs index 4db23b14..1e37aa64 100644 --- a/src/SharpEmu.GUI/Localization.cs +++ b/src/SharpEmu.GUI/Localization.cs @@ -1,6 +1,8 @@ // Copyright (C) 2026 SharpEmu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +using System.ComponentModel; +using System.Runtime.CompilerServices; using System.Text.Json; namespace SharpEmu.GUI; @@ -14,25 +16,50 @@ public sealed record LanguageInfo(string Code, string NativeName); /// executable overrides the embedded copy for that code, so a translation /// fix or a brand-new language never needs a rebuild. /// -public sealed class Localization +public sealed class Localization : INotifyPropertyChanged { public static Localization Instance { get; } = new(); private const string EmbeddedResourcePrefix = "Languages."; private const string EmbeddedResourceSuffix = ".json"; + private const string IndexerPropertyName = "Item"; + private readonly string _languagesDirectory; private Dictionary _strings = new(); private Dictionary _fallbackStrings = new(); + private string _currentCode = "en"; - - private Localization() + private Localization() : this(LanguagesDirectory) { } + internal Localization(string languagesDirectory) + { + _languagesDirectory = languagesDirectory; + } + /// Directory holding optional *.json language overrides, next to the executable. public static string LanguagesDirectory => Path.Combine(AppContext.BaseDirectory, "Languages"); - public string CurrentCode { get; private set; } = "en"; + public event PropertyChangedEventHandler? PropertyChanged; + + /// Exposes localized strings to XAML bindings by key. + public string this[string key] => Get(key); + + public string CurrentCode + { + get => _currentCode; + private set + { + if (_currentCode == value) + { + return; + } + + _currentCode = value; + OnPropertyChanged(); + } + } public string Get(string key) { @@ -67,7 +94,7 @@ public sealed class Localization try { - foreach (var file in Directory.EnumerateFiles(LanguagesDirectory, "*.json")) + foreach (var file in Directory.EnumerateFiles(_languagesDirectory, "*.json")) { var code = Path.GetFileNameWithoutExtension(file); using var stream = File.OpenRead(file); @@ -84,47 +111,36 @@ public sealed class Localization return result; } - /// Loads a language by code (e.g. "en"): a loose override file first, then the embedded copy. - /// english is the fallback language + /// + /// Loads a language by code. Loose files overlay the embedded language, + /// while English supplies values missing from the selected language. + /// public void Load(string code) { - if (_fallbackStrings.Count == 0 && !string.Equals(code, "en", StringComparison.OrdinalIgnoreCase)) + _fallbackStrings = LoadMergedLanguage("en"); + _strings = string.Equals(code, "en", StringComparison.OrdinalIgnoreCase) + ? _fallbackStrings + : LoadMergedLanguage(code); + + CurrentCode = code; + OnPropertyChanged(IndexerPropertyName); + } + + private Dictionary LoadMergedLanguage(string code) + { + var merged = TryLoadEmbedded(code, out var embedded) + ? embedded + : new Dictionary(); + + if (TryLoadLooseFile(code, out var loose)) { - if (!TryLoadLooseFile("en", out var fallback) && !TryLoadEmbedded("en", out fallback)) + foreach (var (key, value) in loose) { - fallback = new Dictionary(); + merged[key] = value; } - _fallbackStrings = fallback; - } - else if (string.Equals(code, "en", StringComparison.OrdinalIgnoreCase)) - { - if (TryLoadLooseFile("en", out var enDict) || TryLoadEmbedded("en", out enDict)) - { - _strings = enDict; - _fallbackStrings = enDict; - } - else - { - _strings = new Dictionary(); - _fallbackStrings = new Dictionary(); - } - CurrentCode = "en"; - return; } - // Load the requested language - if (TryLoadLooseFile(code, out var loaded) || TryLoadEmbedded(code, out loaded)) - { - _strings = loaded; - } - else - { - if (_fallbackStrings.Count > 0) - _strings = new Dictionary(_fallbackStrings); - else - _strings = new Dictionary(); - } - CurrentCode = code; + return merged; } private static IEnumerable EmbeddedLanguageCodes() @@ -161,44 +177,12 @@ public sealed class Localization return null; } - private bool TryLoadLooseFile(string code) - { - try - { - var path = Path.Combine(LanguagesDirectory, $"{code}.json"); - return File.Exists(path) && TryLoad(code, File.ReadAllText(path)); - } - catch (Exception) - { - return false; - } - } - - private bool TryLoadEmbedded(string code) - { - try - { - using var stream = OpenEmbeddedLanguageStream(code); - if (stream is null) - { - return false; - } - - using var reader = new StreamReader(stream); - return TryLoad(code, reader.ReadToEnd()); - } - catch (Exception) - { - return false; - } - } - private bool TryLoadLooseFile(string code, out Dictionary result) { result = new Dictionary(); try { - var path = Path.Combine(LanguagesDirectory, $"{code}.json"); + var path = Path.Combine(_languagesDirectory, $"{code}.json"); if (!File.Exists(path)) return false; @@ -243,14 +227,6 @@ public sealed class Localization return true; } - private bool TryLoad(string code, string json) - { - if (TryLoad(json, out var dict)) - { - _strings = dict; - CurrentCode = code; - return true; - } - return false; - } -} \ No newline at end of file + private void OnPropertyChanged([CallerMemberName] string? propertyName = null) + => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); +} diff --git a/src/SharpEmu.GUI/LocalizedChoice.cs b/src/SharpEmu.GUI/LocalizedChoice.cs new file mode 100644 index 00000000..e01a6d65 --- /dev/null +++ b/src/SharpEmu.GUI/LocalizedChoice.cs @@ -0,0 +1,61 @@ +// Copyright (C) 2026 SharpEmu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace SharpEmu.GUI; + +/// +/// A stable settings value with a display label that can be refreshed when +/// the active UI language changes. +/// +public sealed class LocalizedChoice : INotifyPropertyChanged +{ + private string _label; + + private LocalizedChoice(string value, string label, string? localizationKey) + { + Value = value; + _label = label; + LocalizationKey = localizationKey; + } + + public string Value { get; } + + public string Label + { + get => _label; + private set + { + if (_label == value) + { + return; + } + + _label = value; + OnPropertyChanged(); + } + } + + private string? LocalizationKey { get; } + + public event PropertyChangedEventHandler? PropertyChanged; + + public static LocalizedChoice FromKey(string value, string localizationKey) => + new(value, localizationKey, localizationKey); + + public static LocalizedChoice Literal(string value, string label) => + new(value, label, null); + + public void Refresh(Localization localization) + { + if (LocalizationKey is { } key) + { + Label = localization.Get(key); + } + } + + private void OnPropertyChanged([CallerMemberName] string? propertyName = null) => + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); +} diff --git a/src/SharpEmu.GUI/MainWindow.axaml b/src/SharpEmu.GUI/MainWindow.axaml index 41721d50..06bfbb5e 100644 --- a/src/SharpEmu.GUI/MainWindow.axaml +++ b/src/SharpEmu.GUI/MainWindow.axaml @@ -18,6 +18,14 @@ SPDX-License-Identifier: GPL-2.0-or-later Icon="avares://SharpEmu.GUI/Assets/SharpEmu.ico" KeyDown="OnKeyDown"> + + + + + + - + - + - - - - + + - - + @@ -242,43 +280,49 @@ SPDX-License-Identifier: GPL-2.0-or-later - + - - - - - - - - - + + - + - - + - -