From ce096fd6225e68f432356130a3ba01089b47a377 Mon Sep 17 00:00:00 2001 From: mh2n <112729612+mh2n@users.noreply.github.com> Date: Tue, 22 Sep 2026 22:04:12 +0100 Subject: [PATCH 1/4] i18n: add Arabic (ar) locale support --- package.json | 3 + src/i18n-ar.ts | 988 +++++++++++++++++++++++++++++++++++ src/i18n-de.ts | 1 + src/i18n-es.ts | 1 + src/i18n-fr.ts | 1 + src/i18n-ja.ts | 1 + src/i18n-ko.ts | 1 + src/i18n-pt.ts | 1 + src/i18n-ru.ts | 1 + src/i18n-vi.ts | 1 + src/i18n-zh.ts | 1 + src/i18n.ts | 3 + src/interface-preferences.ts | 3 +- 13 files changed, 1005 insertions(+), 1 deletion(-) create mode 100644 src/i18n-ar.ts diff --git a/package.json b/package.json index af1f5762..fdc8da6b 100644 --- a/package.json +++ b/package.json @@ -20,5 +20,8 @@ "devDependencies": { "typescript": "^5.8.3", "vite": "^6.3.5" + }, + "allowScripts": { + "esbuild@0.25.12": true } } diff --git a/src/i18n-ar.ts b/src/i18n-ar.ts new file mode 100644 index 00000000..2f05615d --- /dev/null +++ b/src/i18n-ar.ts @@ -0,0 +1,988 @@ +import type { I18nKey } from "./i18n.ts"; + +/** French strings, split into a lazy chunk so the initial bundle ships + English only. Loaded via ensureLocale() before first use. */ +export const ar: Record = { + "nav.language": "Langue", + "nav.settings": "Paramètres", + "nav.support": "Soutenir", + "nav.supportProject": "Soutenir le projet", + "nav.mouseCheck": "Tester la souris", + "nav.home": "Accueil", + "nav.dashboard": "Config. souris", + "nav.feedback": "Feedback", + "nav.docs": "Documentation", + "nav.supported": "Appareils compatibles", + "nav.whatsNew": "Nouveautés", + "nav.expand": "Développer la barre latérale", + "nav.collapse": "Réduire la barre latérale", + "side.selectedDevice": "APPAREIL SÉLECTIONNÉ", + "side.connectedMouse": "Souris connectée", + "side.connected": "Connectée", + "side.connectedDevices": "APPAREILS CONNECTÉS", + "bridge.title": "OpenMouse Bridge", + "bridge.connected": "Connecté", + "bridge.games": "JEUX", + "bridge.profileEnabled": "Application automatique activée", + "bridge.profileEnabledDetail": "Bridge enverra ce profil à votre souris dès que {name} sera lancé.", + "bridge.profileUpdated": "Profil mis à jour", + "bridge.profileUpdatedDetail": "Bridge appliquera les nouveaux réglages la prochaine fois que {name} sera au premier plan.", + "bridge.profileDisabled": "Application automatique désactivée", + "bridge.profileDisabledDetail": "{name} ne recevra plus ce profil automatiquement.", + "bridge.profileSaveFailed": "Impossible de joindre OpenMouse Bridge", + "bridge.profileSaveFailedDetail": "Vérifiez que Bridge est toujours lancé, puis réessayez.", + "bridge.profileAppliedHere": "Profil de jeu appliqué", + "bridge.profileRestored": "Anciens réglages de la souris restaurés", + "panel.overline": "CONTRÔLE DE L'APPAREIL", + "panel.connectMouse": "Connectez une souris", + "panel.shareProfile": "Partager le profil", + "panel.deviceSections": "Sections de l'appareil", + "empty.previewsTitle": "Aperçus des drivers", + "empty.title": "Connectez votre appareil.", + "empty.previewsBody": "Affichez n'importe quel driver compatible sans son matériel :", + "empty.body": "Choisissez votre souris dans la fenêtre du navigateur pour ajuster ses réglages intégrés.", + "tab.overview": "Aperçu", + "tab.performance": "Performance", + "tab.buttons": "Boutons", + "tab.profiles": "Profils", + "tab.advanced": "Avancé", + "tab.lighting": "Éclairage", + "ov.battery": "BATTERIE", + "ov.firmware": "FIRMWARE", + "ov.fwSingle": "Firmware signalé par la souris", + "ov.fwNone": "Non signalé", + "ov.connection": "CONNEXION", + "ov.connReceiver": "Récepteur 2,4 GHz", + "ov.conn24": "2,4 GHz", + "ov.profile": "Profil", + "ov.led": "LED du récepteur", + "ov.on": "Activé", + "ov.off": "Désactivé", + "test.title": "Test de Taux de Polling de la Souris", + "test.subtitle": "Déplacez votre souris en petits cercles pour mesurer son taux de polling réel.", + "test.movePrompt": "Déplacez votre souris ici pour détecter le mouvement", + "test.ready": "Prêt", + "test.getReady": "Préparez-vous…", + "test.sampling": "Mesure en cours…", + "test.areaNote": "Gardez la souris en mouvement régulier pendant le compte à rebours et la mesure.", + "test.complete": "Test terminé", + "test.start": "Démarrer le test", + "test.reset": "Réinitialiser", + "test.avgHz": "Moyenne", + "test.peakHz": "Pic", + "test.low5": "5 % les plus bas", + "test.stability": "Stabilité", + "test.jitter": "Gigue", + "test.dropouts": "Décrochages", + "test.events": "Événements", + "test.avgInterval": "Intervalle moyen", + "test.deviceInfo": "INFOS APPAREIL", + "test.deviceName": "Appareil", + "test.connection": "Connexion", + "test.reportedHz": "Taux de polling signalé", + "test.dpi": "DPI", + "test.dpiStages": "Étapes DPI", + "test.battery": "Batterie", + "test.firmware": "Firmware", + "test.noDevice": "Aucun appareil connecté. Testez votre taux de polling quand même ou ouvrez la Config de souris pour connecter.", + "test.buttonTest": "TEST DES BOUTONS", + "test.buttonHint": "Cliquez sur n'importe quel bouton de la souris pour le voir s'allumer ici.", + "test.btn.left": "Gauche", + "test.btn.right": "Droit", + "test.btn.middle": "Milieu", + "test.btn.back": "Retour", + "test.btn.forward": "Avant", + "set.title": "Paramètres", + "set.back": "Retour à l'appareil", + "set.soundTitle": "Son", + "set.soundDescription": "Activez des sons comme des clics de souris et de nouvelles connexions", + "set.profiles": "PROFILS", + "set.profileKey": "Clé de profil", + "set.profileKeyBody": "Une clé à copier-coller qui transfère les réglages de cette souris vers une autre unité du même modèle. Collez-la dans les Paramètres là-bas pour charger la même configuration.", + "set.yourKey": "Votre clé", + "set.noKey": "Connectez une souris pour générer une clé.", + "set.copyKey": "Copier la clé", + "set.copied": "Copié", + "set.importKey": "Importer une clé", + "set.importPlaceholder": "Collez ici une clé de profil…", + "set.import": "Importer", + "set.importNote": "Les réglages importés sont préparés comme n'importe quelle autre modification — rien n'est écrit tant que vous ne les gravez pas.", + "set.appearance": "APPARENCE", + "set.accentTheme": "Thème d'accent", + "set.accentBody": "Chaque tuile est peinte dans son propre thème.", + "set.glass": "VERRE LIQUIDE", + "set.glassTitle": "Intensité du verre", + "set.glassBody": "Ajustez le matériau givré, des panneaux entièrement transparents à la finition acrylique complète.", + "set.transparent": "Transparent", + "set.acrylic": "Acrylique", + "set.language": "LANGUE", + "set.languageTitle": "Langue", + "set.languageBody": "Choisissez la langue de l'interface. Les messages de l'appareil restent en anglais pour l'instant.", + "set.english": "English", + "set.portuguese": "Português", + "set.spanish": "Español", + "set.french": "Français", + "set.german": "Deutsch", + "set.chinese": "中文", + "set.japanese": "日本語", + "set.korean": "한국어", + "set.russian": "Русский", + "set.vietnamese": "Tiếng Việt", + "set.arabic" : "العربيّة", + "set.motion": "MOUVEMENT", + "set.animations": "Animations", + "set.animationsBody": "Active les transitions de l'interface et les changements d'état animés.", + "set.enableAnimations": "Activer les animations", + "set.writes": "ÉCRITURES", + "set.instantFlash": "Gravure instantanée", + "set.instantFlashBody": "Écrit chaque modification sur la souris dès que vous la faites, au lieu de la préparer pour la barre de gravure.", + "set.flashImmediately": "Graver immédiatement", + "set.sections": "SECTIONS", + "set.advancedEditors": "Éditeurs avancés", + "set.advancedEditorsBody": "Choisissez si les sections CPI, mappage des boutons et expérimentales commencent développées.", + "set.expandByDefault": "Développer par défaut", + "set.experimental": "EXPÉRIMENTAL", + "set.experimentalTitle": "Contrôles expérimentaux", + "set.experimentalBody": "Affiche ou masque complètement les contrôles qui peuvent varier selon les versions de firmware.", + "set.showExperimental": "Afficher les réglages expérimentaux", + "set.dev": "DÉVELOPPEMENT", + "set.previewsTitle": "Aperçus des drivers", + "set.previewsBody": "Affiche n'importe quel driver compatible sans son matériel, pour vérifier une modification sur chaque marque. Rien n'est écrit sur un appareil.", + "set.reset": "Réinitialiser les préférences d'interface", + "set.supportTitle": "Soutenir le projet", + "set.supportBody": "OpenMouse est gratuit et open source. Rejoignez la communauté, suivez le projet ou soutenez le travail qui le rend possible.", + "pend.region": "Modifications non enregistrées", + "pend.overline": "EN ATTENTE", + "pend.none": "Aucune modification en attente", + "pend.one": "1 modification non enregistrée", + "pend.many": "modifications non enregistrées", + "pend.idleHint": "Ajustez un réglage pour le prévisualiser avant de l'écrire.", + "pend.revert": "Annuler", + "pend.applying": "Application…", + "pend.apply": "Appliquer les modifications", + "toast.region": "Notifications", + "toast.dismiss": "Ignorer la notification", + "bat.needsCharging": "Besoin de charge", + "bat.full": "Complètement chargée", + "bat.untilFull": "avant charge complète", + "bat.remaining": "restant", + "bat.charging": "En charge", + "bat.chargingSlowly": "Charge lente", + "bat.almostFull": "Presque pleine", + "bat.fullState": "Pleine", + "bat.discharging": "En décharge", + "bat.unknown": "Inconnu", + "fb.title": "Envoyer un retour", + "fb.description": "Partagez un rapport de bug, une demande de fonctionnalité ou toute autre note. Le retour est envoyé de façon anonyme : rien n'est joint sauf si vous l'activez ci-dessous.", + "fb.placeholder": "Écrivez votre retour ici…", + "fb.handleLabel": "Pseudo Discord (facultatif)", + "fb.handlePlaceholder": "username", + "fb.attachLabel": "Joindre les détails de l'appareil et le journal de diagnostic", + "fb.attachDetail": "Ajoute les informations de votre appareil et le trafic WebHID récent pour que nous puissions déboguer plus vite.", + "fb.send": "Envoyer le retour", + "fb.sent": "Retour envoyé", + "fb.sentDetail": "Merci — votre note a été livrée.", + "fb.error": "Impossible d'envoyer le retour", + "fb.errorDetail": "Vérifiez votre connexion et réessayez.", + "fb.cooldown": "Vous pourrez renvoyer un retour dans {seconds}s.", + "fb.limit": "Vous avez atteint la limite de retours pour le moment. Réessayez plus tard.", + "artreq.request": "Proposer une visuelle", + "artreq.title": "Proposer une visuelle", + "artreq.description": "La visuelle de cet appareil est manquante ? Envoyez un découpage vu de dessus et nous le vérifierons. Rien n'est publié directement : votre image part à notre équipe pour validation.", + "artreq.deviceLabel": "Appareil", + "artreq.drop": "Glissez votre visuelle ici ou cliquez pour sélectionner", + "artreq.hint": "PNG/WebP · fond transparent ou blanc pur · rendu de dessus du périphérique uniquement · 5 Mo max", + "artreq.noteLabel": "Note (facultatif)", + "artreq.notePlaceholder": "Lien source, page produit ou toute info utile à la vérification…", + "artreq.send": "Envoyer la demande", + "artreq.sent": "Demande de visuelle envoyée", + "artreq.sentDetail": "Notre équipe la vérifiera et publiera la visuelle une fois validée.", + "artreq.error": "Impossible d'envoyer la demande", + "artreq.errorDetail": "Vérifiez votre connexion et réessayez.", + "artreq.sizeError": "L'image est trop lourde. 5 Mo max.", + "artreq.typeError": "Choisissez une image PNG ou WebP.", + "artreq.screened": "Les envois sont automatiquement contrôlés pour détecter tout contenu inapproprié.", + "artreq.rejected": "Cette image ne peut pas être envoyée.", + "artreq.rejectedInvalid": "Ce fichier n'est pas une image PNG ou WebP valide.", + "artreq.rejectedNsfw": "Contenu inapproprié détecté (NSFW).", + "artreq.rejectedHate": "Contenu haineux ou abusif détecté.", + "artreq.rejectedGore": "Contenu graphique ou violent détecté.", + "artreq.rejectedJunk": "Cela ne ressemble pas à un visuel d'appareil. Envoyez un découpage du produit vu du dessus.", + "artreq.rejectedNotArtwork": "Ce n'est pas un visuel de souris — envoyez un rendu/découpe du périphérique vu de dessus, sans rien d'autre dans le cadre.", + "artreq.rejectedPhoto": "Cela ressemble à une photo, pas à un rendu — seuls les rendus ou découpes numériques vus de dessus sont acceptés.", + "artreq.rejectedBackground": "L'arrière-plan doit être transparent ou blanc pur — pas de scène, de bureau, de dégradé ni d'ombre.", + "artreq.rejectedUnconfirmed": "La vérification IA n'a pas pu confirmer qu'il s'agit d'un visuel d'appareil valide.", + "artreq.rejectedUnscreened": "La vérification automatique n'est pas disponible pour le moment. Veuillez réessayer plus tard.", + "artreq.lockedTitle": "Trop d'envois rejetés.", + "artreq.lockedBody": "Votre image ne respecte pas les règles du visuel et les envois sont temporairement bloqués. Réessayez dans {minutes} minutes ou ouvrez un ticket manuel sur Discord.", + "artreq.lockedDiscord": "Ouvrir un ticket manuel sur Discord", + "wn.title": "Application de bureau OpenMouse", + "wn.body": "Désormais disponible en alpha : l'application de bureau OpenMouse. Utilisez OpenMouse comme une app installable — sans garder un onglet de navigateur ouvert. Elle inclut l'accès HID natif, des profils de jeu et une interface unifiée sur le web et le bureau. Rendez-vous sur notre page de versions pour la télécharger pour votre plateforme.", + "wn.download": "Télécharger pour le bureau", + "wn.close": "Peut-être plus tard", + "ai.title": "OpenMouse AI", + "ai.subtitle": "Réponses rapides et dépannage", + "ai.greeting": "Salut ! Je suis OpenMouse AI. Choisis un sujet ci-dessous et je t'aiderai à le résoudre.", + "ai.topic1": "Ma souris ne se connecte pas", + "ai.topic1Ans": "Assure-toi que ta souris est branchée (ou que son récepteur est en place) et allumée. Essaie un autre port USB ou une connexion filaire si ta souris le permet. Sous Linux, vérifie que les nœuds de périphériques HID sont lisibles — le README liste les règles udev. Puis appuie sur Connecter et choisis ton périphérique dans l'invite du navigateur.", + "ai.topic2": "Le DPI ou la fréquence d'interrogation ne change pas", + "ai.topic2Ans": "Certaines souris n'acceptent que des valeurs prédéfinies, donc essaie un préréglage si une valeur personnalisée est refusée. Appuie sur Appliquer et laisse l'écriture se terminer avant de toucher autre chose. Si la valeur revient toujours en arrière, ce réglage n'est peut-être pas encore inscriptible sur ta souris.", + "ai.topic3": "L'application ne s'ouvre pas dans mon navigateur", + "ai.topic3Ans": "OpenMouse nécessite WebHID, donc il fonctionne dans Chrome, Edge et autres navigateurs basés sur Chromium. Firefox et Safari ne prennent pas encore en charge WebHID, l'application ne s'y ouvrira donc pas. Essaie la dernière version de Chrome ou Edge.", + "ai.topic4": "Mes paramètres ne sont pas enregistrés", + "ai.topic4Ans": "Les paramètres sont écrits dans le profil stocké de la souris et appliqués sur l'appareil, pas dans le cloud. Après avoir modifié un réglage, appuie sur Appliquer et garde la page ouverte jusqu'à la fin de l'écriture. Si cela revient encore après un redémarrage, ce réglage est peut-être en lecture seule sur ton modèle.", + "ai.other": "Autre chose", + "ai.otherAns": "Pas de souci — passe sur le Discord d'OpenMouse et la communauté t'aidera.", + "ai.joinDiscord": "Rejoindre le Discord", + "conn.add": "Ajouter un appareil", + "conn.addMouse": "Ajouter une souris", + "conn.connecting": "Connexion…", + "conn.preview": "Mode aperçu", + "common.apply": "Appliquer", + "common.custom": "Personnalisé", + "common.current": "Actuel {v}", + "common.staged": "Préparé {v}", + "common.active": "Actif", + "common.close": "Fermer", + "common.back": "Retour", + "common.cancel": "Annuler", + "common.done": "Terminé", + "common.save": "Enregistrer", + "common.on": "Activé", + "common.off": "Désactivé", + "dpi.sensitivity": "Sensibilité", + "dpi.perProfile": "Par profil", + "dpi.value": "Valeur DPI", + "dpi.presets": "Valeurs DPI courantes", + "dpi.presetsInUse": "Préréglages utilisés", + "dpi.slotsInUse": "Emplacements utilisés", + "dpi.slotsCount": "Nombre d'emplacements DPI", + "dpi.startingSlot": "Emplacement de départ", + "dpi.makeStarting": "En faire l'emplacement de départ", + "dpi.slotX": "DPI X de l'emplacement {n}", + "dpi.slotY": "DPI Y de l'emplacement {n}", + "dpi.linkXY": "Lier X et Y de l'emplacement {n}", + "dpi.linkedHint": "X et Y sont liés — cliquez pour les régler séparément", + "dpi.unlinkedHint": "X et Y sont séparés — cliquez pour les lier", + "dpi.slotLiftOff": "Lift-off de l'emplacement {n}", + "dpi.liftOffTitle": "Définir la distance de lift-off", + "dpi.noLiftOff": "Ce format de profil n'a pas de réglage de lift-off", + "dpi.slotReadonly": "Lecture seule : l'écriture des emplacements DPI sur un profil n'est pas encore activée, car la séquence de gravure n'a pas été vérifiée sur du matériel réel.", + "dpi.slotNote": "Chaque emplacement stocke sa propre sensibilité X/Y et son niveau de lift-off. {min}–{max} DPI par pas de {step}. L'emplacement mis en surbrillance est celui sur lequel la souris démarre.", + "dpi.stagesInUse": "Étapes utilisées", + "dpi.stagesCount": "Nombre d'étapes DPI", + "dpi.activeStage": "Étape active", + "dpi.makeActive": "En faire l'étape active", + "dpi.stageDpi": "DPI de l'étape {n}", + "dpi.color": "Couleur", + "dpi.stageColor": "Couleur de l'étape {n}", + "dpi.stageNoteCount": "Préréglages et Personnalisé modifient l'étape en surbrillance. {min}–{max} DPI. Le bouton DPI de la souris parcourt ces étapes.", + "dpi.stageNoteSteps": "Préréglages et Personnalisé modifient l'étape en surbrillance. {min}–{max} DPI par pas de {step}. Le bouton DPI de la souris parcourt les {total} étapes.", + "dpi.stageToggle": "Include this DPI stage", + "dpi.editorCountNote": "One row per DPI stage. Tick a row to include it in the DPI cycle; untick to disable it and keep the value for later. Click a number to make it the starting stage.", + "dpi.editorFixedNote": "One row per DPI stage, {total} fixed. Edit the value or slider to change it. Click a number to make it the active stage.", + "dpi.editorGenericNote": "One row per preset DPI. Tick a row (or click its number) to make it the current DPI; unticked rows are kept as picks for later.", + "dpi.xAxis": "Axe X", + "dpi.yAxis": "Axe Y", + "dpi.viewStages": "Étapes", + "dpi.viewSingle": "Unique", + "dpi.viewSlots": "Emplacements", + "dpi.viewSlotsToggle": "Modifier le DPI en emplacements ou en valeur unique", + "dpi.viewToggle": "Modifier le DPI en étapes ou en valeur unique", + "perf.reportFrequency": "Fréquence de rapport", + "perf.reportRate": "Taux de rapport", + "perf.sharedNote": "Enregistré dans ce profil comme un seul intervalle partagé, jusqu'à {max} Hz.", + "perf.splitNote": "Enregistré dans ce profil, un taux par liaison. Jusqu'à {wireless} Hz sans fil, {wired} Hz par câble.", + "perf.eggNote": "Des taux plus élevés actualisent le mouvement du curseur plus souvent et augmentent la charge de traitement CPU/USB.", + "perf.note": "Des taux plus élevés actualisent le mouvement du curseur plus souvent, mais consomment plus de batterie.", + "perf.allConnections": "Toutes les connexions", + "perf.wired": "Filaire", + "perf.wireless": "Sans fil", + "perf.gamingSurface": "Surface de jeu", + "perf.surfaceNote": "Ajuste le capteur pour les tapis de souris gaming. Auto laisse la souris décider ; désactivez si le suivi se comporte mal sur une surface non gaming.", + "perf.auto": "Auto", + "perf.liftOff": "Distance de lift-off", + "perf.liftOffMode": "Mode de lift-off", + "perf.single": "Unique", + "perf.asymmetric": "Asymétrique", + "perf.liftOffLabel": "Lift-off", + "perf.landing": "Atterrissage", + "perf.lodLow": "Bas", + "perf.lodMedium": "Moyen", + "perf.lodHigh": "Haut", + "perf.lodNeedSurface": "Activez la surface de jeu ou réglez-la sur auto pour ajuster la distance de lift-off.", + "perf.lodNote": "Contrôle jusqu'à quelle hauteur vous pouvez soulever la souris avant l'arrêt du suivi. Des valeurs plus élevées maintiennent le suivi un peu plus longtemps.", + "perf.bunnyHop": "Bunny hop", + "perf.bunnyTime": "Durée du bunny hop en millisecondes", + "perf.bunnyReadonly": "Ce format de profil n'a pas été vérifié sur du matériel réel, il est donc en lecture seule.", + "perf.bunnyNote": "Ignore les clics répétés qui tombent dans cette fenêtre, afin qu'un switch qui rebondit lors d'un spam de clics rapides ne s'enregistre qu'une fois. Des durées plus longues filtrent davantage ; des durées plus courtes laissent passer les vrais clics rapides. {min}–{max} ms par pas de {step}.", + "perf.hybrid": "Hybride", + "perf.opticalOnly": "Optique uniquement", + "perf.lightforceMode": "Mode switch LightForce", + "perf.lightforceNote": "Hybride économise l'énergie en utilisant le contact mécanique et n'active le capteur optique qu'en cas de besoin. Optique uniquement est constant mais consomme plus de batterie.", + "light.receiverTitle": "Éclairage du récepteur", + "light.zoneTitle": "Éclairage {zone}", + "light.writeOnly": "Écriture seule", + "light.rgbPart": "Partie RGB", + "light.rgbParts": "Parties RGB", + "light.stripLeds": "LED du bandeau", + "light.rgbZones": "Zones RGB", + "light.effect": "Effet d'éclairage", + "light.brightness": "Luminosité", + "light.brightnessAria": "Luminosité de l'éclairage", + "light.colour": "Couleur", + "light.colour2": "Couleur 2", + "light.colourAria": "Couleur de l'éclairage", + "light.colour2Aria": "Deuxième couleur de l'éclairage", + "light.speed": "Vitesse de l'effet", + "light.choose": "Choisissez un effet", + "light.writeOnlyNote": "La souris ne peut pas signaler son effet actuel, ceci affiche donc la dernière valeur écrite.", + "light.zoneNote": "Choisit l'effet lumineux de {zone}.", + "mx.haptics": "Retour haptique", + "mx.hapticFeedback": "Retour haptique", + "mx.hapticStrength": "Intensité haptique", + "mx.batterySaving": "Économie de batterie", + "mx.friendlyName": "Nom convivial", + "mx.friendlyNameAria": "Nom convivial de l'appareil", + "mx.stageName": "Nom de l'étape", + "mx.chars": "{n}/{max} caractères", + "mx.ratcheted": "À crans", + "mx.freeSpinning": "Rotation libre", + "mx.wheelMode": "Mode de la molette", + "mx.ratchet": "Crans", + "mx.freespin": "Rotation libre", + "mx.hiRes": "Défilement haute résolution", + "mx.invertVertical": "Inverser le défilement vertical", + "mx.invertThumb": "Inverser la molette du pouce", + "mx.switchThreshold": "Seuil du switch", + "mx.pairedComputers": "Ordinateurs jumelés", + "mx.hostOf": "{a} sur {b}", + "mx.switchConfirm": "Basculer vers l'ordinateur {n} ? La souris se déconnectera immédiatement. Utilisez le bouton sous la souris pour la récupérer.", + "mx.switch": "Basculer", + "mx.remapping": "Réaffectation", + "mx.lockedOne": "{names} est verrouillé par le firmware de la souris et ne peut pas être réaffecté.", + "mx.lockedMany": "{names} sont verrouillés par le firmware de la souris et ne peuvent pas être réaffectés.", + "mx.divertedOne": "{name} est géré par une autre application, donc il ne fait rien ici.", + "mx.divertedMany": "{names} sont gérés par une autre application, donc ils ne font rien ici.", + "mx.restoreHardware": "Restaurer le contrôle matériel", + "adv.sleepMin": "Le délai de veille ne peut pas être inférieur à 1 minute.", + "adv.sleepTimeout": "Délai de mise en veille automatique", + "adv.hours": "Heures", + "adv.minutes": "Minutes", + "adv.seconds": "Secondes", + "adv.signal": "Force du signal", + "adv.signalUnavailable": "Le signal du récepteur n'est pas disponible.", + "adv.signal0": "Très faible", + "adv.signal1": "Faible", + "adv.signal2": "Correct", + "adv.signal3": "Bon", + "adv.signal4": "Excellent", + "adv.signalLevel": "Niveau {n}", + "adv.debounce": "Debounce", + "adv.autoSleep": "Veille automatique", + "adv.lowPower": "Mode basse consommation", + "adv.lowPowerNote": "Ralentit la souris pour économiser la batterie en dessous de ce niveau.", + "adv.lowPowerCeiling": "Indisponible au-dessus de {max} Hz. Réduisez le taux de sondage pour le modifier.", + "adv.processing": "Traitement", + "adv.angleSnapping": "Correction d'angle", + "adv.straightLine": "Correction en ligne droite", + "adv.hyperMode": "Mode hyper", + "adv.turboMode": "Mode turbo", + "adv.buttonCombos": "Combinaisons de boutons", + "adv.ultraRange": "Portée ultra-longue", + "adv.angleTune": "Réglage d'angle", + "adv.highSpeed": "Mode haute vitesse", + "adv.competitive": "Mode compétitif", + "adv.highestPerf": "Performance maximale", + "adv.perfMode": "Mode performance", + "adv.sensorMode": "Mode du capteur", + "adv.ecoNote": "Éco économise l'énergie à 125–1000 Hz sans fil. Élevé utilise le profil de capteur performance.", + "adv.lockedNote": "Verrouillé sur {mode} à {hz} Hz {conn}.", + "adv.duration": "Durée", + "adv.dpiIndicator": "Indicateur DPI", + "adv.effect": "Effet", + "adv.ledOff": "Éteint", + "adv.ledSteady": "Fixe", + "adv.ledBreathing": "Respiration", + "adv.brightness": "Luminosité", + "adv.speed": "Vitesse", + "adv.dpiStageNote": "Utilise la couleur de l'étape DPI active enregistrée par la souris.", + "adv.sensorPerf": "Performance du capteur", + "adv.systemMode": "Mode système", + "adv.opticalNote": "Choisissez le profil de performance et de consommation du capteur. Optical Engine est verrouillé tant que le mode Ultra est actif.", + "adv.clickBehavior": "Comportement du clic", + "adv.clickNote": "HyperClick réduit la latence du clic. Slam-Click contrôle la protection contre les clics déclenchés par impact.", + "adv.dongleTournament": "Dongle et mode tournoi", + "adv.dongleLed": "LED du dongle", + "adv.receiverRapidFire": "Récepteur et tir rapide", + "adv.ledConnectRate": "Connexion et taux d'interrogation", + "adv.ledBatteryStatus": "État de la batterie", + "adv.ledBatteryWarning": "Alerte de batterie", + "adv.fireKeyTimes": "Clics par appui", + "adv.fireKeyHold": "Maintenir pour tirer", + "adv.fireKeyInterval": "Intervalle (ms)", + "adv.batteryIndicator": "Indicateur de batterie", + "adv.solidWhite": "Blanc fixe", + "adv.tournamentScroll": "Défilement tournoi", + "adv.scrollUp": "Défiler vers le haut", + "adv.scrollDown": "Défiler vers le bas", + "adv.bothDirections": "Les deux directions", + "adv.passthrough": "Fenêtre de passage", + "adv.oneSecond": "1 seconde", + "adv.halfSeconds": "1,5 seconde", + "adv.filters": "Filtres", + "adv.slamclickFilter": "Filtre slamclick", + "adv.jitterFilter": "Filtre de vibration de mouvement", + "adv.gxMode": "Mode switch GX", + "adv.leftButton": "Bouton gauche", + "adv.rightButton": "Bouton droit", + "adv.dividerTitle": "Diviseur personnalisé", + "adv.dividerWarning": "Les diviseurs de sondage non standard peuvent se comporter différemment selon les versions de firmware.", + "adv.divider8k": "Diviseur 8K", + "adv.dividerResult": "Résultat : {hz} Hz", + "adv.dividerHint": "Entrez un diviseur de 1 à 255.", + "adv.applyDivider": "Appliquer le diviseur", + "adv.cpiStages": "Étapes CPI", + "adv.enabledStages": "Étapes activées", + "adv.stageCount": "{n} étape{s}", + "adv.stage": "Étape {n}", + "adv.separateXY": "X/Y séparés", + "adv.applyStage": "Appliquer l'étape", + "adv.mapping": "Mappage", + "adv.razerLocked": "{name} est fixé sur la couche Standard et ne peut pas être réaffecté ou désactivé.", + "adv.multiclick": "Filtre multiclic", + "adv.eggButtonTitle": "Multiclic et mappage", + "adv.proAdvanced": "Avancé", + "adv.wheelAccel": "Accélération de la molette", + "adv.angleTuning": "Réglage d'angle", + "adv.onboardProfile": "Profil intégré", + "adv.profileOpt": "Profil {n}", + "prof.onboardTitle": "Profil", + "prof.activeProfile": "Profil actif", + "prof.profileStores": "Chaque profil enregistre ses propres étapes DPI et son taux de sondage, ces valeurs changent donc avec le profil.", + "map.remap": "Réaffecter", + "map.defaultNote": "« Par défaut » restaure la fonction d'usine d'un bouton.", + "pow.mode": "Mode", + "pow.perfMode": "Mode performance", + "diag.details": "Détails de l'appareil", + "diag.diagnostics": "Diagnostic", + "diag.deviceDiag": "Diagnostic de l'appareil", + "diag.download": "Télécharger le diagnostic", + "diag.verifyFormat": "Vérifier le format du profil", + "diag.reads": "Lectures", + "diag.rawSnapshot": "Instantané brut", + "diag.notReported": "Non signalé", + "diag.unknown": "Inconnu", + "diag.noneHost": "Aucun en mode host", + "diag.linkedXY": "X/Y liés", + "sup.support": "SUPPORT DES APPAREILS", + "sup.requestMouse": "Demander une souris", + "sup.introVote": "Effectuez la vérification antispam, puis votez pour une souris listée ou soumettez une nouvelle demande.", + "sup.introPaused": "Le vote et les nouvelles demandes sont temporairement suspendus pendant que nous ajoutons une protection anti-abus renforcée.", + "sup.turnstile": "Vérification antispam", + "sup.searchPlaceholder": "Rechercher un fabricant ou un modèle", + "sup.searchAria": "Rechercher des demandes de souris", + "sup.protectionLoading": "Chargement de la protection de vote", + "sup.completeCheck": "Complétez d'abord la vérification antispam", + "sup.vote": "Voter", + "sup.loading": "Chargement", + "sup.noMatches": "Aucune demande correspondante pour l'instant.", + "sup.requestDifferent": "Demander une autre souris", + "sup.manufacturer": "Fabricant", + "sup.model": "Modèle", + "sup.connection": "Connexion", + "sup.notSure": "Je ne sais pas", + "sup.wiredUsb": "USB filaire", + "sup.wirelessUsb": "Récepteur USB sans fil", + "sup.bluetooth": "Bluetooth", + "sup.wiredWireless": "Filaire et sans fil", + "sup.scope": "Une demande couvre toute la souris : réglages de performance, boutons, profils, éclairage, informations de batterie et toute autre fonctionnalité que nous pouvons prendre en charge.", + "sup.consent": "Ceci n'envoie que les champs affichés ici. Le diagnostic de l'appareil n'est jamais joint automatiquement.", + "sup.submitting": "Envoi…", + "sup.submit": "Envoyer la demande", + "sup.helpDiagnostics": "Aider à ajouter le support avec un diagnostic", + "sup.reviewTitle": "Vérifiez le diagnostic avant l'envoi", + "sup.reviewBody": "Les rapports peuvent contenir le firmware, des identifiants de récepteur, des réglages intégrés et le trafic HID récent. Rien ci-dessous n'est envoyé sans votre consentement.", + "sup.reviewAria": "Vérification de l'envoi du diagnostic", + "sup.reviewConsent": "J'ai vérifié ces données et j'accepte de les envoyer pour cette demande de support.", + "sup.upload": "Envoyer le diagnostic", + "sup.loadingRequests": "Chargement des demandes…", + "sup.loadFail": "Impossible de charger les demandes.", + "sup.protectionMissing": "La protection de vote n'est pas configurée.", + "sup.turnstileFail": "La vérification antispam n'a pas pu se charger.", + "sup.turnstileMissing": "La vérification antispam ne s'est pas chargée.", + "sup.voteRecorded": "Votre vote pour {item} a été enregistré.", + "sup.alreadyVoted": "Vous avez déjà voté pour cette souris.", + "sup.voteFail": "Impossible d'enregistrer votre vote.", + "sup.saved": "Demande enregistrée. Vous pouvez maintenant voter pour elle depuis la liste.", + "sup.saveFail": "Impossible d'enregistrer cette demande.", + "sup.uploadedThanks": "Diagnostic envoyé séparément. Merci de nous aider à étudier cette souris.", + "sup.uploadFail": "Impossible d'envoyer le diagnostic.", + "cap.title": "Capture HID++", + "cap.closeCapture": "Fermer la capture", + "cap.copyVerification": "Copier les données de vérification", + "cap.verifyWrites": "Vérifier les écritures de profil", + "cap.snapshot": "Instantané des profils", + "cap.compare": "Comparer", + "cap.clear": "Effacer", + "cap.copyComparison": "Copier la comparaison", + "cap.whatChanged": "Qu'avez-vous changé ?", + "cap.notesPlaceholder": "Détail optionnel, p. ex. sondage sans fil de 8000 Hz à 1000 Hz", + "misc.devTesting": "Test de développement", + "misc.devTestingBody": "Enregistrez l'identifiant de l'appareil, la version du protocole et tout réglage défaillant dans l'issue ou la pull request. N'utilisez pas la réinitialisation d'usine pendant les tests initiaux.", + "prof.editing": "MODIFICATION", + "prof.active": "actif", + "prof.editingTag": "modification", + "prof.reload": "Recharger les profils", + "prof.deleteReset": "Supprimer et réinitialiser tous les profils intégrés", + "prof.restoreDefaults": "Restaurer définitivement tous les profils intégrés aux valeurs par défaut Logitech", + "prof.openHost": "Ouvrir les réglages host", + "prof.hostAlready": "La souris est déjà en mode host", + "prof.switchHost": "Basculer la souris en mode host", + "prof.switchHostAria": "Basculer en mode host", + "prof.layoutUnverified": "Cette disposition de profil n'a pas été vérifiée sur du matériel réel", + "prof.openProfile": "Ouvrez ce profil pour le modifier", + "prof.noNameField": "Ce format de profil n'a pas de champ nom", + "prof.contentUnverified": "Les écritures de contenu de profil n'ont pas été vérifiées sur du matériel réel", + "prof.renameProfile": "Renommer ce profil", + "prof.runningProfile": "La souris exécute ce profil", + "prof.enableFirst": "Activez ce profil avant d'y basculer", + "prof.switchProfile": "Basculer la souris vers ce profil", + "prof.disable": "Désactiver", + "prof.enable": "Activer", + "prof.disableProfile": "Désactiver ce profil", + "prof.enableProfile": "Activer ce profil", + "prof.toggleProfile": "{a} le profil {n}", + "prof.assign": "Affectations intégrées", + "prof.assignBody": "Choisissez ce que fait chaque contrôle physique dans ce profil.", + "prof.assignLayer": "Couche d'affectation", + "prof.normalTab": "Normal", + "prof.keyboardShortcut": "Raccourci clavier", + "prof.customPreserved": "Mappage personnalisé (conservé)", + "prof.keyboardOpt": "Raccourci clavier…", + "prof.volUp": "Volume plus", + "prof.volDown": "Volume moins", + "prof.mute": "Muet", + "prof.playPause": "Lecture / pause", + "prof.nextTrack": "Piste suivante", + "prof.prevTrack": "Piste précédente", + "prof.recorder": "ENREGISTREUR CLAVIER", + "prof.recordTitle": "Enregistrer une séquence de commandes", + "prof.recordBody": "Démarrez l'enregistrement, appuyez sur un raccourci ou une séquence, puis arrêtez l'enregistrement.", + "prof.stopRec": "Arrêter l'enregistrement", + "prof.record": "Enregistrer", + "prof.listening": "Écoute…", + "prof.nothingRec": "Rien d'enregistré pour l'instant", + "prof.macroNote": "Cette séquence sera enregistrée dans la mémoire de macros intégrée de la souris.", + "prof.assignSeq": "Affecter la séquence", + "prof.assignShortcut": "Affecter le raccourci", + "super.actuation": "Point d'activation", + "super.both": "Les deux boutons", + "super.independent": "Indépendant", + "super.bothPrimary": "Les deux boutons principaux", + "super.bothBody": "Applique les mêmes valeurs aux boutons gauche et droit.", + "super.applyBoth": "Appliquer aux deux boutons", + "super.shortClick": "1 clic court", + "super.longClick": "{max} clic long", + "super.fast": "1 rapide", + "super.slow": "{max} lent", + "super.off0": "0 désactivé", + "super.maxFeedback": "{max} retour maximal", + "super.applyLeft": "Appliquer à gauche", + "super.applyRight": "Appliquer à droite", + "super.clickHaptics": "Retour haptique du clic", + "key.reload": "Recharger les couches", + "key.openLayer": "Ouvrir cette couche", + "key.currentLayer": "Couche actuelle sur la souris", + "key.storedLayer": "Enregistrée sur la souris", + "key.alreadyLayer": "La souris est déjà sur cette couche", + "key.switchLayer": "Basculer la souris vers {label}", + "key.switchTo": "Basculer vers {label}", + "key.active": "active", + "key.editing": "modification", + "key.layersStored": "Couches intégrées enregistrées sur la Nape Pro", + "key.inspectHint": "Cliquez sur une couche pour l'inspecter. Utilisez le cercle pour y basculer la souris.", + "key.reading": "Lecture de {label}…", + "key.layerNote": "Les modifications restent sur cette couche jusqu'à ce que vous les appliquiez. L'orientation est enregistrée par couche par pas de 45°. Le défilement horaire et antihoraire peut être configuré indépendamment.", + "key.assignBody": "Choisissez l'orientation du capteur de cette couche et ce que fait chaque contrôle physique.", + "ctl.noDevice": "Aucun appareil connecté", + "ctl.addSidebar": "Ajoutez un appareil compatible depuis la barre latérale pour lire son état actuel.", + "ctl.onboardIdle": "Les profils se chargent lorsque la souris est en mode intégré.", + "ctl.waitFlash": "Attendez la fin de la gravure en cours.", + "ctl.alreadyMatches": "{label} correspond déjà à la souris.", + "ctl.stagedFlash": "{label} préparé. Gravez pour l'écrire sur la souris.", + "ctl.discarded": "Les modifications préparées ont été annulées.", + "ctl.badKey": "Impossible de lire cette clé de profil", + "ctl.noMouse": "Aucune souris connectée", + "ctl.noMouseDetail": "Connectez la souris pour y importer les réglages.", + "ctl.keyMismatch": "La clé de profil ne correspond pas à cette souris", + "ctl.mismatchDetail": "Cette clé a été capturée depuis une {brand} {name}, pas cet appareil.", + "ctl.keyImported": "Clé de profil importée", + "ctl.keyImportedDetail": "Vérifiez les modifications en file d'attente, puis gravez pour les écrire.", + "ctl.switchingHost": "Basculement vers l'ordinateur {n}", + "ctl.switchHostDetail": "Appuyez sur le bouton sous la souris pour la récupérer.", + "ctl.unableSwitch": "Impossible de demander le basculement.", + "ctl.restoring": "Restauration des boutons au contrôle matériel…", + "ctl.restored": "Boutons restaurés au contrôle matériel.", + "ctl.unableRestore": "Impossible de restaurer les boutons.", + "ctl.waitRefresh": "Attente de l'actualisation actuelle de l'appareil…", + "ctl.flashFailed": "Échec de la gravure", + "ctl.unableFlash": "Impossible de graver les modifications préparées.", + "ctl.flashedOne": "1 modification gravée sur la souris.", + "ctl.flashedMany": "{n} modifications gravées sur la souris.", + "ctl.connected": "Connecté", + "ctl.batteryPct": "Batterie {n}%", + "ctl.currentLine": "Actuel : {dpi} DPI · {hz} Hz", + "ctl.switching": "Basculement", + "ctl.switchingPath": "Chemin de basculement", + "ctl.newDevice": "Nouvel appareil détecté", + "ctl.connFailed": "Échec de la connexion", + "ctl.reading": "Lecture de {name}…", + "ctl.preferUsb": "Préférence pour l'USB plutôt que le récepteur.", + "ctl.unableSwitchDevices": "Impossible de changer d'appareil.", + "ctl.unableRead": "Impossible de lire la souris connectée.", + "ctl.unableSwitchMouse": "Impossible de basculer vers une autre souris connectée.", + "ctl.requesting": "Demande d'autorisation", + "ctl.choosePrompt": "Choisissez votre appareil dans la fenêtre du navigateur.", + "ctl.notConnected": "Non connecté", + "ctl.noSelection": "Aucun appareil n'a été sélectionné dans la fenêtre du navigateur.", + "ctl.opening": "Ouverture de l'appareil", + "ctl.notMouse": "Ce n'est pas une souris", + "ctl.reconnecting": "Reconnexion", + "ctl.readingPrev": "Lecture de l'appareil précédemment autorisé.", + "ctl.useAdd": "Utilisez Ajouter un appareil si la souris ne se reconnecte pas automatiquement.", + "ctl.couldNotReconnect": "Impossible de reconnecter la souris", + "ctl.dpiUnsupported": "Cette valeur DPI n'est pas prise en charge par cette souris.", + "ctl.closestStep": "Cette souris ne peut pas faire {dpi} DPI. Le pas le plus proche pris en charge est {closest}.", + "ctl.dpiNotSupported": "{dpi} DPI n'est pas pris en charge par cette souris.", + "ctl.axesAdvertised": "Les deux valeurs d'axe doivent être des valeurs DPI annoncées.", + "ctl.unableProfiles": "Impossible de lire les profils intégrés.", + "ctl.switchingMode": "Basculement vers le mode {mode}…", + "ctl.unableMode": "Impossible de changer le mode intégré.", + "ctl.switchingProfile": "Basculement vers le profil {n}…", + "ctl.unableProfile": "Impossible de sélectionner ce profil.", + "ctl.unableKeychron": "Impossible de lire les affectations de boutons Keychron.", + "ctl.runningFrom": "Exécution depuis {label}. {layers}", + "ctl.layersCount": "{n} couche{s} intégrée{s}", + "ctl.readingLayers": "Lecture des couches intégrées…", + "ctl.noLayers": "La souris n'a signalé aucune couche intégrée.", + "ctl.unableLayers": "Impossible de lire les couches intégrées.", + "ctl.previewSwitched": "Aperçu : basculé vers {label}. Rien n'est écrit.", + "ctl.runningFromLabel": "Exécution depuis {label}.", + "ctl.unableLayer": "Impossible de changer de couche.", + "ctl.unableProfileState": "Impossible de changer l'état du profil.", + "ctl.resetting": "Réinitialisation de tous les profils intégrés…", + "ctl.writingDefaults": "Écriture des valeurs par défaut d'usine Logitech…", + "ctl.resetDone": "Tous les profils intégrés ont été réinitialisés aux valeurs par défaut Logitech.", + "ctl.resetComplete": "Réinitialisation terminée. Le profil 1 est actif ; les autres profils sont désactivés.", + "ctl.unableReset": "Impossible de réinitialiser tous les profils intégrés.", + "ctl.rateSupport": "Cette souris prend en charge {rates} Hz pour cette liaison de profil.", + "ctl.noLighting": "L'éclairage n'est pas disponible pour cette souris.", + "ctl.pickEffect": "Choisissez d'abord un effet.", + "ctl.waitingRefresh": "En attente d'actualisation", + "ctl.unableRefresh": "Impossible d'actualiser l'état de la souris.", + "ctl.previewG502": "Aperçu : performance, profils intégrés, réaffectation de boutons et éclairage RGB de la G502 X PLUS.", + "ctl.previewLabel": "Aperçu : {label}. Rien n'est écrit.", + "ctl.connectedTo": "Connecté à {name}", + "ctl.mouseGone": "Souris déconnectée", + "ctl.deviceRemoved": "L'appareil a été retiré.", + "ctl.savedName": "{name} enregistré", + "ctl.gone": "La souris n'est plus connectée.", + "ctl.noWebHid": "WebHID n'est pas disponible. Utilisez Chrome ou Edge sur ordinateur.", + "ctl.unableReconnect": "Impossible de se reconnecter à la souris.", + "ctl.noProfileOpen": "Aucun profil n'est ouvert pour modification.", + "ctl.receiverGone": "Le récepteur n'est plus connecté.", + "ctl.noLedControl": "Cet appareil Pulsar n'expose pas de contrôle de LED du récepteur.", + "ctl.teeGone": "La souris Teevolution n'est plus connectée.", + "ctl.previewNoMouse": "Mode aperçu : aucune souris n'est connectée, rien n'a donc été écrit.", + "ctl.atkPending": "Appliquez ou annulez les modifications en attente avant de changer de banque de configuration.", + "ctl.atkSwitching": "Basculement vers la banque de configuration {n}…", + "ctl.atkActive": "La banque de configuration {n} est active.", + "ctl.atkUnableSelect": "Impossible de sélectionner cette banque de configuration ATK R1.", + "ctl.atkUnableBank": "Impossible de sélectionner cette banque de configuration.", + "ctl.pairStarting": "Démarrage de la fenêtre d'appairage du récepteur R1 SE+…", + "ctl.pairActive": "Le récepteur a déjà une fenêtre d'appairage active. Attendez qu'elle se termine, puis démarrez l'appairage R1 SE+.", + "ctl.pairActiveTitle": "Appairage déjà actif", + "ctl.pairActiveDetail": "OpenMouse a laissé le compte à rebours du récepteur existant inchangé.", + "ctl.pairProgress": "Appairage R1 SE+… {n}s restantes.", + "ctl.pairChecking": "Vérification de l'appairage terminé…", + "ctl.pairWaiting": "En attente de la fenêtre d'appairage du récepteur…", + "ctl.pairDone": "Appairage R1 SE+ terminé. La souris est en ligne.", + "ctl.pairDoneTitle": "Récepteur appairé", + "ctl.pairDoneDetail": "La R1 SE+ est en ligne via le récepteur 1K.", + "ctl.pairEnded": "L'appairage s'est terminé sans souris en ligne (état {s}).", + "ctl.pairExpired": "La fenêtre d'appairage du récepteur a expiré avant la fin.", + "ctl.pairUnable": "Impossible d'appairer le récepteur R1 SE+.", + "ctl.pairFailed": "Échec de l'appairage", + "ctl.cmdPower": "Changer le mode de performance", + "ctl.progPower": "Changement de mode…", + "ctl.cmdRemap": "Réaffecter le bouton {button}", + "ctl.progRemap": "Réaffectation…", + "ctl.cmdProfile": "Changer le profil actif", + "ctl.progProfile": "Basculement de profil…", + "ctl.switchingLayer": "Basculement vers {label}…", + "ctl.readingProfiles": "Lecture des profils intégrés…", + "ctl.noProfiles": "Cette souris n'a signalé aucun profil intégré.", + "ctl.noNameField": "Ce format de profil n'a pas de champ nom.", + "ctl.selectedMouse": "la souris sélectionnée", + "ctl.autoSleep": "Veille automatique {v}", + "ctl.autoSleepOff": "Veille automatique désactivée", + "ctl.highestPref": "Performance maximale {v}", + "sleep.never": "Jamais", + "sleep.second1": "1 seconde", + "sleep.seconds": "{n} secondes", + "sleep.minute1": "1 minute", + "sleep.minutes": "{n} minutes", + "sleep.hour1": "1 heure", + "sleep.hours": "{n} heures", + "prof.hostName": "Host", + "prof.liveDetail": "Réglages en direct, non enregistrés sur la souris", + "prof.dpiSlots": "{n} emplacement{s} DPI", + "prof.noSlots": "aucun emplacement DPI", + "prof.profileName": "Profil {n}", + "prof.disabledTag": "désactivé", + "key.layerName": "Couche {n}", + "conn.wired": "Filaire", + "conn.wireless": "Sans fil", + "light.noEffect": "Aucun effet", + "light.speedN": "vitesse {n}", + "page.locale": "Langue", + "page.en": "EN", + "page.pt": "PT", + "page.es": "ES", + "page.fr": "FR", + "page.de": "DE", + "page.zh": "中文", + "page.ja": "日本語", + "page.ko": "한국어", + "page.ru": "РУС", + "off.banner": "Vous êtes hors ligne. Tout ce qui nécessite le réseau ne sera pas mis à jour.", + "land.supported": "Souris compatibles", + "land.contribute": "Contribuer", + "land.donate": "Faire un don", + "land.openApp": "Ouvrir l'application", + "land.eyebrow": "Gratuit · Open source · Aucun logiciel du fabricant", + "land.hero": "Une application pour chaque souris.", + "land.lead": "OpenMouse fonctionne entièrement dans votre navigateur via WebHID — DPI, taux de sondage, boutons et RGB, pour des dizaines de souris gaming, sans compte, sans installation et sans télémétrie envoyée où que ce soit.", + "land.checkMouse": "Vérifiez votre souris", + "land.f1t": "Fonctionne dans votre navigateur", + "land.f1b": "Pas d'installateur, pas de service en arrière-plan, pas de compte. Branchez votre souris, ouvrez la page, et elle est là via WebHID.", + "land.f2t": "Des dizaines de souris, une application", + "land.f2b": "Une interface cohérente entre les marques et modèles, au lieu d'une application différente et surchargée par fabricant.", + "land.f3t": "Entièrement open source", + "land.f3b": "Chaque driver est rétro-ingénié ouvertement et revu sur GitHub — rien n'appelle chez lui, et vous pouvez lire exactement ce qu'il fait.", + "land.contribTitle": "Aidez à ajouter le support pour plus de souris", + "land.contribBody": "OpenMouse ne prend en charge que ce que la communauté a rétro-ingénié et testé. Si votre souris n'est pas encore listée, le guide de contribution explique les pratiques de rétro-ingénierie sûres et comment les dépôts de drivers s'articulent.", + "land.contribCta": "Lire le guide de contribution", + "chk.back": "← Retour au site", + "chk.overline": "DIAGNOSTIC HID", + "chk.heroBody": "Scannez vos souris gaming connectées pour voir quelles interfaces sont accessibles via WebHID — et lesquelles nécessitent un driver natif.", + "chk.webhidOk": "WebHID est disponible dans ce navigateur — le scan d'appareils est pris en charge.", + "chk.webhidMissing": "WebHID n'est pas disponible. Utilisez Chrome ou Edge sur ordinateur pour exécuter le diagnostic.", + "chk.scanning": "Scan en cours…", + "chk.scanAgain": "Scanner à nouveau", + "chk.scanBtn": "Scanner les souris", + "chk.scanNote": "Vous verrez une fenêtre du navigateur pour sélectionner les appareils.", + "chk.waitPrompt": "En attente de la fenêtre du navigateur…", + "chk.cancelled": "Scan annulé ou aucun appareil sélectionné.", + "chk.noMatch": "Aucun appareil correspondant sélectionné.", + "chk.testing": "Test de {n} appareil{s}…", + "chk.scanError": "Erreur de scan : {msg}", + "chk.resultsOne": "RÉSULTATS — {n} APPAREIL", + "chk.resultsMany": "RÉSULTATS — {n} APPAREILS", + "chk.shareDiscord": "Partagez ces résultats avec l'équipe OpenMouse sur Discord.", + "chk.copied": "Copié !", + "chk.copyDiscord": "Copier pour Discord", + "chk.collections": "COLLECTIONS HID", + "chk.txTest": "TEST RAZER TX-ID", + "chk.responded": "✓ a répondu", + "chk.noResponse": "✗ aucune réponse", + "chk.openedOk": "Appareil ouvert avec succès", + "chk.couldNotOpen": "Impossible d'ouvrir", + "chk.mouseFallback": "Souris {brand}", + "chk.noteBlocked": "Dongle HyperPolling — mouhid.sys bloque WebHID sur Windows", + "chk.noteFull": "Interface fabricant avec rapports de caractéristiques visibles", + "chk.notePartial": "Interface fabricant trouvée — la visibilité des rapports de caractéristiques varie selon l'OS/le navigateur", + "chk.noteLimited": "Seule l'interface souris de démarrage standard est visible pour WebHID", + "chk.noteUnknown": "Aucune collection visible — l'interface peut être bloquée", + "chk.noteRazerOk": "Le protocole HID Razer répond — test TX-ID réussi", + "chk.noteRazerPartial": "L'appareil s'est ouvert mais le test TX-ID n'a reçu aucune réponse valide", + "chk.noteSkipped": "{brand} — interface accessible (sondage ignoré par sécurité)", + "chk.noteReadable": "Rapport de caractéristiques lisible sur l'interface fabricant", + "chk.noteReadFailed": "Interface fabricant accessible mais la lecture du rapport de caractéristiques a échoué", + "chk.noteBlockedOpen": "L'OS/navigateur a bloqué l'ouverture : {msg}", + "chk.couldNotOpenDevice": "Impossible d'ouvrir l'appareil", + "chk.unknownVid": "Inconnu (VID {vid})", + "supp.devices": "Appareils", + "supp.contribute": "Contribuer", + "supp.support": "Support", + "supp.theme": "Changer de thème", + "supp.title": "Appareils compatibles", + "supp.sub": "Quelles souris gaming fonctionnent avec OpenMouse — modèles compatibles, demandes de la communauté et état du driver en un coup d'œil.", + "supp.search": "Rechercher par marque, modèle ou protocole…", + "supp.legend": "Légende", + "supp.brands": "Marques", + "supp.supportedNum": "{n} compatibles", + "supp.totalNum": "{n} suivies au total", + "supp.supportedWord": "compatibles", + "supp.totalWord": "suivies au total", + "supp.oneDevice": "{n} appareil", + "supp.manyDevices": "{n} appareils", + "supp.noResults": "Aucun appareil ne correspond à votre recherche.", + "supp.noFilters": "Aucun appareil ne correspond à ces filtres.", + "supp.clearFilters": "Effacer les filtres de marque et d'étiquette", + "supp.thStatus": "État", + "supp.thModel": "Modèle", + "supp.thNotes": "Notes", + "supp.thVotes": "Votes", + "supp.oneRequest": "({n} demande)", + "supp.manyRequests": "({n} demandes)", + "supp.follow": "Suivre sur X", + "supp.source": "Voir le code source", + "supp.stSupported": "Compatible", + "supp.stPr": "PR en attente", + "supp.stQuickwin": "Ajout facile", + "supp.stLikely": "Test nécessaire", + "supp.stDriver": "Driver nécessaire", + "supp.stUnknown": "Inconnu", + "supp.stBridge": "Bridge nécessaire", + "supp.stPending": "Demandé", + "supp.tabAll": "Tous", + "supp.legSupported": "Confirmé fonctionnel avec un driver enregistré", + "supp.legPr": "Une pull request ajoutant le driver est ouverte", + "supp.legQuickwin": "Protocole implémenté — il ne manque que l'entrée PID/config", + "supp.legLikely": "Le driver le couvre probablement — nécessite un test matériel", + "supp.legDriver": "Aucun driver n'existe encore", + "supp.legUnknown": "Protocole non encore identifié", + "supp.legBridge": "Non compatible avec WebHID — nécessite le compagnon OpenMouse Bridge", + "supp.legPending": "Demande active de la communauté", + "supp.kicker": "Catalogue d'appareils", + "supp.allBrands": "Toutes les marques", + "supp.showEverything": "Tout afficher", + "supp.brandWord": "Marque", + "supp.noBrands": "Aucune marque ne correspond.", + "supp.searchBrands": "Rechercher des marques…", + "supp.filterBrand": "Filtrer par marque", + "supp.allTags": "Toutes les étiquettes", + "supp.tagsWord": "Étiquettes", + "supp.tagWord": "Étiquette", + "supp.noTags": "Aucune étiquette ne correspond.", + "supp.searchTags": "Rechercher des étiquettes…", + "supp.filterTag": "Filtrer par étiquette", + "supp.legendTitle": "Que signifient les étiquettes ?", + "don.devices": "Appareils", + "don.support": "Support", + "don.check": "Tester la souris", + "don.contribute": "Contribuer", + "don.stars": "{n} étoiles", + "don.eyebrow": "Gratuit · Open source · Construit par la communauté", + "don.heroA": "Soutenez ce", + "don.heroB": "projet", + "don.lead": "OpenMouse est gratuit, open source, et conçu pour la communauté. S'il améliore votre configuration, ou vous évite le poids d'un logiciel propriétaire, envisagez de soutenir le travail derrière lui.", + "don.profileTitle": "Le projet OpenMouse", + "don.profileRole": "Mainteneurs et contributeurs", + "don.profileB1": "Bonjour ! Nous sommes les développeurs derrière OpenMouse — un configurateur de souris gratuit et open source. Nous investissons beaucoup de temps à régler de nouvelles souris, écrire des drivers filaires et sans fil, et garder le projet exempt de logiciel superflu des fabricants.", + "don.profileB2": "Nous apprécions le soutien de la communauté et de nos contributeurs. Le parrainage nous aide à couvrir le matériel, les tests et l'infrastructure, et nous permet de continuer à améliorer OpenMouse. Tout don est grandement apprécié !", + "don.thanks": "Merci de votre lecture !", + "don.optional": "Le don est facultatif.", + "don.type": "Type de don", + "don.once": "Ponctuel", + "don.monthly": "Mensuel", + "don.amount": "Montant du don (USD)", + "don.custom": "Montant personnalisé", + "don.customPh": "Entrez un montant", + "don.chargeOnce": "Vous ferez un don de {v} une fois, via GitHub Sponsors.", + "don.chargeMonthly": "Vous ferez un don de {v} chaque mois, via GitHub Sponsors.", + "don.submit": "Faire un don sur GitHub Sponsors", + "don.skip": "Non merci, continuer vers l'application", + "don.contribEyebrow": "AVEC AMOUR DE LA PART DE", + "don.contribTitle": "Nos contributeurs", + "don.stale": "Affichage des données enregistrées — ", + "don.apiFail": "Impossible de contacter GitHub ({msg}). Nouvelle tentative automatique.", + "don.contribs": "{n} contributions", + "don.contribOne": "{n} contribution", + "don.seeAll": "Voir tout le monde sur GitHub ↗", + "don.tagline": "Le configurateur de souris multiplateforme et open source.", + "don.pages": "Pages", + "don.home": "Accueil", + "don.contributeCol": "Contribuer", + "don.reportIssue": "Signaler un problème", + "don.discussions": "Discussions", + "don.source": "Code source", + "don.community": "Communauté", + "don.rights": "© {year} OpenMouse Project. Tous droits réservés.", + "don.privacy": "Politique de confidentialité", + "don.terms": "Conditions d'utilisation", + "don.created": "Créé avec ❤️ par", + "don.theCommunity": "la communauté", + "don.and": "et", + "don.contributors": "contributeurs", + "faq.title": "Foire aux questions", + "faq.q1": "OpenMouse est-il gratuit ?", + "faq.a1": "Oui. OpenMouse est gratuit et open source, sans comptes, abonnements ni paliers payants.", + "faq.q2": "OpenMouse envoie-t-il certaines de mes données quelque part ?", + "faq.a2": "Non. OpenMouse fonctionne entièrement dans votre navigateur via WebHID — il n'y a pas de télémétrie, pas de service en arrière-plan, et rien n'appelle chez lui. Vous pouvez lire exactement ce qu'il fait, car chaque driver est open source.", + "faq.q3": "Quelles souris sont compatibles ?", + "faq.a3a": "Des dizaines de souris gaming de plusieurs marques. Consultez la", + "faq.a3b": "liste des souris compatibles", + "faq.a3c": "pour l'ensemble actuel — le support dépend de ce que la communauté a rétro-ingénié et testé jusqu'à présent.", + "faq.q4": "Quels navigateurs fonctionnent avec OpenMouse ?", + "faq.a4": "OpenMouse nécessite un navigateur avec support WebHID, donc Chrome, Edge et autres navigateurs basés sur Chromium fonctionnent. Firefox et Safari ne prennent actuellement pas en charge WebHID.", + "faq.q5": "Ma souris n'est pas listée — puis-je ajouter le support pour elle ?", + "faq.a5a": "Oui. Le", + "faq.a5b": "guide de contribution", + "faq.a5c": "explique les pratiques de rétro-ingénierie sûres et comment les dépôts de drivers s'articulent.", + "faq.q6": "Dois-je installer quelque chose ?", + "faq.a6": "Pas d'installateur, pas de driver, pas d'application en arrière-plan. Branchez votre souris, ouvrez la page dans un navigateur compatible, et elle est là.", + "faq.q7": "Ma configuration est-elle stockée quelque part ?", + "faq.a7": "Vos réglages ne sont stockés que localement, dans votre navigateur — il n'y a pas de compte ni de synchronisation cloud.", + "faq.q8": "Comment puis-je soutenir le projet ?", + "faq.a8a": "Mettez une étoile au projet sur", + "faq.a8b": "rejoignez le", + "faq.a8c": "pour aider à financer le matériel de test et le développement.", + "adm.title": "Administration OpenMouse", + "adm.password": "Mot de passe", + "adm.checking": "Vérification…", + "adm.signin": "Se connecter", + "adm.loginFailed": "Échec de la connexion.", + "adm.networkError": "Erreur réseau.", + "adm.signout": "Se déconnecter", + "adm.loading": "Chargement…", + "adm.updated": "Mis à jour {time}", + "adm.live": "En direct maintenant", + "adm.peak": "Pic de tous les temps", + "adm.ofPeak": "{n}% du pic", + "adm.dailyViews": "Vues quotidiennes", + "adm.lastAvg": "DERNIERS {n}J · MOY {avg}", + "adm.viewsDays": "Vues, {n}j", + "adm.avgDay": "Moy. / jour", + "adm.medianAdj": "proche de la médiane", + "adm.bestDay": "Meilleur jour", + "adm.bestWeekday": "Meilleur jour de la semaine", + "adm.byViews": "par vues totales", + "adm.regions": "Régions", + "adm.regionsSub": "{views} vues · {n} régions", + "adm.country": "Pays", + "adm.views": "Vues", + "adm.mice": "Souris les plus utilisées", + "adm.miceSub": "{n} connexions · {m} modèles", + "adm.model": "Modèle", + "adm.uses": "Utilisations", + "adm.traffic": "Trafic par jour de la semaine", + "adm.trafficSub": "Vues par jour, par semaine", + "adm.session": "Détail de session", + "adm.sessionSub": "Dérivé de la plage actuelle", + "adm.trackedSince": "Suivi depuis", + "adm.daysTracked": "Jours suivis", + "adm.quietest": "Jour le plus calme", + "adm.trend7d": "Tendance 7j", + "adm.noHistory": "Pas encore d'historique.", + "adm.noData": "Pas encore de données.", + "adm.unknown": "Inconnu", + "adm.loadFail": "Impossible de charger les statistiques.", + "adm.viewsWord": "vues", + "adm.peakConcurrent": "pic simultané {n}", + + "tab.unavailable": "Les commandes de {tab} ne sont pas disponibles pour cet appareil.", + "tab.chooseAnother": "Choisissez un autre onglet pour continuer à configurer l’appareil.", +} diff --git a/src/i18n-de.ts b/src/i18n-de.ts index 102f79ae..91da4336 100644 --- a/src/i18n-de.ts +++ b/src/i18n-de.ts @@ -128,6 +128,7 @@ export const de: Record = { "set.korean": "한국어", "set.russian": "Русский", "set.vietnamese": "Tiếng Việt", + "set.arabic" : "العربيّة", "set.motion": "BEWEGUNG", "set.animations": "Animationen", "set.animationsBody": "Aktiviert Oberflächenübergänge und animierte Zustandsänderungen.", diff --git a/src/i18n-es.ts b/src/i18n-es.ts index 50086277..3984fa5c 100644 --- a/src/i18n-es.ts +++ b/src/i18n-es.ts @@ -128,6 +128,7 @@ export const es: Record = { "set.korean": "한국어", "set.russian": "Русский", "set.vietnamese": "Tiếng Việt", + "set.arabic" : "العربيّة", "set.motion": "MOVIMIENTO", "set.animations": "Animaciones", "set.animationsBody": "Activa las transiciones de la interfaz y los cambios de estado animados.", diff --git a/src/i18n-fr.ts b/src/i18n-fr.ts index abe12d76..8cf8689c 100644 --- a/src/i18n-fr.ts +++ b/src/i18n-fr.ts @@ -128,6 +128,7 @@ export const fr: Record = { "set.korean": "한국어", "set.russian": "Русский", "set.vietnamese": "Tiếng Việt", + "set.arabic" : "العربيّة", "set.motion": "MOUVEMENT", "set.animations": "Animations", "set.animationsBody": "Active les transitions de l'interface et les changements d'état animés.", diff --git a/src/i18n-ja.ts b/src/i18n-ja.ts index 8583b091..6f7dc02c 100644 --- a/src/i18n-ja.ts +++ b/src/i18n-ja.ts @@ -128,6 +128,7 @@ export const ja: Record = { "set.korean": "한국어", "set.russian": "Русский", "set.vietnamese": "Tiếng Việt", + "set.arabic" : "العربيّة", "set.motion": "モーション", "set.animations": "アニメーション", "set.animationsBody": "インターフェースの遷移とアニメーション付き状態変化を有効にします。", diff --git a/src/i18n-ko.ts b/src/i18n-ko.ts index c419ee9a..ea80f0e6 100644 --- a/src/i18n-ko.ts +++ b/src/i18n-ko.ts @@ -128,6 +128,7 @@ export const ko: Record = { "set.korean": "한국어", "set.russian": "Русский", "set.vietnamese": "Tiếng Việt", + "set.arabic" : "العربيّة", "set.motion": "모션", "set.animations": "애니메이션", "set.animationsBody": "인터페이스 전환 효과와 애니메이션 상태 변화를 활성화합니다.", diff --git a/src/i18n-pt.ts b/src/i18n-pt.ts index 55698cfe..5a00ecc6 100644 --- a/src/i18n-pt.ts +++ b/src/i18n-pt.ts @@ -128,6 +128,7 @@ export const pt: Record = { "set.korean": "한국어", "set.russian": "Русский", "set.vietnamese": "Tiếng Việt", + "set.arabic" : "العربيّة", "set.motion": "MOVIMENTO", "set.animations": "Animações", "set.animationsBody": "Ativa transições da interface e mudanças animadas de estado.", diff --git a/src/i18n-ru.ts b/src/i18n-ru.ts index 843bc0ce..a86451d0 100644 --- a/src/i18n-ru.ts +++ b/src/i18n-ru.ts @@ -127,6 +127,7 @@ export const ru: Record = { "set.japanese": "日本語", "set.korean": "한국어", "set.vietnamese": "Tiếng Việt", + "set.arabic" : "العربيّة", "set.motion": "АНИМАЦИЯ", "set.animations": "Анимации", "set.animationsBody": "Включить переходы интерфейса и анимацию смены состояний.", diff --git a/src/i18n-vi.ts b/src/i18n-vi.ts index 586fd998..e23f7ea0 100644 --- a/src/i18n-vi.ts +++ b/src/i18n-vi.ts @@ -94,6 +94,7 @@ export const vi: Record = { "set.korean": "한국어", "set.russian": "Русский", "set.vietnamese": "Tiếng Việt", + "set.arabic" : "العربيّة", "set.motion": "CHUYỂN ĐỘNG", "set.animations": "Hiệu ứng chuyển động", "set.animationsBody": "Bật hiệu ứng chuyển giao diện và thay đổi trạng thái có chuyển động.", diff --git a/src/i18n-zh.ts b/src/i18n-zh.ts index ca1733f1..25a27aa0 100644 --- a/src/i18n-zh.ts +++ b/src/i18n-zh.ts @@ -128,6 +128,7 @@ export const zh: Record = { "set.korean": "한국어", "set.russian": "Русский", "set.vietnamese": "Tiếng Việt", + "set.arabic" : "العربيّة", "set.motion": "动效", "set.animations": "动画", "set.animationsBody": "启用界面过渡效果和动态状态变化。", diff --git a/src/i18n.ts b/src/i18n.ts index 8a46b59e..26d483cb 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -131,6 +131,7 @@ const en = { "set.korean": "한국어", "set.russian": "Русский", "set.vietnamese": "Tiếng Việt", + "set.arabic" : "العربيّة", "set.motion": "MOTION", "set.animations": "Animations", "set.animationsBody": "Enable interface transitions and animated state changes.", @@ -1004,6 +1005,7 @@ export const LOCALE_NAME_KEYS: ReadonlyArray<[InterfaceLocale, I18nKey]> = [ ["ko", "set.korean"], ["ru", "set.russian"], ["vi", "set.vietnamese"], + ["ar", "set.arabic"], ]; /** Non-English tables load on demand so the initial bundle ships English @@ -1026,6 +1028,7 @@ const LOCALE_LOADERS: Record, () => Promise import("./i18n-ko.ts").then((m) => m.ko), ru: () => import("./i18n-ru.ts").then((m) => m.ru), vi: () => import("./i18n-vi.ts").then((m) => m.vi), + ar: () => import("./i18n-ar.ts").then((m) => m.ar), }; export function ensureLocale(locale: InterfaceLocale): Promise { diff --git a/src/interface-preferences.ts b/src/interface-preferences.ts index 7a900279..44dfb06a 100644 --- a/src/interface-preferences.ts +++ b/src/interface-preferences.ts @@ -13,7 +13,7 @@ export type InterfaceTheme = | "Light"; export type InterfaceColorMode = "Light" | "Dark" | "System"; export type InterfaceLocale = - "en" | "pt" | "es" | "fr" | "de" | "zh" | "ja" | "ko" | "ru" | "vi"; + "en" | "pt" | "es" | "fr" | "de" | "zh" | "ja" | "ko" | "ru" | "vi" | "ar"; /** Every supported locale, in picker order. Each entry's `match` decides which `navigator.language` prefixes resolve to it on first run — checked @@ -29,6 +29,7 @@ export const LOCALES: ReadonlyArray<{ code: InterfaceLocale; match: readonly str { code: "ru", match: ["ru"] }, { code: "vi", match: ["vi"] }, { code: "en", match: ["en"] }, + { code: "ar", match: ["ar"] }, ]; export interface InterfacePreferences { From 25235bc67b94363dab041d3cf469ba7f1971058d Mon Sep 17 00:00:00 2001 From: mh2n <112729612+mh2n@users.noreply.github.com> Date: Tue, 22 Sep 2026 22:48:20 +0100 Subject: [PATCH 2/4] i18n: add Arabic translate --- src/i18n-ar.ts | 222 ++++++++++++++++++++++++------------------------- 1 file changed, 111 insertions(+), 111 deletions(-) diff --git a/src/i18n-ar.ts b/src/i18n-ar.ts index 2f05615d..4663874d 100644 --- a/src/i18n-ar.ts +++ b/src/i18n-ar.ts @@ -1,123 +1,123 @@ import type { I18nKey } from "./i18n.ts"; -/** French strings, split into a lazy chunk so the initial bundle ships +/** Arabic strings, split into a lazy chunk so the initial bundle ships English only. Loaded via ensureLocale() before first use. */ export const ar: Record = { - "nav.language": "Langue", - "nav.settings": "Paramètres", - "nav.support": "Soutenir", - "nav.supportProject": "Soutenir le projet", - "nav.mouseCheck": "Tester la souris", - "nav.home": "Accueil", - "nav.dashboard": "Config. souris", - "nav.feedback": "Feedback", - "nav.docs": "Documentation", - "nav.supported": "Appareils compatibles", - "nav.whatsNew": "Nouveautés", - "nav.expand": "Développer la barre latérale", - "nav.collapse": "Réduire la barre latérale", - "side.selectedDevice": "APPAREIL SÉLECTIONNÉ", - "side.connectedMouse": "Souris connectée", - "side.connected": "Connectée", - "side.connectedDevices": "APPAREILS CONNECTÉS", + "nav.language": "", + "nav.settings": "الاعدادات", + "nav.support": "الدعم", + "nav.supportProject": "ادعم المشروع", + "nav.mouseCheck": "التحقق من الماوس", + "nav.home": "الصفحة الرئيسية", + "nav.dashboard": "اعدادات الماوس", + "nav.feedback": "", + "nav.docs": "Docs", + "nav.supported": "الاجهزة المدعومة", + "nav.whatsNew": "", + "nav.expand": "Expand sidebar", + "nav.collapse": "Collapse sidebar", + "side.selectedDevice": "الجهاز قيد الاستخدام", + "side.connectedMouse": "الماوس المتصل", + "side.connected": "متصل", + "side.connectedDevices": "الاجهزة المتصلة", "bridge.title": "OpenMouse Bridge", - "bridge.connected": "Connecté", - "bridge.games": "JEUX", - "bridge.profileEnabled": "Application automatique activée", - "bridge.profileEnabledDetail": "Bridge enverra ce profil à votre souris dès que {name} sera lancé.", - "bridge.profileUpdated": "Profil mis à jour", - "bridge.profileUpdatedDetail": "Bridge appliquera les nouveaux réglages la prochaine fois que {name} sera au premier plan.", - "bridge.profileDisabled": "Application automatique désactivée", - "bridge.profileDisabledDetail": "{name} ne recevra plus ce profil automatiquement.", - "bridge.profileSaveFailed": "Impossible de joindre OpenMouse Bridge", - "bridge.profileSaveFailedDetail": "Vérifiez que Bridge est toujours lancé, puis réessayez.", - "bridge.profileAppliedHere": "Profil de jeu appliqué", - "bridge.profileRestored": "Anciens réglages de la souris restaurés", - "panel.overline": "CONTRÔLE DE L'APPAREIL", - "panel.connectMouse": "Connectez une souris", - "panel.shareProfile": "Partager le profil", - "panel.deviceSections": "Sections de l'appareil", - "empty.previewsTitle": "Aperçus des drivers", - "empty.title": "Connectez votre appareil.", - "empty.previewsBody": "Affichez n'importe quel driver compatible sans son matériel :", - "empty.body": "Choisissez votre souris dans la fenêtre du navigateur pour ajuster ses réglages intégrés.", - "tab.overview": "Aperçu", - "tab.performance": "Performance", - "tab.buttons": "Boutons", - "tab.profiles": "Profils", - "tab.advanced": "Avancé", - "tab.lighting": "Éclairage", - "ov.battery": "BATTERIE", + "bridge.connected": "متصل", + "bridge.games": "الالعاب", + "bridge.profileEnabled": "الاختيار الداتي مفعل", + "bridge.profileEnabledDetail": "Bridge will push this profile to your mouse the moment {name} launches.", + "bridge.profileUpdated": "Profile updated", + "bridge.profileUpdatedDetail": "Bridge will apply the new settings the next time {name} is in the foreground.", + "bridge.profileDisabled": "Automatic apply turned off", + "bridge.profileDisabledDetail": "{name} will no longer get this profile pushed to it.", + "bridge.profileSaveFailed": "Could not reach OpenMouse Bridge", + "bridge.profileSaveFailedDetail": "Check that Bridge is still running, then try again.", + "bridge.profileAppliedHere": "خيار اللعب المفعل", + "bridge.profileRestored": "تم استرجاع اعداداتك السابقة", + "panel.overline": "DEVICE CONTROL", + "panel.connectMouse": "توصيل الموس", + "panel.shareProfile": "Share profile", + "panel.deviceSections": "Device sections", + "empty.previewsTitle": "Driver previews", + "empty.title": "اوصل جهازك.", + "empty.previewsBody": "عرض اي برنامجتشغيل مدعوم بدون الاجهزة المرتبطة به", + "empty.body": "اختر الماوس في نافذة المطالبة التي تظهر في المتصفح لضبط إعداداته المدمجة.", + "tab.overview": "نضرة عامة", + "tab.performance": "الاداء", + "tab.buttons": "الازرار", + "tab.profiles": "", + "tab.advanced": "الاعدادات المتقدمة", + "tab.lighting": "الاضاءة", + "ov.battery": "البطارية", "ov.firmware": "FIRMWARE", - "ov.fwSingle": "Firmware signalé par la souris", - "ov.fwNone": "Non signalé", - "ov.connection": "CONNEXION", - "ov.connReceiver": "Récepteur 2,4 GHz", - "ov.conn24": "2,4 GHz", - "ov.profile": "Profil", - "ov.led": "LED du récepteur", - "ov.on": "Activé", - "ov.off": "Désactivé", - "test.title": "Test de Taux de Polling de la Souris", - "test.subtitle": "Déplacez votre souris en petits cercles pour mesurer son taux de polling réel.", - "test.movePrompt": "Déplacez votre souris ici pour détecter le mouvement", - "test.ready": "Prêt", - "test.getReady": "Préparez-vous…", - "test.sampling": "Mesure en cours…", - "test.areaNote": "Gardez la souris en mouvement régulier pendant le compte à rebours et la mesure.", - "test.complete": "Test terminé", - "test.start": "Démarrer le test", - "test.reset": "Réinitialiser", - "test.avgHz": "Moyenne", - "test.peakHz": "Pic", - "test.low5": "5 % les plus bas", - "test.stability": "Stabilité", - "test.jitter": "Gigue", - "test.dropouts": "Décrochages", - "test.events": "Événements", - "test.avgInterval": "Intervalle moyen", - "test.deviceInfo": "INFOS APPAREIL", - "test.deviceName": "Appareil", - "test.connection": "Connexion", - "test.reportedHz": "Taux de polling signalé", + "ov.fwSingle": "Firmware reported by mouse", + "ov.fwNone":"ليسة مبلغة", + "ov.connection": "CONNECTION", + "ov.connReceiver": "موصل ال2.4", + "ov.conn24": "2.4 GHz", + "ov.profile": "Profile", + "ov.led": "LED الموصل", + "ov.on": "تشغيل", + "ov.off": "ايقاف", + "test.title": "معدل التجميع", + "test.subtitle": "حرك الموس في دوائر صغيرة لقيا معدل التجميع الفعلي", + "test.movePrompt": "حرك الموس هنا للتاكد من وجود حركة", + "test.ready": "Ready", + "test.getReady": "استعد…", + "test.sampling": "… أخذ العينات", + "test.areaNote": "حرك الموس بسلاسة اثناء العد التنازلي و اثناء اخد العينات.", + "test.complete": "انتهى الاختبار", + "test.start": "ابدا الاختبار", + "test.reset": "اعادة تعيين", + "test.avgHz": "المتوسط", + "test.peakHz": "اقصى حد", + "test.low5": "5% كحد ادنى ", + "test.stability": "التوازن", + "test.jitter": "Jitter", + "test.dropouts": "Dropouts", + "test.events": "Events", + "test.avgInterval": "Avg interval", + "test.deviceInfo": "معلومات الجهاز", + "test.deviceName": "Device", + "test.connection": "Connection", + "test.reportedHz": "Reported polling rate", "test.dpi": "DPI", - "test.dpiStages": "Étapes DPI", - "test.battery": "Batterie", + "test.dpiStages": "DPI stages", + "test.battery": "Battery", "test.firmware": "Firmware", - "test.noDevice": "Aucun appareil connecté. Testez votre taux de polling quand même ou ouvrez la Config de souris pour connecter.", - "test.buttonTest": "TEST DES BOUTONS", - "test.buttonHint": "Cliquez sur n'importe quel bouton de la souris pour le voir s'allumer ici.", - "test.btn.left": "Gauche", - "test.btn.right": "Droit", - "test.btn.middle": "Milieu", - "test.btn.back": "Retour", - "test.btn.forward": "Avant", - "set.title": "Paramètres", - "set.back": "Retour à l'appareil", - "set.soundTitle": "Son", - "set.soundDescription": "Activez des sons comme des clics de souris et de nouvelles connexions", - "set.profiles": "PROFILS", - "set.profileKey": "Clé de profil", - "set.profileKeyBody": "Une clé à copier-coller qui transfère les réglages de cette souris vers une autre unité du même modèle. Collez-la dans les Paramètres là-bas pour charger la même configuration.", - "set.yourKey": "Votre clé", - "set.noKey": "Connectez une souris pour générer une clé.", - "set.copyKey": "Copier la clé", - "set.copied": "Copié", - "set.importKey": "Importer une clé", - "set.importPlaceholder": "Collez ici une clé de profil…", - "set.import": "Importer", - "set.importNote": "Les réglages importés sont préparés comme n'importe quelle autre modification — rien n'est écrit tant que vous ne les gravez pas.", - "set.appearance": "APPARENCE", - "set.accentTheme": "Thème d'accent", - "set.accentBody": "Chaque tuile est peinte dans son propre thème.", - "set.glass": "VERRE LIQUIDE", - "set.glassTitle": "Intensité du verre", - "set.glassBody": "Ajustez le matériau givré, des panneaux entièrement transparents à la finition acrylique complète.", + "test.noDevice": "No device connected. Test your polling rate anyway, or open Mouse Config to connect.", + "test.buttonTest": "BUTTON TEST", + "test.buttonHint": "Click any mouse button to see it light up here.", + "test.btn.left": "Left", + "test.btn.right": "Right", + "test.btn.middle": "Middle", + "test.btn.back": "Back", + "test.btn.forward": "Forward", + "set.title": "Settings", + "set.back": "Back to device", + "set.profiles": "PROFILES", + "set.profileKey": "Profile key", + "set.profileKeyBody": "A copy-paste key that carries this mouse's settings to another unit of the same model. Paste it into Settings there to load the same setup.", + "set.yourKey": "Your key", + "set.noKey": "Connect a mouse to generate a key.", + "set.copyKey": "Copy key", + "set.copied": "Copied", + "set.importKey": "Import a key", + "set.importPlaceholder": "Paste a profile key here…", + "set.import": "Import", + "set.soundTitle": "Sound", + "set.soundDescription": "Enable sounds like mouse clicks and new connections", + "set.importNote": "Imported settings are staged like any other edit — nothing is written until you flash them.", + "set.appearance": "APPEARANCE", + "set.accentTheme": "Accent theme", + "set.accentBody": "Each tile is painted in its own theme.", + "set.glass": "LIQUID GLASS", + "set.glassTitle": "Glass intensity", + "set.glassBody": "Dial the frosted material from fully transparent panels to the full acrylic finish.", "set.transparent": "Transparent", - "set.acrylic": "Acrylique", - "set.language": "LANGUE", - "set.languageTitle": "Langue", - "set.languageBody": "Choisissez la langue de l'interface. Les messages de l'appareil restent en anglais pour l'instant.", + "set.acrylic": "Acrylic", + "set.language": "LANGUAGE", + "set.languageTitle": "Language", + "set.languageBody": "Choose the interface language. Device messages stay English for now.", "set.english": "English", "set.portuguese": "Português", "set.spanish": "Español", From e6131789a4bc8441bfae20d63f7f11c998efcd80 Mon Sep 17 00:00:00 2001 From: snekxs <26660858+snekxs@users.noreply.github.com> Date: Thu, 24 Sep 2026 01:40:30 -0600 Subject: [PATCH 3/4] Complete Arabic locale: native translation and RTL layout - Replace the French-derived i18n-ar.ts with a full native Arabic table covering all 1050 current keys, matching the English key set and placeholder set exactly. - Mirror the layout for right-to-left: set dir="rtl" on when the locale is Arabic, and convert direction-sensitive CSS to logical properties (margin/border/padding-inline, inset-inline, logical corner radii, text-align start/end) so spacing and borders flip automatically. Add [dir=rtl] overrides for transform-based direction (toggles, nav chevrons, expand chevron). - Add the missing 'ar' entry to the html lang map. - Drop the unrelated esbuild entry under allowScripts. --- package.json | 3 - src/app/App.tsx | 6 + src/control.css | 149 ++-- src/i18n-ar.ts | 1966 ++++++++++++++++++++++++----------------------- 4 files changed, 1104 insertions(+), 1020 deletions(-) diff --git a/package.json b/package.json index fd91da49..b98fbbcd 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,5 @@ "devDependencies": { "typescript": "^5.8.3", "vite": "^6.3.5" - }, - "allowScripts": { - "esbuild@0.25.12": true } } diff --git a/src/app/App.tsx b/src/app/App.tsx index 752cca6a..cf685cee 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -67,12 +67,18 @@ export function App(): ReactNode { ko: "ko", ru: "ru", vi: "vi", + ar: "ar", en: "en", }; const nextLang = htmlLang[locale] ?? "en"; if (document.documentElement.lang !== nextLang) { document.documentElement.lang = nextLang; } + // Arabic reads right-to-left; every other locale is left-to-right. + const nextDir = locale === "ar" ? "rtl" : "ltr"; + if (document.documentElement.dir !== nextDir) { + document.documentElement.dir = nextDir; + } } catch { /* non-DOM environment (tests) */ } diff --git a/src/control.css b/src/control.css index 522e021a..48fb7354 100644 --- a/src/control.css +++ b/src/control.css @@ -239,9 +239,9 @@ button:focus-visible, a:focus-visible, input:focus-visible { outline: 2px solid var(--surface-bg); } /* A thin turquoise-to-pink line tops the sidebar, like a synth readout. */ -.control-shell[data-interface-theme="miku"] .sidebar { border-right-color: color-mix(in srgb, var(--ui-accent) 26%, var(--border)); } +.control-shell[data-interface-theme="miku"] .sidebar { border-inline-end-color: color-mix(in srgb, var(--ui-accent) 26%, var(--border)); } .control-shell[data-interface-theme="miku"] .sidebar::before { - position: absolute; top: 0; right: 0; left: 0; height: 2px; + position: absolute; top: 0; inset-inline-end: 0; inset-inline-start: 0; height: 2px; background: linear-gradient(90deg, transparent, var(--ui-accent) 32%, var(--ui-accent) 68%, var(--miku-pink)); content: ""; opacity: .85; pointer-events: none; } @@ -612,7 +612,7 @@ button:focus-visible, a:focus-visible, input:focus-visible { outline: 2px solid .control-shell.sidebar-hidden { grid-template-columns: minmax(0, 1fr); } .control-shell.sidebar-hidden .sidebar { display: none; } -.sidebar { position: sticky; top: 0; display: flex; height: 100vh; flex-direction: column; padding: 1.5rem; border-right: 1px solid var(--line); background: var(--sidebar); } +.sidebar { position: sticky; top: 0; display: flex; height: 100vh; flex-direction: column; padding: 1.5rem; border-inline-end: 1px solid var(--line); background: var(--sidebar); } .control-panel { position: relative; width: min(100% - 4rem, 1180px); margin: 0 auto; padding: 1.5rem 0 2rem; overflow-y: auto; scrollbar-width: none; } .control-panel::-webkit-scrollbar { display: none; width: 0; height: 0; } .panel-top { position: sticky; top: 0; z-index: 5; background: var(--ink); } @@ -623,8 +623,8 @@ button:focus-visible, a:focus-visible, input:focus-visible { outline: 2px solid .demo-wordmark img { width: auto; height: 1.5rem; } .sidebar > .build-badge { margin-top: auto; } .build-badge { color: var(--text-soft); font-family: var(--font-mono); font-size: .64rem; letter-spacing: .06em; white-space: nowrap; } -.demo-wordmark .build-badge { margin-left: .15rem; padding: .12rem .45rem; border: 1px solid var(--border-soft); border-radius: 1rem; background: var(--surface-raised); font-size: .56rem; } -.brand-links { display: flex; align-items: center; gap: .7rem; margin-left: auto; } +.demo-wordmark .build-badge { margin-inline-start: .15rem; padding: .12rem .45rem; border: 1px solid var(--border-soft); border-radius: 1rem; background: var(--surface-raised); font-size: .56rem; } +.brand-links { display: flex; align-items: center; gap: .7rem; margin-inline-start: auto; } .brand-links a { display: flex; color: var(--text-soft); transition: color .18s ease; } .brand-links a:hover { color: var(--ui-accent); } .brand-links svg { width: auto; height: .85rem; } @@ -633,14 +633,14 @@ button:focus-visible, a:focus-visible, input:focus-visible { outline: 2px solid .device-panel { overflow: hidden; border: 1px solid var(--border); border-radius: 10px; background: var(--raised); } .sidebar-device-list { max-height: min(34vh, 15rem); overflow-y: auto; overscroll-behavior: contain; scrollbar-color: var(--border-hover) transparent; scrollbar-width: thin; } -.device-row { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: .7rem; width: 100%; padding: .72rem .78rem; border: 0; border-bottom: 1px solid var(--line); background: transparent; text-align: left; } +.device-row { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: .7rem; width: 100%; padding: .72rem .78rem; border: 0; border-bottom: 1px solid var(--line); background: transparent; text-align: start; } .device-row:hover { background: var(--surface-hover); } .device-row.is-selected { background: var(--ui-accent-soft); } .device-row-copy { display: block; min-width: 0; } .device-row-copy strong { display: block; overflow: hidden; color: var(--bright); font-size: .82rem; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; } .device-row-copy small { display: block; margin-top: .2rem; overflow: hidden; color: var(--muted); font-size: .68rem; text-overflow: ellipsis; white-space: nowrap; } -.device-add { display: block; width: 100%; padding: .68rem .78rem; border: 0; background: transparent; color: var(--muted); text-align: left; font-size: .78rem; font-weight: 600; } -.device-add::before { margin-right: .5rem; color: var(--ui-accent); content: "+"; } +.device-add { display: block; width: 100%; padding: .68rem .78rem; border: 0; background: transparent; color: var(--muted); text-align: start; font-size: .78rem; font-weight: 600; } +.device-add::before { margin-inline-end: .5rem; color: var(--ui-accent); content: "+"; } .device-add:hover { background: var(--surface-hover); color: var(--text-hover); } .device-add:disabled { cursor: wait; opacity: .7; } @@ -656,7 +656,7 @@ nav { display: grid; gap: .3rem; margin-top: 1.4rem; } .nav-item svg { width: 1.05rem; height: 1.05rem; } .nav-item.has-label { width: auto; grid-auto-flow: column; gap: .42rem; padding: 0 .6rem; place-items: center; font-size: .74rem; } .nav-item:hover { background: var(--surface-hover); color: var(--text-hover); } -.nav-item.is-debug { margin-left: auto; } +.nav-item.is-debug { margin-inline-start: auto; } .control-shell .nav-item[aria-current="true"] { background: var(--ui-accent-soft); color: var(--ui-accent); } /* Globe language picker: globe icon opens an upward popup menu. @@ -666,7 +666,7 @@ nav { display: grid; gap: .3rem; margin-top: 1.4rem; } .locale-menu { position: absolute; bottom: calc(100% + .45rem); - left: 0; + inset-inline-start: 0; z-index: 50; display: grid; gap: .15rem; @@ -687,7 +687,7 @@ nav { display: grid; gap: .3rem; margin-top: 1.4rem; } background: transparent; color: var(--dim); font-size: .74rem; - text-align: left; + text-align: start; cursor: pointer; } .locale-menu button:hover { background: var(--surface-hover); color: var(--text-hover); } @@ -770,7 +770,7 @@ nav { display: grid; gap: .3rem; margin-top: 1.4rem; } .gamereq-chip { justify-self: start; padding: .4rem .85rem; border: 0; border-radius: 999px; background: var(--ui-accent-soft); color: var(--bright); font-size: .75rem; font-weight: 650; cursor: pointer; } .gamereq-chip:hover { background: var(--hover); } .gamereq-apps { display: grid; gap: .25rem; max-height: 12rem; margin: 0; padding: 0; list-style: none; overflow-y: auto; } -.gamereq-apps button { display: flex; align-items: center; gap: .6rem; width: 100%; padding: .45rem .55rem; border: 0; border-radius: 8px; background: transparent; color: inherit; text-align: left; cursor: pointer; } +.gamereq-apps button { display: flex; align-items: center; gap: .6rem; width: 100%; padding: .45rem .55rem; border: 0; border-radius: 8px; background: transparent; color: inherit; text-align: start; cursor: pointer; } .gamereq-apps button:hover { background: var(--hover); } .gamereq-apps img, .gamereq-apps svg { flex: 0 0 auto; width: 1.5rem; height: 1.5rem; object-fit: contain; } .gamereq-apps svg { padding: .15rem; box-sizing: border-box; color: var(--muted); } @@ -781,7 +781,7 @@ nav { display: grid; gap: .3rem; margin-top: 1.4rem; } .gamereq-command code { flex: 1; min-width: 0; color: var(--text-input); font-size: .72rem; line-height: 1.55; overflow-wrap: anywhere; white-space: pre-wrap; } .gamereq-command button { display: grid; flex: 0 0 auto; place-items: center; width: 1.9rem; height: 1.9rem; padding: 0; border: 0; border-radius: 6px; background: var(--surface-control); color: var(--dim); cursor: pointer; } .gamereq-command button:hover { background: var(--hover); color: var(--bright); } -.gamereq-embed { display: grid; gap: .75rem; padding: .9rem 1rem; border-left: 4px solid var(--ui-accent); border-radius: 6px; background: var(--surface-control); } +.gamereq-embed { display: grid; gap: .75rem; padding: .9rem 1rem; border-inline-start: 4px solid var(--ui-accent); border-radius: 6px; background: var(--surface-control); } .gamereq-embed-title { margin: 0; color: var(--bright); font-size: .92rem; font-weight: 700; } .gamereq-embed-fields { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .75rem 1rem; } .gamereq-embed-fields > div { display: grid; gap: .2rem; min-width: 0; } @@ -824,7 +824,7 @@ nav { display: grid; gap: .3rem; margin-top: 1.4rem; } .device-status { display: flex; flex: 0 0 auto; align-items: center; gap: .45rem; color: var(--text-soft); font-size: .75rem; white-space: nowrap; } .device-status > .status-dot { width: .45rem; height: .45rem; border-radius: 50%; background: var(--success); } .live-status { display: flex; align-items: center; gap: .5rem; margin: 0 0 .8rem; padding: .55rem .75rem; border: 1px solid var(--line); border-radius: 9px; background: var(--well); color: var(--dim); font-size: .72rem; } -.live-status-share { margin-left: auto; padding: .32rem .65rem; border: 1px solid var(--border-hover); border-radius: 6px; background: var(--surface-strong); color: var(--text-soft); font-size: .68rem; font-weight: 600; cursor: pointer; } +.live-status-share { margin-inline-start: auto; padding: .32rem .65rem; border: 1px solid var(--border-hover); border-radius: 6px; background: var(--surface-strong); color: var(--text-soft); font-size: .68rem; font-weight: 600; cursor: pointer; } .live-status i { width: .38rem; height: .38rem; flex: 0 0 auto; border-radius: 50%; background: var(--success); box-shadow: 0 0 0 3px color-mix(in srgb, var(--success) 10%, transparent); } .sidebar-menu-toggle { display: grid; width: 1.9rem; height: 1.75rem; flex: 0 0 auto; grid-template-rows: repeat(3, 1px); align-content: center; gap: .24rem; padding: .42rem .45rem; border: 1px solid var(--border); border-radius: 6px; background: var(--input); cursor: pointer; } @@ -836,16 +836,16 @@ nav { display: grid; gap: .3rem; margin-top: 1.4rem; } .is-empty .empty-state { display: block; } .control-shell.is-empty .device-data { display: none !important; } .empty-connect-action { width: max-content; margin-top: 1.5rem; padding: .7rem 1rem; border: 1px solid var(--ui-accent); border-radius: 7px; background: var(--ui-accent); color: var(--ui-accent-ink); font-size: .72rem; font-weight: 750; } -.empty-connect-action::before { margin-right: .45rem; content: "+"; } +.empty-connect-action::before { margin-inline-end: .45rem; content: "+"; } .empty-connect-action:hover { background: color-mix(in srgb, var(--ui-accent) 80%, #ffffff); border-color: color-mix(in srgb, var(--ui-accent) 80%, #ffffff); transform: translateY(-1px); } .empty-connect-action:disabled { cursor: wait; opacity: .6; transform: none; } .device-overview { display: grid; grid-template-columns: 1.45fr 1fr; min-height: 330px; overflow: hidden; scroll-margin-top: 1.5rem; border: 1px solid var(--border); border-radius: 14px; background: var(--card); } -.device-overview .device-thumbnail { display: flex; overflow: hidden; align-items: center; justify-content: center; padding: .5rem; border-right: 1px solid var(--line-soft); background: radial-gradient(circle at 50% 45%, var(--surface-hover-soft) 0, var(--surface-menu) 72%); } +.device-overview .device-thumbnail { display: flex; overflow: hidden; align-items: center; justify-content: center; padding: .5rem; border-inline-end: 1px solid var(--line-soft); background: radial-gradient(circle at 50% 45%, var(--surface-hover-soft) 0, var(--surface-menu) 72%); } .device-overview .device-thumbnail[hidden] { display: none; } .device-overview .device-thumbnail img { max-width: 100%; max-height: 100%; object-fit: contain; filter: drop-shadow(0 5px 9px rgb(0 0 0 / 60%)); } -.device-overview .summary-stat { display: flex; min-width: 0; flex-direction: column; justify-content: center; padding: 1.1rem 1.35rem; border-right: 1px solid var(--line-soft); } -.device-overview .summary-stat:last-child { border-right: 0; } +.device-overview .summary-stat { display: flex; min-width: 0; flex-direction: column; justify-content: center; padding: 1.1rem 1.35rem; border-inline-end: 1px solid var(--line-soft); } +.device-overview .summary-stat:last-child { border-inline-end: 0; } .device-overview .summary-stat > span { margin-bottom: .45rem; color: var(--text-soft); font-family: var(--font-mono); font-size: .64rem; letter-spacing: .09em; } .device-overview .summary-stat strong { font-size: 1.3rem; font-weight: 500; letter-spacing: -.025em; } .device-overview .summary-stat small { margin-top: .2rem; color: var(--faint); font-size: .68rem; } @@ -871,10 +871,10 @@ nav { display: grid; gap: .3rem; margin-top: 1.4rem; } .setting-card button:disabled { cursor: default; opacity: 1; } .dpi-card { grid-row: span 2; } .dpi-card.has-lift-off { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); gap: 1.1rem; } -.dpi-card.has-lift-off > .dpi-card-lift { padding-left: 1.1rem; border-left: 1px solid var(--line-soft); } +.dpi-card.has-lift-off > .dpi-card-lift { padding-inline-start: 1.1rem; border-inline-start: 1px solid var(--line-soft); } @media (max-width: 980px) { .dpi-card.has-lift-off { grid-template-columns: minmax(0, 1fr); } - .dpi-card.has-lift-off > .dpi-card-lift { padding-left: 0; padding-top: .9rem; border-left: 0; border-top: 1px solid var(--line-soft); } + .dpi-card.has-lift-off > .dpi-card-lift { padding-inline-start: 0; padding-top: .9rem; border-inline-start: 0; border-top: 1px solid var(--line-soft); } } .setting-heading { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 2rem; } .setting-heading.compact { margin-bottom: .55rem; } @@ -938,9 +938,9 @@ nav { display: grid; gap: .3rem; margin-top: 1.4rem; } .lighting-strip { display:grid;grid-template-columns:repeat(auto-fit,minmax(2.6rem,4rem));gap:.3rem;align-items:center } .lighting-strip.is-lightstrip { grid-template-columns:1.15fr repeat(8,1fr) } .lighting-strip button { position:relative;min-width:0;height:2.2rem;padding:0;border:1px solid color-mix(in srgb,var(--zone-color) 45%,var(--border));border-radius:7px;background:color-mix(in srgb,var(--zone-color) 74%,#090b0d);color:#fff;font-family:var(--font-mono);font-size:.52rem;box-shadow:inset 0 0 14px color-mix(in srgb,var(--zone-color) 50%,transparent);cursor:pointer } -.lighting-strip.is-lightstrip button:first-child { margin-right:.2rem;background:var(--surface-control);box-shadow:none;color:var(--muted) } +.lighting-strip.is-lightstrip button:first-child { margin-inline-end:.2rem;background:var(--surface-control);box-shadow:none;color:var(--muted) } .lighting-strip button:hover,.lighting-strip button.is-selected { border-color:var(--ui-accent);outline:1px solid color-mix(in srgb,var(--ui-accent) 35%,transparent);outline-offset:1px } -.lighting-strip button.is-selected::after { position:absolute;right:25%;bottom:-.48rem;left:25%;height:2px;border-radius:2px;background:var(--ui-accent);content:"" } +.lighting-strip button.is-selected::after { position:absolute;inset-inline-end:25%;bottom:-.48rem;inset-inline-start:25%;height:2px;border-radius:2px;background:var(--ui-accent);content:"" } @media (max-width:760px) { .lighting-zone-picker { grid-template-columns:1fr }.lighting-strip { overflow-x:auto }.lighting-strip.is-lightstrip { grid-template-columns:3.5rem repeat(8,minmax(2.2rem,1fr)) } } .dpi-header-actions { display: flex; align-items: center; gap: .45rem; } @@ -977,7 +977,7 @@ nav { display: grid; gap: .3rem; margin-top: 1.4rem; } .angle-tuning-readonly output { color: var(--text-input); font-family: var(--font-mono); } .angle-tuning-control { margin-top: .55rem; padding-top: .55rem; border-top: 1px solid var(--line); } .angle-tuning-head { display: flex; align-items: baseline; justify-content: space-between; gap: .75rem; color: var(--dim); font-size: .7rem; } -.angle-tuning-head output { min-width: 2.8rem; color: var(--text-input); font: 650 .72rem var(--font-mono); text-align: right; } +.angle-tuning-head output { min-width: 2.8rem; color: var(--text-input); font: 650 .72rem var(--font-mono); text-align: end; } .angle-tuning-inputs { display: grid; grid-template-columns: 1.65rem minmax(7rem, 1fr) 1.65rem; align-items: center; gap: .5rem; margin-top: .35rem; } .angle-tuning-inputs button { width: 1.65rem; height: 1.65rem; padding: 0; border: 1px solid var(--border); border-radius: 6px; background: var(--surface-strong); color: var(--text-input); font-size: .9rem; line-height: 1; cursor: pointer; } .angle-tuning-inputs button:hover:not(:disabled) { border-color: var(--ui-accent); color: var(--ui-accent); } @@ -995,7 +995,7 @@ nav { display: grid; gap: .3rem; margin-top: 1.4rem; } .egg-collapsible summary::-webkit-details-marker, .egg-experimental summary::-webkit-details-marker { display: none; } .egg-collapsible summary span small { display: block; margin-bottom: .12rem; color: var(--faint); font-family: var(--font-mono); font-size: .5rem; letter-spacing: .09em; } .egg-experimental summary small { display: block; margin-bottom: .18rem; color: color-mix(in srgb, var(--warning) 82%, var(--text-soft)); font-family: var(--font-mono); font-size: .52rem; letter-spacing: .09em; } -.egg-collapsible summary i, .egg-experimental summary i { border-right: 1px solid var(--text-soft); border-bottom: 1px solid var(--text-soft); transform: rotate(45deg); transition: transform .18s ease; } +.egg-collapsible summary i, .egg-experimental summary i { border-inline-end: 1px solid var(--text-soft); border-bottom: 1px solid var(--text-soft); transform: rotate(45deg); transition: transform .18s ease; } .egg-collapsible summary i { width: .42rem; height: .42rem; } .egg-experimental summary i { width: .45rem; height: .45rem; } .egg-collapsible[open] summary i, .egg-experimental[open] summary i { transform: rotate(225deg); } @@ -1113,7 +1113,7 @@ nav { display: grid; gap: .3rem; margin-top: 1.4rem; } flex: 0 0 auto; align-items: center; gap: 0.5rem; - margin-left: auto; + margin-inline-start: auto; } .apply-bar-actions button { display: inline-flex; @@ -1216,7 +1216,7 @@ nav { display: grid; gap: .3rem; margin-top: 1.4rem; } .news-banner a.news-banner-link:hover { text-decoration: underline; } .news-banner-dismiss { flex: 0 0 auto; - margin-left: auto; + margin-inline-start: auto; padding: 0.1rem 0.4rem; border: 0; border-radius: 6px; @@ -1447,7 +1447,7 @@ body { height: 100vh; overflow: hidden; } .sidebar-battery { display: flex; align-items: center; gap: .35rem; } .sidebar-battery::before { color: var(--ghost); content: "·"; } .sidebar-battery .battery-icon { width: 1.45rem; } -#sidebar-battery-value { min-width: 2.4em; color: var(--text-strong); text-align: left; font-variant-numeric: tabular-nums; } +#sidebar-battery-value { min-width: 2.4em; color: var(--text-strong); text-align: start; font-variant-numeric: tabular-nums; } .control-shell:not(.is-empty) .sidebar-product-status .status-dot { background: var(--ui-accent); box-shadow: 0 0 0 3px var(--ui-accent-soft); } .device-label { margin: auto .35rem .5rem; padding-top: .4rem; } @@ -1544,9 +1544,9 @@ body { height: 100vh; overflow: hidden; } .workspace-tabs button[aria-selected="true"] { color: var(--text-hover); } .workspace-tabs button[aria-selected="true"]::after { position: absolute; - right: .9rem; + inset-inline-end: .9rem; bottom: .12rem; - left: .9rem; + inset-inline-start: .9rem; height: 1px; background: var(--text-hover); content: ""; @@ -1604,7 +1604,7 @@ body { height: 100vh; overflow: hidden; } color: var(--text-hover); font: 500 2.2rem/1 var(--font-sans); letter-spacing: -.04em; - text-align: right; + text-align: end; } .dpi-header-actions button { border-radius: 5px; background: transparent; } .segmented { gap: 0; } @@ -1667,7 +1667,7 @@ body { height: 100vh; overflow: hidden; } .toast-stack { position: fixed; top: 1rem; - right: 1rem; + inset-inline-end: 1rem; z-index: 200; display: flex; width: min(24rem, calc(100vw - 2rem)); @@ -1839,7 +1839,7 @@ body { height: 100vh; overflow: hidden; } } .app-sidebar-brand-version { flex-shrink: 0; - margin-left: auto; + margin-inline-start: auto; white-space: nowrap; color: var(--faint); font-size: 0.78rem; @@ -1883,8 +1883,8 @@ body { height: 100vh; overflow: hidden; } } .app-sidebar-nav-item + .app-sidebar-nav-item { border-top: 1px solid var(--line-strong); - border-top-left-radius: 0; - border-top-right-radius: 0; + border-start-start-radius: 0; + border-start-end-radius: 0; } .app-sidebar-nav-item > .app-sidebar-nav-icon { flex-shrink: 0; @@ -1896,7 +1896,7 @@ body { height: 100vh; overflow: hidden; } flex-shrink: 0; width: 0.85rem; height: 0.85rem; - margin-left: auto; + margin-inline-start: auto; color: var(--ghost); opacity: 0.9; transition: color 0.15s ease, transform 0.15s ease; @@ -1931,7 +1931,7 @@ body { height: 100vh; overflow: hidden; } .app-sidebar-collapse-toggle { position: absolute; top: 50%; - right: -0.875rem; + inset-inline-end: -0.875rem; transform: translateY(-50%); z-index: 30; display: grid; @@ -2094,8 +2094,8 @@ body { height: 100vh; overflow: hidden; } width: 12.5rem; min-width: 0; } -.device-diagram-rail--left { text-align: left; } -.device-diagram-rail--right { text-align: right; } +.device-diagram-rail--left { text-align: start; } +.device-diagram-rail--right { text-align: end; } .device-diagram-canvas { position: relative; flex: 0 0 auto; @@ -2159,13 +2159,13 @@ body { height: 100vh; overflow: hidden; } white-space: nowrap; } .device-diagram-chip--left { - left: auto; - right: 0.4rem; + inset-inline-start: auto; + inset-inline-end: 0.4rem; animation: device-diagram-chip-in-l 0.32s ease both; } .device-diagram-chip--right { - left: 0.4rem; - right: auto; + inset-inline-start: 0.4rem; + inset-inline-end: auto; animation: device-diagram-chip-in-r 0.32s ease both; } .device-diagram-chip-label { @@ -2353,7 +2353,7 @@ body { height: 100vh; overflow: hidden; } background: none; color: inherit; font-family: inherit; - text-align: left; + text-align: start; cursor: pointer; } .games-tile-art { @@ -2383,7 +2383,7 @@ body { height: 100vh; overflow: hidden; } .games-tile-badge { position: absolute; top: 0.5rem; - right: 0.5rem; + inset-inline-end: 0.5rem; padding: 0.15rem 0.5rem; border-radius: 999px; font-size: 0.68rem; @@ -2695,7 +2695,7 @@ body { height: 100vh; overflow: hidden; } .game-profile-toggle-thumb { position: absolute; top: 2px; - left: 2px; + inset-inline-start: 2px; width: 18px; height: 18px; border-radius: 50%; @@ -2802,14 +2802,14 @@ body { height: 100vh; overflow: hidden; } .welcome-aurora i:nth-child(1) { width: 420px; height: 420px; - left: 12%; + inset-inline-start: 12%; top: 8%; background: color-mix(in srgb, var(--ui-accent, #5dde89) 34%, transparent); } .welcome-aurora i:nth-child(2) { width: 380px; height: 380px; - right: 8%; + inset-inline-end: 8%; bottom: 4%; background: color-mix(in srgb, var(--ui-accent, #5dde89) 22%, transparent); animation-delay: -5s; @@ -2817,7 +2817,7 @@ body { height: 100vh; overflow: hidden; } .welcome-aurora i:nth-child(3) { width: 300px; height: 300px; - left: 42%; + inset-inline-start: 42%; bottom: -10%; background: color-mix(in srgb, var(--bright) 14%, transparent); animation-delay: -9s; @@ -3098,7 +3098,7 @@ body { height: 100vh; overflow: hidden; } font-size: 0.88rem; font-weight: 650; position: absolute; - left: 0; + inset-inline-start: 0; transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease; top: 50%; transform: translateY(-50%); @@ -3113,7 +3113,7 @@ body { height: 100vh; overflow: hidden; } as the primary Call-To-Action in accent so the tab still stands out. */ .device-tab-profiles-nav { position: absolute; - right: 0; + inset-inline-end: 0; top: 50%; transform: translateY(-50%); } @@ -3427,7 +3427,7 @@ body { height: 100vh; overflow: hidden; } position: absolute; width: 14px; height: 14px; - left: 2px; + inset-inline-start: 2px; top: 2px; border-radius: 50%; background: var(--muted); @@ -3450,7 +3450,7 @@ body { height: 100vh; overflow: hidden; } padding: 0.1rem 0.45rem; border-radius: 999px; border: 1px solid var(--line); - margin-left: 0.5rem; + margin-inline-start: 0.5rem; color: var(--dim); } .theme-custom-editor { margin-top: 0.75rem; display: flex; flex-direction: column; gap: 0.6rem; } @@ -3518,7 +3518,7 @@ body { height: 100vh; overflow: hidden; } /* OpenMouse AI chat overlay + launcher button. */ .ai-launcher { position: absolute; - right: 1.25rem; + inset-inline-end: 1.25rem; bottom: 1.5rem; z-index: 60; display: inline-flex; @@ -3544,7 +3544,7 @@ body { height: 100vh; overflow: hidden; } .ai-overlay { position: absolute; - right: 1.25rem; + inset-inline-end: 1.25rem; bottom: 5.25rem; z-index: 60; display: flex; @@ -3631,13 +3631,13 @@ body { height: 100vh; overflow: hidden; } align-self: flex-start; background: var(--control); border: 1px solid var(--line); - border-bottom-left-radius: 4px; + border-end-start-radius: 4px; } .ai-message.is-user { align-self: flex-end; background: var(--ui-accent); color: var(--ui-accent-ink); - border-bottom-right-radius: 4px; + border-end-end-radius: 4px; } .ai-typing { display: inline-flex; @@ -3670,7 +3670,7 @@ body { height: 100vh; overflow: hidden; } background: var(--surface-bg-tint); } .ai-options button { - text-align: left; + text-align: start; padding: .55rem .75rem; border: 1px solid var(--line); border-radius: 10px; @@ -3762,8 +3762,8 @@ body { height: 100vh; overflow: hidden; } } .mouse-test-chart { position: absolute; - left: 0; - right: 0; + inset-inline-start: 0; + inset-inline-end: 0; bottom: 0; display: block; width: 100%; @@ -3788,16 +3788,16 @@ body { height: 100vh; overflow: hidden; } letter-spacing: 0.04em; } .mouse-test-chip-left { - left: 0.8rem; + inset-inline-start: 0.8rem; } .mouse-test-chip-right { - right: 0.8rem; + inset-inline-end: 0.8rem; font-variant-numeric: tabular-nums; } .mouse-test-area-note { position: absolute; bottom: 0.8rem; - left: 50%; + inset-inline-start: 50%; transform: translateX(-50%); padding: 0.3rem 0.9rem; border-radius: 999px; @@ -4023,7 +4023,7 @@ body { height: 100vh; overflow: hidden; } .mouse-test-device-val { color: var(--text); font-weight: 600; - text-align: right; + text-align: end; min-width: 0; } .mouse-test-device-val-wrap { @@ -4222,7 +4222,7 @@ body { height: 100vh; overflow: hidden; } text-transform: uppercase; } .hardware-test-terminal-state { - margin-left: auto; + margin-inline-start: auto; font-size: 0.68rem; font-weight: 650; color: var(--dim); @@ -4255,7 +4255,7 @@ body { height: 100vh; overflow: hidden; } .hardware-test-line-at { display: inline-block; min-width: 4.6rem; - margin-right: 0.6rem; + margin-inline-end: 0.6rem; color: var(--muted); user-select: none; font-variant-numeric: tabular-nums; @@ -4273,7 +4273,7 @@ body { height: 100vh; overflow: hidden; } width: 0.55em; height: 1.05em; vertical-align: text-bottom; - margin-left: 2px; + margin-inline-start: 2px; background: var(--text); animation: hardware-test-blink 1s steps(1) infinite; } @@ -4297,7 +4297,7 @@ body { height: 100vh; overflow: hidden; } .hardware-test-summary-fail { color: var(--destructive); } .hardware-test-summary-skip { color: var(--dim); } .hardware-test-summary strong { - margin-left: auto; + margin-inline-start: auto; letter-spacing: 0.03em; } .hardware-test-summary.pass strong { color: var(--success); } @@ -4347,7 +4347,7 @@ body { height: 100vh; overflow: hidden; } filter: brightness(1.12); } .hardware-test-btn-share { - margin-left: auto; + margin-inline-start: auto; background: var(--surface-control); border: 1px solid var(--line-strong); color: var(--text); @@ -4364,3 +4364,16 @@ body { height: 100vh; overflow: hidden; } height: clamp(420px, 58vh, 600px); } } + +/* Right-to-left (Arabic). The stylesheet uses CSS logical properties for + direction-sensitive spacing, borders and offsets, so most of the layout + mirrors on its own once is set. The rules below cover the + cases that cannot be expressed logically — transform-based direction — and + the directional chevron icons. */ +[dir="rtl"] .game-profile-toggle.is-on .game-profile-toggle-thumb { transform: translateX(-18px); } +[dir="rtl"] .switch input:checked + .switch-track::before { transform: translateX(-16px); } +[dir="rtl"] .app-sidebar-nav-arrow { transform: scaleX(-1); } +[dir="rtl"] .app-sidebar-nav-item:hover .app-sidebar-nav-arrow { transform: scaleX(-1) translateX(2px); } +[dir="rtl"] .app-sidebar-collapse-toggle:hover { transform: translateY(-50%) translateX(-2px); } +[dir="rtl"] .egg-collapsible summary i, +[dir="rtl"] .egg-experimental summary i { transform: rotate(-45deg); } diff --git a/src/i18n-ar.ts b/src/i18n-ar.ts index 4663874d..1ccd0b8c 100644 --- a/src/i18n-ar.ts +++ b/src/i18n-ar.ts @@ -3,121 +3,157 @@ import type { I18nKey } from "./i18n.ts"; /** Arabic strings, split into a lazy chunk so the initial bundle ships English only. Loaded via ensureLocale() before first use. */ export const ar: Record = { - "nav.language": "", - "nav.settings": "الاعدادات", + "nav.language": "اللغة", + "nav.settings": "الإعدادات", "nav.support": "الدعم", "nav.supportProject": "ادعم المشروع", - "nav.mouseCheck": "التحقق من الماوس", - "nav.home": "الصفحة الرئيسية", - "nav.dashboard": "اعدادات الماوس", - "nav.feedback": "", - "nav.docs": "Docs", - "nav.supported": "الاجهزة المدعومة", - "nav.whatsNew": "", - "nav.expand": "Expand sidebar", - "nav.collapse": "Collapse sidebar", - "side.selectedDevice": "الجهاز قيد الاستخدام", + "nav.mouseCheck": "فحص الماوس", + "nav.home": "الرئيسية", + "nav.dashboard": "إعداد الماوس", + "nav.feedback": "الملاحظات", + "nav.docs": "المستندات", + "nav.supported": "الأجهزة المدعومة", + "nav.whatsNew": "الجديد", + "nav.games": "الألعاب", + "nav.hardwareTest": "فحص العتاد", + "nav.expand": "توسيع الشريط الجانبي", + "nav.collapse": "طي الشريط الجانبي", + "side.selectedDevice": "الجهاز المحدد", "side.connectedMouse": "الماوس المتصل", "side.connected": "متصل", - "side.connectedDevices": "الاجهزة المتصلة", + "side.connectedDevices": "الأجهزة المتصلة", "bridge.title": "OpenMouse Bridge", "bridge.connected": "متصل", - "bridge.games": "الالعاب", - "bridge.profileEnabled": "الاختيار الداتي مفعل", - "bridge.profileEnabledDetail": "Bridge will push this profile to your mouse the moment {name} launches.", - "bridge.profileUpdated": "Profile updated", - "bridge.profileUpdatedDetail": "Bridge will apply the new settings the next time {name} is in the foreground.", - "bridge.profileDisabled": "Automatic apply turned off", - "bridge.profileDisabledDetail": "{name} will no longer get this profile pushed to it.", - "bridge.profileSaveFailed": "Could not reach OpenMouse Bridge", - "bridge.profileSaveFailedDetail": "Check that Bridge is still running, then try again.", - "bridge.profileAppliedHere": "خيار اللعب المفعل", - "bridge.profileRestored": "تم استرجاع اعداداتك السابقة", - "panel.overline": "DEVICE CONTROL", - "panel.connectMouse": "توصيل الموس", - "panel.shareProfile": "Share profile", - "panel.deviceSections": "Device sections", - "empty.previewsTitle": "Driver previews", - "empty.title": "اوصل جهازك.", - "empty.previewsBody": "عرض اي برنامجتشغيل مدعوم بدون الاجهزة المرتبطة به", - "empty.body": "اختر الماوس في نافذة المطالبة التي تظهر في المتصفح لضبط إعداداته المدمجة.", - "tab.overview": "نضرة عامة", - "tab.performance": "الاداء", - "tab.buttons": "الازرار", - "tab.profiles": "", - "tab.advanced": "الاعدادات المتقدمة", - "tab.lighting": "الاضاءة", + "games.subtitle": "اختر لعبة لتمنحها إعدادات ماوس خاصة بها — تُطبَّق فور تشغيل اللعبة.", + "games.autoApply": "تلقائي", + "games.settings": "الإعدادات", + "games.settingsHint": "تُحفظ في ملف هذه اللعبة فقط. يحتفظ ماوسك بإعداداته الحالية حتى تشغيل {name}، ثم يستعيدها عند إغلاقها.", + "games.changedCount": "إعدادات مخصّصة لهذه اللعبة: {n}", + "games.noChanges": "يستخدم إعدادات ماوسك الحالية", + "games.connectTarget": "وصّل {name} لتعديل إعداداته لهذه اللعبة.", + "games.noTarget": "اختر جهازًا مستهدفًا لتعديل إعدادات هذه اللعبة.", + "bridge.profileEnabled": "تم تفعيل التطبيق التلقائي", + "bridge.profileEnabledDetail": "سيدفع Bridge هذا الملف إلى ماوسك فور تشغيل {name}.", + "bridge.profileUpdated": "تم تحديث الملف", + "bridge.profileUpdatedDetail": "سيطبّق Bridge الإعدادات الجديدة في المرة التالية التي يكون فيها {name} في المقدمة.", + "bridge.profileDisabled": "تم إيقاف التطبيق التلقائي", + "bridge.profileDisabledDetail": "لن يُدفع هذا الملف إلى {name} بعد الآن.", + "bridge.profileSaveFailed": "تعذّر الوصول إلى OpenMouse Bridge", + "bridge.profileSaveFailedDetail": "تأكد من أن Bridge ما زال يعمل، ثم حاول مرة أخرى.", + "bridge.profileAppliedHere": "ملف اللعبة المطبَّق", + "bridge.profileRestored": "تمت استعادة إعدادات ماوسك السابقة", + "panel.overline": "التحكم بالجهاز", + "panel.connectMouse": "توصيل ماوس", + "panel.shareProfile": "مشاركة الملف", + "panel.deviceSections": "أقسام الجهاز", + "empty.previewsTitle": "معاينات التعريف", + "empty.title": "وصّل جهازك.", + "empty.previewsBody": "اعرض أي تعريف مدعوم بدون عتاده:", + "empty.body": "اختر ماوسك في نافذة المتصفح لضبط إعداداته المدمجة.", + "tab.overview": "نظرة عامة", + "tab.performance": "الأداء", + "tab.buttons": "الأزرار", + "tab.profiles": "الملفات", + "tab.advanced": "متقدم", + "tab.lighting": "الإضاءة", "ov.battery": "البطارية", - "ov.firmware": "FIRMWARE", - "ov.fwSingle": "Firmware reported by mouse", - "ov.fwNone":"ليسة مبلغة", - "ov.connection": "CONNECTION", - "ov.connReceiver": "موصل ال2.4", + "ov.firmware": "البرنامج الثابت", + "ov.fwSingle": "البرنامج الثابت المُبلَّغ من الماوس", + "ov.fwNone": "غير مُبلَّغ", + "ov.connection": "الاتصال", + "ov.connReceiver": "مستقبل 2.4 GHz", "ov.conn24": "2.4 GHz", - "ov.profile": "Profile", - "ov.led": "LED الموصل", + "ov.profile": "الملف", + "ov.led": "مؤشر المستقبل", "ov.on": "تشغيل", - "ov.off": "ايقاف", - "test.title": "معدل التجميع", - "test.subtitle": "حرك الموس في دوائر صغيرة لقيا معدل التجميع الفعلي", - "test.movePrompt": "حرك الموس هنا للتاكد من وجود حركة", - "test.ready": "Ready", + "ov.off": "إيقاف", + "test.title": "اختبار معدل استقصاء الماوس", + "test.subtitle": "حرّك ماوسك في دوائر صغيرة لقياس معدل الاستقصاء الفعلي.", + "test.movePrompt": "حرّك ماوسك هنا لاكتشاف الحركة", + "test.ready": "جاهز", "test.getReady": "استعد…", - "test.sampling": "… أخذ العينات", - "test.areaNote": "حرك الموس بسلاسة اثناء العد التنازلي و اثناء اخد العينات.", - "test.complete": "انتهى الاختبار", - "test.start": "ابدا الاختبار", - "test.reset": "اعادة تعيين", + "test.sampling": "جارٍ أخذ العينات…", + "test.areaNote": "استمر في التحريك بسلاسة أثناء العد التنازلي وأخذ العينات.", + "test.complete": "اكتمل الاختبار", + "test.start": "ابدأ الاختبار", + "test.reset": "إعادة تعيين", "test.avgHz": "المتوسط", - "test.peakHz": "اقصى حد", - "test.low5": "5% كحد ادنى ", - "test.stability": "التوازن", - "test.jitter": "Jitter", - "test.dropouts": "Dropouts", - "test.events": "Events", - "test.avgInterval": "Avg interval", + "test.peakHz": "الذروة", + "test.low5": "أدنى 5%", + "test.stability": "الاستقرار", + "test.jitter": "الاهتزاز", + "test.dropouts": "الانقطاعات", + "test.events": "الأحداث", + "test.avgInterval": "متوسط الفاصل", "test.deviceInfo": "معلومات الجهاز", - "test.deviceName": "Device", - "test.connection": "Connection", - "test.reportedHz": "Reported polling rate", + "test.deviceName": "الجهاز", + "test.connection": "الاتصال", + "test.reportedHz": "معدل الاستقصاء المُبلَّغ", "test.dpi": "DPI", - "test.dpiStages": "DPI stages", - "test.battery": "Battery", - "test.firmware": "Firmware", - "test.noDevice": "No device connected. Test your polling rate anyway, or open Mouse Config to connect.", - "test.buttonTest": "BUTTON TEST", - "test.buttonHint": "Click any mouse button to see it light up here.", - "test.btn.left": "Left", - "test.btn.right": "Right", - "test.btn.middle": "Middle", - "test.btn.back": "Back", - "test.btn.forward": "Forward", - "set.title": "Settings", - "set.back": "Back to device", - "set.profiles": "PROFILES", - "set.profileKey": "Profile key", - "set.profileKeyBody": "A copy-paste key that carries this mouse's settings to another unit of the same model. Paste it into Settings there to load the same setup.", - "set.yourKey": "Your key", - "set.noKey": "Connect a mouse to generate a key.", - "set.copyKey": "Copy key", - "set.copied": "Copied", - "set.importKey": "Import a key", - "set.importPlaceholder": "Paste a profile key here…", - "set.import": "Import", - "set.soundTitle": "Sound", - "set.soundDescription": "Enable sounds like mouse clicks and new connections", - "set.importNote": "Imported settings are staged like any other edit — nothing is written until you flash them.", - "set.appearance": "APPEARANCE", - "set.accentTheme": "Accent theme", - "set.accentBody": "Each tile is painted in its own theme.", - "set.glass": "LIQUID GLASS", - "set.glassTitle": "Glass intensity", - "set.glassBody": "Dial the frosted material from fully transparent panels to the full acrylic finish.", - "set.transparent": "Transparent", - "set.acrylic": "Acrylic", - "set.language": "LANGUAGE", - "set.languageTitle": "Language", - "set.languageBody": "Choose the interface language. Device messages stay English for now.", + "test.dpiStages": "مراحل DPI", + "test.battery": "البطارية", + "test.firmware": "البرنامج الثابت", + "test.noDevice": "لا يوجد جهاز متصل. اختبر معدل الاستقصاء على أي حال، أو افتح إعداد الماوس للاتصال.", + "test.buttonTest": "اختبار الأزرار", + "test.buttonHint": "انقر أي زر في الماوس لتراه يضيء هنا.", + "test.btn.left": "يسار", + "test.btn.right": "يمين", + "test.btn.middle": "أوسط", + "test.btn.back": "رجوع", + "test.btn.forward": "تقدّم", + "hw.title": "فحص العتاد", + "hw.subtitle": "يشغّل مجموعة التحقق الكاملة من التعريف على الماوس المتصل — وهي الأدلة المستخدمة لنقل طراز يحتاج اختبارًا إلى مدعوم في صفحة الأجهزة المدعومة.", + "hw.start": "ابدأ الفحص", + "hw.end": "إنهاء الفحص", + "hw.share": "مشاركة التقرير", + "hw.connect": "توصيل جهاز", + "hw.ready": "اضغط ابدأ الفحص لتشغيل مجموعة التحقق على الماوس المتصل.", + "hw.noDevice": "لا يوجد ماوس متصل", + "hw.noDeviceDetail": "وصّل ماوسًا لتشغيل اختبارات العتاد.", + "hw.deviceCard": "الجهاز", + "hw.termTitle": "طرفية الفحص", + "hw.identity": "VID / PID", + "hw.transport": "النقل", + "hw.driver": "التعريف", + "hw.rates": "المعدلات المدعومة", + "hw.lod": "مسافة الرفع", + "hw.mode": "وضع الجهاز", + "hw.receiver": "المستقبل", + "hw.signal": "الإشارة", + "hw.interfaces": "الواجهات", + "hw.verdictPass": "نجاح — اجتازت جميع الفحوص", + "hw.verdictFail": "فشل — فشل فحص واحد أو أكثر", + "hw.verdictIncomplete": "غير مكتمل — أُوقف الفحص مبكرًا", + "hw.reportSent": "تم إرسال التقرير", + "hw.reportSentDetail": "أُرسلت نتائج فحص العتاد إلى قناة ملاحظات OpenMouse.", + "hw.reportError": "تعذّر إرسال التقرير", + "hw.reportErrorDetail": "مرحّل الملاحظات غير متاح الآن — حاول بعد لحظات.", + "set.title": "الإعدادات", + "set.back": "العودة إلى الجهاز", + "set.profiles": "الملفات", + "set.profileKey": "مفتاح الملف", + "set.profileKeyBody": "مفتاح للنسخ واللصق ينقل إعدادات هذا الماوس إلى وحدة أخرى من الطراز نفسه. الصقه في الإعدادات هناك لتحميل الإعداد نفسه.", + "set.yourKey": "مفتاحك", + "set.noKey": "وصّل ماوسًا لإنشاء مفتاح.", + "set.copyKey": "نسخ المفتاح", + "set.copied": "تم النسخ", + "set.importKey": "استيراد مفتاح", + "set.importPlaceholder": "الصق مفتاح ملف هنا…", + "set.import": "استيراد", + "set.soundTitle": "الصوت", + "set.soundDescription": "تفعيل أصوات مثل نقرات الماوس والاتصالات الجديدة", + "set.importNote": "تُدرج الإعدادات المستوردة كأي تعديل آخر — لا يُكتب شيء حتى تثبّتها.", + "set.appearance": "المظهر", + "set.accentTheme": "سمة التمييز", + "set.accentBody": "كل بلاطة مصبوغة بسمتها الخاصة.", + "set.glass": "الزجاج السائل", + "set.glassTitle": "كثافة الزجاج", + "set.glassBody": "اضبط المادة الضبابية من لوحات شفافة تمامًا إلى لمسة الأكريليك الكاملة.", + "set.transparent": "شفاف", + "set.acrylic": "أكريليك", + "set.language": "اللغة", + "set.languageTitle": "اللغة", + "set.languageBody": "اختر لغة الواجهة. تبقى رسائل الجهاز بالإنجليزية حاليًا.", "set.english": "English", "set.portuguese": "Português", "set.spanish": "Español", @@ -128,625 +164,658 @@ export const ar: Record = { "set.korean": "한국어", "set.russian": "Русский", "set.vietnamese": "Tiếng Việt", - "set.arabic" : "العربيّة", - "set.motion": "MOUVEMENT", - "set.animations": "Animations", - "set.animationsBody": "Active les transitions de l'interface et les changements d'état animés.", - "set.enableAnimations": "Activer les animations", - "set.writes": "ÉCRITURES", - "set.instantFlash": "Gravure instantanée", - "set.instantFlashBody": "Écrit chaque modification sur la souris dès que vous la faites, au lieu de la préparer pour la barre de gravure.", - "set.flashImmediately": "Graver immédiatement", - "set.sections": "SECTIONS", - "set.advancedEditors": "Éditeurs avancés", - "set.advancedEditorsBody": "Choisissez si les sections CPI, mappage des boutons et expérimentales commencent développées.", - "set.expandByDefault": "Développer par défaut", - "set.experimental": "EXPÉRIMENTAL", - "set.experimentalTitle": "Contrôles expérimentaux", - "set.experimentalBody": "Affiche ou masque complètement les contrôles qui peuvent varier selon les versions de firmware.", - "set.showExperimental": "Afficher les réglages expérimentaux", - "set.dev": "DÉVELOPPEMENT", - "set.previewsTitle": "Aperçus des drivers", - "set.previewsBody": "Affiche n'importe quel driver compatible sans son matériel, pour vérifier une modification sur chaque marque. Rien n'est écrit sur un appareil.", - "set.reset": "Réinitialiser les préférences d'interface", - "set.supportTitle": "Soutenir le projet", - "set.supportBody": "OpenMouse est gratuit et open source. Rejoignez la communauté, suivez le projet ou soutenez le travail qui le rend possible.", - "pend.region": "Modifications non enregistrées", - "pend.overline": "EN ATTENTE", - "pend.none": "Aucune modification en attente", - "pend.one": "1 modification non enregistrée", - "pend.many": "modifications non enregistrées", - "pend.idleHint": "Ajustez un réglage pour le prévisualiser avant de l'écrire.", - "pend.revert": "Annuler", - "pend.applying": "Application…", - "pend.apply": "Appliquer les modifications", - "toast.region": "Notifications", - "toast.dismiss": "Ignorer la notification", - "bat.needsCharging": "Besoin de charge", - "bat.full": "Complètement chargée", - "bat.untilFull": "avant charge complète", - "bat.remaining": "restant", - "bat.charging": "En charge", - "bat.chargingSlowly": "Charge lente", - "bat.almostFull": "Presque pleine", - "bat.fullState": "Pleine", - "bat.discharging": "En décharge", - "bat.unknown": "Inconnu", - "fb.title": "Envoyer un retour", - "fb.description": "Partagez un rapport de bug, une demande de fonctionnalité ou toute autre note. Le retour est envoyé de façon anonyme : rien n'est joint sauf si vous l'activez ci-dessous.", - "fb.placeholder": "Écrivez votre retour ici…", - "fb.handleLabel": "Pseudo Discord (facultatif)", + "set.arabic": "العربية", + "set.motion": "الحركة", + "set.animations": "الرسوم المتحركة", + "set.animationsBody": "تفعيل انتقالات الواجهة وتغيّرات الحالة المتحركة.", + "set.enableAnimations": "تفعيل الرسوم المتحركة", + "set.writes": "الكتابة", + "set.instantFlash": "التثبيت الفوري", + "set.instantFlashBody": "اكتب كل تغيير إلى الماوس فور إجرائه، بدلًا من تجهيزه لشريط التثبيت.", + "set.flashImmediately": "ثبّت فورًا", + "set.sections": "الأقسام", + "set.advancedEditors": "المحررات المتقدمة", + "set.advancedEditorsBody": "اختر ما إذا كانت أقسام CPI وربط الأزرار والتجريبية تبدأ موسّعة.", + "set.expandByDefault": "توسيع افتراضيًا", + "set.experimental": "تجريبي", + "set.experimentalTitle": "عناصر تحكم تجريبية", + "set.experimentalBody": "إظهار أو إخفاء عناصر التحكم التي قد تختلف بين إصدارات البرنامج الثابت.", + "set.showExperimental": "إظهار الإعدادات التجريبية", + "set.dev": "التطوير", + "set.previewsTitle": "معاينات التعريف", + "set.previewsBody": "اعرض أي تعريف مدعوم بدون عتاده، لفحص تغيير مقابل كل علامة تجارية. لا يُكتب شيء إلى أي جهاز.", + "set.reset": "إعادة تعيين تفضيلات الواجهة", + "set.supportTitle": "ادعم المشروع", + "set.supportBody": "OpenMouse مجاني ومفتوح المصدر. انضم إلى المجتمع، تابع المشروع، أو ادعم العمل الذي يقف خلفه.", + "pend.region": "تغييرات غير محفوظة", + "pend.overline": "قيد الانتظار", + "pend.none": "لا تغييرات معلّقة", + "pend.one": "تغيير واحد غير محفوظ", + "pend.many": "تغييرات غير محفوظة", + "pend.idleHint": "اضبط إعدادًا لمعاينته قبل الكتابة.", + "pend.revert": "تراجع", + "pend.applying": "جارٍ التطبيق…", + "pend.apply": "تطبيق التغييرات", + "toast.region": "الإشعارات", + "toast.dismiss": "تجاهل الإشعار", + "bat.needsCharging": "بحاجة للشحن", + "bat.full": "مشحون بالكامل", + "bat.untilFull": "حتى الامتلاء", + "bat.remaining": "متبقٍ", + "bat.charging": "جارٍ الشحن", + "bat.chargingSlowly": "شحن بطيء", + "bat.almostFull": "شبه ممتلئ", + "bat.fullState": "ممتلئ", + "bat.discharging": "قيد التفريغ", + "bat.unknown": "غير معروف", + "fb.title": "إرسال ملاحظات", + "fb.description": "شارك تقرير خطأ أو طلب ميزة أو أي ملاحظة أخرى. تُرسل الملاحظات بشكل مجهول — لا يُرفق شيء إلا إذا فعّلت ذلك أدناه.", + "fb.placeholder": "اكتب ملاحظاتك هنا…", + "fb.handleLabel": "معرّف Discord (اختياري)", "fb.handlePlaceholder": "username", - "fb.attachLabel": "Joindre les détails de l'appareil et le journal de diagnostic", - "fb.attachDetail": "Ajoute les informations de votre appareil et le trafic WebHID récent pour que nous puissions déboguer plus vite.", - "fb.send": "Envoyer le retour", - "fb.sent": "Retour envoyé", - "fb.sentDetail": "Merci — votre note a été livrée.", - "fb.error": "Impossible d'envoyer le retour", - "fb.errorDetail": "Vérifiez votre connexion et réessayez.", - "fb.cooldown": "Vous pourrez renvoyer un retour dans {seconds}s.", - "fb.limit": "Vous avez atteint la limite de retours pour le moment. Réessayez plus tard.", - "artreq.request": "Proposer une visuelle", - "artreq.title": "Proposer une visuelle", - "artreq.description": "La visuelle de cet appareil est manquante ? Envoyez un découpage vu de dessus et nous le vérifierons. Rien n'est publié directement : votre image part à notre équipe pour validation.", - "artreq.deviceLabel": "Appareil", - "artreq.drop": "Glissez votre visuelle ici ou cliquez pour sélectionner", - "artreq.hint": "PNG/WebP · fond transparent ou blanc pur · rendu de dessus du périphérique uniquement · 5 Mo max", - "artreq.noteLabel": "Note (facultatif)", - "artreq.notePlaceholder": "Lien source, page produit ou toute info utile à la vérification…", - "artreq.send": "Envoyer la demande", - "artreq.sent": "Demande de visuelle envoyée", - "artreq.sentDetail": "Notre équipe la vérifiera et publiera la visuelle une fois validée.", - "artreq.error": "Impossible d'envoyer la demande", - "artreq.errorDetail": "Vérifiez votre connexion et réessayez.", - "artreq.sizeError": "L'image est trop lourde. 5 Mo max.", - "artreq.typeError": "Choisissez une image PNG ou WebP.", - "artreq.screened": "Les envois sont automatiquement contrôlés pour détecter tout contenu inapproprié.", - "artreq.rejected": "Cette image ne peut pas être envoyée.", - "artreq.rejectedInvalid": "Ce fichier n'est pas une image PNG ou WebP valide.", - "artreq.rejectedNsfw": "Contenu inapproprié détecté (NSFW).", - "artreq.rejectedHate": "Contenu haineux ou abusif détecté.", - "artreq.rejectedGore": "Contenu graphique ou violent détecté.", - "artreq.rejectedJunk": "Cela ne ressemble pas à un visuel d'appareil. Envoyez un découpage du produit vu du dessus.", - "artreq.rejectedNotArtwork": "Ce n'est pas un visuel de souris — envoyez un rendu/découpe du périphérique vu de dessus, sans rien d'autre dans le cadre.", - "artreq.rejectedPhoto": "Cela ressemble à une photo, pas à un rendu — seuls les rendus ou découpes numériques vus de dessus sont acceptés.", - "artreq.rejectedBackground": "L'arrière-plan doit être transparent ou blanc pur — pas de scène, de bureau, de dégradé ni d'ombre.", - "artreq.rejectedUnconfirmed": "La vérification IA n'a pas pu confirmer qu'il s'agit d'un visuel d'appareil valide.", - "artreq.rejectedUnscreened": "La vérification automatique n'est pas disponible pour le moment. Veuillez réessayer plus tard.", - "artreq.lockedTitle": "Trop d'envois rejetés.", - "artreq.lockedBody": "Votre image ne respecte pas les règles du visuel et les envois sont temporairement bloqués. Réessayez dans {minutes} minutes ou ouvrez un ticket manuel sur Discord.", - "artreq.lockedDiscord": "Ouvrir un ticket manuel sur Discord", - "wn.title": "Application de bureau OpenMouse", - "wn.body": "Désormais disponible en alpha : l'application de bureau OpenMouse. Utilisez OpenMouse comme une app installable — sans garder un onglet de navigateur ouvert. Elle inclut l'accès HID natif, des profils de jeu et une interface unifiée sur le web et le bureau. Rendez-vous sur notre page de versions pour la télécharger pour votre plateforme.", - "wn.download": "Télécharger pour le bureau", - "wn.close": "Peut-être plus tard", + "fb.attachLabel": "إرفاق تفاصيل الجهاز وسجل التشخيص", + "fb.attachDetail": "يضيف معلومات جهازك وحركة WebHID الأخيرة لنتمكن من تصحيح الأخطاء أسرع. لا يُرسل إلا عند تحديد هذا المربع.", + "fb.send": "إرسال الملاحظات", + "fb.sent": "تم إرسال الملاحظات", + "fb.sentDetail": "شكرًا — تم تسليم ملاحظتك.", + "fb.error": "تعذّر إرسال الملاحظات", + "fb.errorDetail": "تحقق من اتصالك وحاول مرة أخرى.", + "fb.cooldown": "يمكنك إرسال ملاحظات مرة أخرى خلال {seconds} ث.", + "fb.limit": "لقد بلغت حد الملاحظات حاليًا. حاول لاحقًا.", + "artreq.request": "طلب رسمة", + "artreq.title": "طلب رسمة", + "artreq.description": "هل رسمة هذا الجهاز مفقودة؟ أرسل صورة مقصوصة من الأعلى وسنراجعها. لا يُرفع شيء إلى الموقع مباشرة — تذهب صورتك إلى فريقنا للتحقق والنشر.", + "artreq.deviceLabel": "الجهاز", + "artreq.drop": "اسحب رسمتك وأفلتها هنا، أو انقر للاختيار", + "artreq.hint": "PNG/WebP · خلفية شفافة أو بيضاء صافية · عرض للجهاز من الأعلى فقط · 5 ميغابايت كحد أقصى", + "artreq.noteLabel": "ملاحظة (اختياري)", + "artreq.notePlaceholder": "رابط المصدر أو صفحة المنتج أو أي شيء يساعدنا في التحقق…", + "artreq.send": "إرسال الطلب", + "artreq.sent": "تم إرسال طلب الرسمة", + "artreq.sentDetail": "سيراجعها فريقنا وينشر الرسمة بعد التحقق.", + "artreq.error": "تعذّر إرسال الطلب", + "artreq.errorDetail": "تحقق من اتصالك وحاول مرة أخرى.", + "artreq.sizeError": "الصورة كبيرة جدًا. 5 ميغابايت كحد أقصى.", + "artreq.typeError": "يرجى اختيار صورة PNG أو WebP.", + "artreq.screened": "تخضع المرفوعات لفحص تلقائي بحثًا عن محتوى غير لائق.", + "artreq.rejected": "لا يمكن إرسال هذه الصورة.", + "artreq.rejectedInvalid": "هذا الملف ليس صورة PNG أو WebP صالحة.", + "artreq.rejectedNsfw": "تم اكتشاف محتوى غير لائق.", + "artreq.rejectedHate": "تم اكتشاف محتوى كراهية أو مسيء.", + "artreq.rejectedGore": "تم اكتشاف محتوى دموي أو عنيف.", + "artreq.rejectedJunk": "لا تبدو هذه رسمة جهاز. ارفع صورة مقصوصة للمنتج من الأعلى.", + "artreq.rejectedNotArtwork": "هذه ليست رسمة ماوس — أرسل عرضًا أو قصة من الأعلى للجهاز وحده، دون أي شيء آخر في الإطار.", + "artreq.rejectedPhoto": "تبدو هذه صورة فوتوغرافية وليست عرضًا. لا تُقبل إلا العروض أو القصاصات الرقمية من الأعلى.", + "artreq.rejectedBackground": "يجب أن تكون الخلفية شفافة أو بيضاء صافية — بلا مشاهد أو مكاتب أو تدرجات أو ظلال.", + "artreq.rejectedUnconfirmed": "لم يتمكن التحقق بالذكاء الاصطناعي من تأكيد أن هذه رسمة جهاز صالحة.", + "artreq.rejectedUnscreened": "الفحص التلقائي غير متاح الآن. يرجى المحاولة لاحقًا.", + "artreq.lockedTitle": "عدد كبير جدًا من الطلبات المرفوضة.", + "artreq.lockedBody": "لم تستوفِ هذه الصورة إرشادات الرسمة وتم حظر الطلبات مؤقتًا. حاول بعد {minutes} دقيقة، أو افتح تذكرة يدوية على Discord لمراجعة بشرية.", + "artreq.lockedDiscord": "فتح تذكرة يدوية على Discord", + "gamereq.title": "طلب لعبة أو تطبيق", + "gamereq.previewTitle": "راجع طلبك", + "gamereq.description": "تريد ملفًا لشيء غير مُدرَج؟ أخبرنا باسمه وملفه التنفيذي وسنضيفه إلى قائمة Bridge.", + "gamereq.kindLabel": "نوع الطلب", + "gamereq.kindGame": "لعبة", + "gamereq.kindApp": "تطبيق", + "gamereq.nameLabel": "الاسم", + "gamereq.namePlaceholder": "مثال: Hunt: Showdown", + "gamereq.appNamePlaceholder": "مثال: Adobe Premiere Pro", + "gamereq.pathLabel": "مسار الملف التنفيذي", + "gamereq.findTitle": "كيف تجد الملف التنفيذي", + "gamereq.pickRunning": "اختر من التطبيقات قيد التشغيل", + "gamereq.noRunning": "لا يرى Bridge أي تطبيقات قيد التشغيل بمسار معروف. استخدم أمرًا أدناه بدلًا من ذلك.", + "gamereq.cmdWindowsHint": "افتحه أولًا، ثم نفّذ هذا في {shell} وانسخ المسار الظاهر بجانب عنوان نافذته.", + "gamereq.cmdMacHint": "نفّذ هذا في {shell}، ثم انتقل إلى اللعبة أو التطبيق خلال 5 ثوانٍ. سيطبع مسار الملف التنفيذي.", + "gamereq.cmdLinuxHint": "افتحه أولًا، ثم نفّذ هذا في {shell}. يسرد ألعاب Steam/Proton قيد التشغيل؛ انسخ مسار التي تريدها.", + "gamereq.copy": "نسخ الأمر", + "gamereq.explorerTip": "أو في مستكشف الملفات: Shift + النقر بالزر الأيمن على ملف .exe ← نسخ كمسار.", + "gamereq.discordLabel": "اسم مستخدم Discord", + "gamereq.discordInvalid": "أدخل اسم مستخدم Discord (2–32 حرفًا: حروف وأرقام و _ و .).", + "gamereq.preview": "معاينة", + "gamereq.previewDescription": "هذا بالضبط ما سيراه فريقنا. ارجع لتصحيح أي شيء قبل الإرسال.", + "gamereq.alreadySupported": "{name} موجود بالفعل في القائمة. يمكنك إرسال هذا إن لم يتم اكتشافه.", + "gamereq.error": "تعذّر إرسال الطلب.", + "gamereq.edit": "تعديل", + "gamereq.send": "إرسال الطلب", + "gamereq.sent": "تم إرسال الطلب", + "gamereq.sentDetail": "شكرًا! سننظر في إضافة {name} وسنتواصل عبر Discord إن احتجنا شيئًا.", + "gamereq.tile": "طلب لعبة أو تطبيق", + "gamereq.tileHint": "لا ترى لعبتك؟", + "wn.title": "تطبيق OpenMouse لسطح المكتب", + "wn.body": "متاح الآن في نسخة ألفا: تطبيق OpenMouse لسطح المكتب. شغّل OpenMouse عبر تطبيق مستقل قابل للتثبيت — دون الحاجة لإبقاء تبويب المتصفح مفتوحًا. يتضمن وصولًا أصليًا إلى HID وملفات الألعاب وواجهة موحدة على الويب وسطح المكتب. توجّه إلى صفحة الإصدارات لتنزيله لمنصتك.", + "wn.download": "تنزيل لسطح المكتب", + "wn.close": "ربما لاحقًا", "ai.title": "OpenMouse AI", - "ai.subtitle": "Réponses rapides et dépannage", - "ai.greeting": "Salut ! Je suis OpenMouse AI. Choisis un sujet ci-dessous et je t'aiderai à le résoudre.", - "ai.topic1": "Ma souris ne se connecte pas", - "ai.topic1Ans": "Assure-toi que ta souris est branchée (ou que son récepteur est en place) et allumée. Essaie un autre port USB ou une connexion filaire si ta souris le permet. Sous Linux, vérifie que les nœuds de périphériques HID sont lisibles — le README liste les règles udev. Puis appuie sur Connecter et choisis ton périphérique dans l'invite du navigateur.", - "ai.topic2": "Le DPI ou la fréquence d'interrogation ne change pas", - "ai.topic2Ans": "Certaines souris n'acceptent que des valeurs prédéfinies, donc essaie un préréglage si une valeur personnalisée est refusée. Appuie sur Appliquer et laisse l'écriture se terminer avant de toucher autre chose. Si la valeur revient toujours en arrière, ce réglage n'est peut-être pas encore inscriptible sur ta souris.", - "ai.topic3": "L'application ne s'ouvre pas dans mon navigateur", - "ai.topic3Ans": "OpenMouse nécessite WebHID, donc il fonctionne dans Chrome, Edge et autres navigateurs basés sur Chromium. Firefox et Safari ne prennent pas encore en charge WebHID, l'application ne s'y ouvrira donc pas. Essaie la dernière version de Chrome ou Edge.", - "ai.topic4": "Mes paramètres ne sont pas enregistrés", - "ai.topic4Ans": "Les paramètres sont écrits dans le profil stocké de la souris et appliqués sur l'appareil, pas dans le cloud. Après avoir modifié un réglage, appuie sur Appliquer et garde la page ouverte jusqu'à la fin de l'écriture. Si cela revient encore après un redémarrage, ce réglage est peut-être en lecture seule sur ton modèle.", - "ai.other": "Autre chose", - "ai.otherAns": "Pas de souci — passe sur le Discord d'OpenMouse et la communauté t'aidera.", - "ai.joinDiscord": "Rejoindre le Discord", - "conn.add": "Ajouter un appareil", - "conn.addMouse": "Ajouter une souris", - "conn.connecting": "Connexion…", - "conn.preview": "Mode aperçu", - "common.apply": "Appliquer", - "common.custom": "Personnalisé", - "common.current": "Actuel {v}", - "common.staged": "Préparé {v}", - "common.active": "Actif", - "common.close": "Fermer", - "common.back": "Retour", - "common.cancel": "Annuler", - "common.done": "Terminé", - "common.save": "Enregistrer", - "common.on": "Activé", - "common.off": "Désactivé", - "dpi.sensitivity": "Sensibilité", - "dpi.perProfile": "Par profil", - "dpi.value": "Valeur DPI", - "dpi.presets": "Valeurs DPI courantes", - "dpi.presetsInUse": "Préréglages utilisés", - "dpi.slotsInUse": "Emplacements utilisés", - "dpi.slotsCount": "Nombre d'emplacements DPI", - "dpi.startingSlot": "Emplacement de départ", - "dpi.makeStarting": "En faire l'emplacement de départ", - "dpi.slotX": "DPI X de l'emplacement {n}", - "dpi.slotY": "DPI Y de l'emplacement {n}", - "dpi.linkXY": "Lier X et Y de l'emplacement {n}", - "dpi.linkedHint": "X et Y sont liés — cliquez pour les régler séparément", - "dpi.unlinkedHint": "X et Y sont séparés — cliquez pour les lier", - "dpi.slotLiftOff": "Lift-off de l'emplacement {n}", - "dpi.liftOffTitle": "Définir la distance de lift-off", - "dpi.noLiftOff": "Ce format de profil n'a pas de réglage de lift-off", - "dpi.slotReadonly": "Lecture seule : l'écriture des emplacements DPI sur un profil n'est pas encore activée, car la séquence de gravure n'a pas été vérifiée sur du matériel réel.", - "dpi.slotNote": "Chaque emplacement stocke sa propre sensibilité X/Y et son niveau de lift-off. {min}–{max} DPI par pas de {step}. L'emplacement mis en surbrillance est celui sur lequel la souris démarre.", - "dpi.stagesInUse": "Étapes utilisées", - "dpi.stagesCount": "Nombre d'étapes DPI", - "dpi.activeStage": "Étape active", - "dpi.makeActive": "En faire l'étape active", - "dpi.stageDpi": "DPI de l'étape {n}", - "dpi.color": "Couleur", - "dpi.stageColor": "Couleur de l'étape {n}", - "dpi.stageNoteCount": "Préréglages et Personnalisé modifient l'étape en surbrillance. {min}–{max} DPI. Le bouton DPI de la souris parcourt ces étapes.", - "dpi.stageNoteSteps": "Préréglages et Personnalisé modifient l'étape en surbrillance. {min}–{max} DPI par pas de {step}. Le bouton DPI de la souris parcourt les {total} étapes.", - "dpi.stageToggle": "Include this DPI stage", - "dpi.editorCountNote": "One row per DPI stage. Tick a row to include it in the DPI cycle; untick to disable it and keep the value for later. Click a number to make it the starting stage.", - "dpi.editorFixedNote": "One row per DPI stage, {total} fixed. Edit the value or slider to change it. Click a number to make it the active stage.", - "dpi.editorGenericNote": "One row per preset DPI. Tick a row (or click its number) to make it the current DPI; unticked rows are kept as picks for later.", - "dpi.xAxis": "Axe X", - "dpi.yAxis": "Axe Y", - "dpi.viewStages": "Étapes", - "dpi.viewSingle": "Unique", - "dpi.viewSlots": "Emplacements", - "dpi.viewSlotsToggle": "Modifier le DPI en emplacements ou en valeur unique", - "dpi.viewToggle": "Modifier le DPI en étapes ou en valeur unique", - "perf.reportFrequency": "Fréquence de rapport", - "perf.reportRate": "Taux de rapport", - "perf.sharedNote": "Enregistré dans ce profil comme un seul intervalle partagé, jusqu'à {max} Hz.", - "perf.splitNote": "Enregistré dans ce profil, un taux par liaison. Jusqu'à {wireless} Hz sans fil, {wired} Hz par câble.", - "perf.eggNote": "Des taux plus élevés actualisent le mouvement du curseur plus souvent et augmentent la charge de traitement CPU/USB.", - "perf.note": "Des taux plus élevés actualisent le mouvement du curseur plus souvent, mais consomment plus de batterie.", - "perf.allConnections": "Toutes les connexions", - "perf.wired": "Filaire", - "perf.wireless": "Sans fil", - "perf.gamingSurface": "Surface de jeu", - "perf.surfaceNote": "Ajuste le capteur pour les tapis de souris gaming. Auto laisse la souris décider ; désactivez si le suivi se comporte mal sur une surface non gaming.", - "perf.auto": "Auto", - "perf.liftOff": "Distance de lift-off", - "perf.liftOffMode": "Mode de lift-off", - "perf.single": "Unique", - "perf.asymmetric": "Asymétrique", - "perf.liftOffLabel": "Lift-off", - "perf.landing": "Atterrissage", - "perf.lodLow": "Bas", - "perf.lodMedium": "Moyen", - "perf.lodHigh": "Haut", - "perf.lodNeedSurface": "Activez la surface de jeu ou réglez-la sur auto pour ajuster la distance de lift-off.", - "perf.lodNote": "Contrôle jusqu'à quelle hauteur vous pouvez soulever la souris avant l'arrêt du suivi. Des valeurs plus élevées maintiennent le suivi un peu plus longtemps.", - "perf.bunnyHop": "Bunny hop", - "perf.bunnyTime": "Durée du bunny hop en millisecondes", - "perf.bunnyReadonly": "Ce format de profil n'a pas été vérifié sur du matériel réel, il est donc en lecture seule.", - "perf.bunnyNote": "Ignore les clics répétés qui tombent dans cette fenêtre, afin qu'un switch qui rebondit lors d'un spam de clics rapides ne s'enregistre qu'une fois. Des durées plus longues filtrent davantage ; des durées plus courtes laissent passer les vrais clics rapides. {min}–{max} ms par pas de {step}.", - "perf.hybrid": "Hybride", - "perf.opticalOnly": "Optique uniquement", - "perf.lightforceMode": "Mode switch LightForce", - "perf.lightforceNote": "Hybride économise l'énergie en utilisant le contact mécanique et n'active le capteur optique qu'en cas de besoin. Optique uniquement est constant mais consomme plus de batterie.", - "light.receiverTitle": "Éclairage du récepteur", - "light.zoneTitle": "Éclairage {zone}", - "light.writeOnly": "Écriture seule", - "light.rgbPart": "Partie RGB", - "light.rgbParts": "Parties RGB", - "light.stripLeds": "LED du bandeau", - "light.rgbZones": "Zones RGB", - "light.effect": "Effet d'éclairage", - "light.brightness": "Luminosité", - "light.brightnessAria": "Luminosité de l'éclairage", - "light.colour": "Couleur", - "light.colour2": "Couleur 2", - "light.colourAria": "Couleur de l'éclairage", - "light.colour2Aria": "Deuxième couleur de l'éclairage", - "light.speed": "Vitesse de l'effet", - "light.choose": "Choisissez un effet", - "light.writeOnlyNote": "La souris ne peut pas signaler son effet actuel, ceci affiche donc la dernière valeur écrite.", - "light.zoneNote": "Choisit l'effet lumineux de {zone}.", - "mx.haptics": "Retour haptique", - "mx.hapticFeedback": "Retour haptique", - "mx.hapticStrength": "Intensité haptique", - "mx.batterySaving": "Économie de batterie", - "mx.friendlyName": "Nom convivial", - "mx.friendlyNameAria": "Nom convivial de l'appareil", - "mx.stageName": "Nom de l'étape", - "mx.chars": "{n}/{max} caractères", - "mx.ratcheted": "À crans", - "mx.freeSpinning": "Rotation libre", - "mx.wheelMode": "Mode de la molette", - "mx.ratchet": "Crans", - "mx.freespin": "Rotation libre", - "mx.hiRes": "Défilement haute résolution", - "mx.invertVertical": "Inverser le défilement vertical", - "mx.invertThumb": "Inverser la molette du pouce", - "mx.switchThreshold": "Seuil du switch", - "mx.pairedComputers": "Ordinateurs jumelés", - "mx.hostOf": "{a} sur {b}", - "mx.switchConfirm": "Basculer vers l'ordinateur {n} ? La souris se déconnectera immédiatement. Utilisez le bouton sous la souris pour la récupérer.", - "mx.switch": "Basculer", - "mx.remapping": "Réaffectation", - "mx.lockedOne": "{names} est verrouillé par le firmware de la souris et ne peut pas être réaffecté.", - "mx.lockedMany": "{names} sont verrouillés par le firmware de la souris et ne peuvent pas être réaffectés.", - "mx.divertedOne": "{name} est géré par une autre application, donc il ne fait rien ici.", - "mx.divertedMany": "{names} sont gérés par une autre application, donc ils ne font rien ici.", - "mx.restoreHardware": "Restaurer le contrôle matériel", - "adv.sleepMin": "Le délai de veille ne peut pas être inférieur à 1 minute.", - "adv.sleepTimeout": "Délai de mise en veille automatique", - "adv.hours": "Heures", - "adv.minutes": "Minutes", - "adv.seconds": "Secondes", - "adv.signal": "Force du signal", - "adv.signalUnavailable": "Le signal du récepteur n'est pas disponible.", - "adv.signal0": "Très faible", - "adv.signal1": "Faible", - "adv.signal2": "Correct", - "adv.signal3": "Bon", - "adv.signal4": "Excellent", - "adv.signalLevel": "Niveau {n}", - "adv.debounce": "Debounce", - "adv.autoSleep": "Veille automatique", - "adv.lowPower": "Mode basse consommation", - "adv.lowPowerNote": "Ralentit la souris pour économiser la batterie en dessous de ce niveau.", - "adv.lowPowerCeiling": "Indisponible au-dessus de {max} Hz. Réduisez le taux de sondage pour le modifier.", - "adv.processing": "Traitement", - "adv.angleSnapping": "Correction d'angle", - "adv.straightLine": "Correction en ligne droite", - "adv.hyperMode": "Mode hyper", - "adv.turboMode": "Mode turbo", - "adv.buttonCombos": "Combinaisons de boutons", - "adv.ultraRange": "Portée ultra-longue", - "adv.angleTune": "Réglage d'angle", - "adv.highSpeed": "Mode haute vitesse", - "adv.competitive": "Mode compétitif", - "adv.highestPerf": "Performance maximale", - "adv.perfMode": "Mode performance", - "adv.sensorMode": "Mode du capteur", - "adv.ecoNote": "Éco économise l'énergie à 125–1000 Hz sans fil. Élevé utilise le profil de capteur performance.", - "adv.lockedNote": "Verrouillé sur {mode} à {hz} Hz {conn}.", - "adv.duration": "Durée", - "adv.dpiIndicator": "Indicateur DPI", - "adv.effect": "Effet", - "adv.ledOff": "Éteint", - "adv.ledSteady": "Fixe", - "adv.ledBreathing": "Respiration", - "adv.brightness": "Luminosité", - "adv.speed": "Vitesse", - "adv.dpiStageNote": "Utilise la couleur de l'étape DPI active enregistrée par la souris.", - "adv.sensorPerf": "Performance du capteur", - "adv.systemMode": "Mode système", - "adv.opticalNote": "Choisissez le profil de performance et de consommation du capteur. Optical Engine est verrouillé tant que le mode Ultra est actif.", - "adv.clickBehavior": "Comportement du clic", - "adv.clickNote": "HyperClick réduit la latence du clic. Slam-Click contrôle la protection contre les clics déclenchés par impact.", - "adv.dongleTournament": "Dongle et mode tournoi", - "adv.dongleLed": "LED du dongle", - "adv.receiverRapidFire": "Récepteur et tir rapide", - "adv.ledConnectRate": "Connexion et taux d'interrogation", - "adv.ledBatteryStatus": "État de la batterie", - "adv.ledBatteryWarning": "Alerte de batterie", - "adv.fireKeyTimes": "Clics par appui", - "adv.fireKeyHold": "Maintenir pour tirer", - "adv.fireKeyInterval": "Intervalle (ms)", - "adv.batteryIndicator": "Indicateur de batterie", - "adv.solidWhite": "Blanc fixe", - "adv.tournamentScroll": "Défilement tournoi", - "adv.scrollUp": "Défiler vers le haut", - "adv.scrollDown": "Défiler vers le bas", - "adv.bothDirections": "Les deux directions", - "adv.passthrough": "Fenêtre de passage", - "adv.oneSecond": "1 seconde", - "adv.halfSeconds": "1,5 seconde", - "adv.filters": "Filtres", - "adv.slamclickFilter": "Filtre slamclick", - "adv.jitterFilter": "Filtre de vibration de mouvement", - "adv.gxMode": "Mode switch GX", - "adv.leftButton": "Bouton gauche", - "adv.rightButton": "Bouton droit", - "adv.dividerTitle": "Diviseur personnalisé", - "adv.dividerWarning": "Les diviseurs de sondage non standard peuvent se comporter différemment selon les versions de firmware.", - "adv.divider8k": "Diviseur 8K", - "adv.dividerResult": "Résultat : {hz} Hz", - "adv.dividerHint": "Entrez un diviseur de 1 à 255.", - "adv.applyDivider": "Appliquer le diviseur", - "adv.cpiStages": "Étapes CPI", - "adv.enabledStages": "Étapes activées", - "adv.stageCount": "{n} étape{s}", - "adv.stage": "Étape {n}", - "adv.separateXY": "X/Y séparés", - "adv.applyStage": "Appliquer l'étape", - "adv.mapping": "Mappage", - "adv.razerLocked": "{name} est fixé sur la couche Standard et ne peut pas être réaffecté ou désactivé.", - "adv.multiclick": "Filtre multiclic", - "adv.eggButtonTitle": "Multiclic et mappage", - "adv.proAdvanced": "Avancé", - "adv.wheelAccel": "Accélération de la molette", - "adv.angleTuning": "Réglage d'angle", - "adv.onboardProfile": "Profil intégré", - "adv.profileOpt": "Profil {n}", - "prof.onboardTitle": "Profil", - "prof.activeProfile": "Profil actif", - "prof.profileStores": "Chaque profil enregistre ses propres étapes DPI et son taux de sondage, ces valeurs changent donc avec le profil.", - "map.remap": "Réaffecter", - "map.defaultNote": "« Par défaut » restaure la fonction d'usine d'un bouton.", - "pow.mode": "Mode", - "pow.perfMode": "Mode performance", - "diag.details": "Détails de l'appareil", - "diag.diagnostics": "Diagnostic", - "diag.deviceDiag": "Diagnostic de l'appareil", - "diag.download": "Télécharger le diagnostic", - "diag.verifyFormat": "Vérifier le format du profil", - "diag.reads": "Lectures", - "diag.rawSnapshot": "Instantané brut", - "diag.notReported": "Non signalé", - "diag.unknown": "Inconnu", - "diag.noneHost": "Aucun en mode host", - "diag.linkedXY": "X/Y liés", - "sup.support": "SUPPORT DES APPAREILS", - "sup.requestMouse": "Demander une souris", - "sup.introVote": "Effectuez la vérification antispam, puis votez pour une souris listée ou soumettez une nouvelle demande.", - "sup.introPaused": "Le vote et les nouvelles demandes sont temporairement suspendus pendant que nous ajoutons une protection anti-abus renforcée.", - "sup.turnstile": "Vérification antispam", - "sup.searchPlaceholder": "Rechercher un fabricant ou un modèle", - "sup.searchAria": "Rechercher des demandes de souris", - "sup.protectionLoading": "Chargement de la protection de vote", - "sup.completeCheck": "Complétez d'abord la vérification antispam", - "sup.vote": "Voter", - "sup.loading": "Chargement", - "sup.noMatches": "Aucune demande correspondante pour l'instant.", - "sup.requestDifferent": "Demander une autre souris", - "sup.manufacturer": "Fabricant", - "sup.model": "Modèle", - "sup.connection": "Connexion", - "sup.notSure": "Je ne sais pas", - "sup.wiredUsb": "USB filaire", - "sup.wirelessUsb": "Récepteur USB sans fil", - "sup.bluetooth": "Bluetooth", - "sup.wiredWireless": "Filaire et sans fil", - "sup.scope": "Une demande couvre toute la souris : réglages de performance, boutons, profils, éclairage, informations de batterie et toute autre fonctionnalité que nous pouvons prendre en charge.", - "sup.consent": "Ceci n'envoie que les champs affichés ici. Le diagnostic de l'appareil n'est jamais joint automatiquement.", - "sup.submitting": "Envoi…", - "sup.submit": "Envoyer la demande", - "sup.helpDiagnostics": "Aider à ajouter le support avec un diagnostic", - "sup.reviewTitle": "Vérifiez le diagnostic avant l'envoi", - "sup.reviewBody": "Les rapports peuvent contenir le firmware, des identifiants de récepteur, des réglages intégrés et le trafic HID récent. Rien ci-dessous n'est envoyé sans votre consentement.", - "sup.reviewAria": "Vérification de l'envoi du diagnostic", - "sup.reviewConsent": "J'ai vérifié ces données et j'accepte de les envoyer pour cette demande de support.", - "sup.upload": "Envoyer le diagnostic", - "sup.loadingRequests": "Chargement des demandes…", - "sup.loadFail": "Impossible de charger les demandes.", - "sup.protectionMissing": "La protection de vote n'est pas configurée.", - "sup.turnstileFail": "La vérification antispam n'a pas pu se charger.", - "sup.turnstileMissing": "La vérification antispam ne s'est pas chargée.", - "sup.voteRecorded": "Votre vote pour {item} a été enregistré.", - "sup.alreadyVoted": "Vous avez déjà voté pour cette souris.", - "sup.voteFail": "Impossible d'enregistrer votre vote.", - "sup.saved": "Demande enregistrée. Vous pouvez maintenant voter pour elle depuis la liste.", - "sup.saveFail": "Impossible d'enregistrer cette demande.", - "sup.uploadedThanks": "Diagnostic envoyé séparément. Merci de nous aider à étudier cette souris.", - "sup.uploadFail": "Impossible d'envoyer le diagnostic.", - "cap.title": "Capture HID++", - "cap.closeCapture": "Fermer la capture", - "cap.copyVerification": "Copier les données de vérification", - "cap.verifyWrites": "Vérifier les écritures de profil", - "cap.snapshot": "Instantané des profils", - "cap.compare": "Comparer", - "cap.clear": "Effacer", - "cap.copyComparison": "Copier la comparaison", - "cap.whatChanged": "Qu'avez-vous changé ?", - "cap.notesPlaceholder": "Détail optionnel, p. ex. sondage sans fil de 8000 Hz à 1000 Hz", - "misc.devTesting": "Test de développement", - "misc.devTestingBody": "Enregistrez l'identifiant de l'appareil, la version du protocole et tout réglage défaillant dans l'issue ou la pull request. N'utilisez pas la réinitialisation d'usine pendant les tests initiaux.", - "prof.editing": "MODIFICATION", - "prof.active": "actif", - "prof.editingTag": "modification", - "prof.reload": "Recharger les profils", - "prof.deleteReset": "Supprimer et réinitialiser tous les profils intégrés", - "prof.restoreDefaults": "Restaurer définitivement tous les profils intégrés aux valeurs par défaut Logitech", - "prof.openHost": "Ouvrir les réglages host", - "prof.hostAlready": "La souris est déjà en mode host", - "prof.switchHost": "Basculer la souris en mode host", - "prof.switchHostAria": "Basculer en mode host", - "prof.layoutUnverified": "Cette disposition de profil n'a pas été vérifiée sur du matériel réel", - "prof.openProfile": "Ouvrez ce profil pour le modifier", - "prof.noNameField": "Ce format de profil n'a pas de champ nom", - "prof.contentUnverified": "Les écritures de contenu de profil n'ont pas été vérifiées sur du matériel réel", - "prof.renameProfile": "Renommer ce profil", - "prof.runningProfile": "La souris exécute ce profil", - "prof.enableFirst": "Activez ce profil avant d'y basculer", - "prof.switchProfile": "Basculer la souris vers ce profil", - "prof.disable": "Désactiver", - "prof.enable": "Activer", - "prof.disableProfile": "Désactiver ce profil", - "prof.enableProfile": "Activer ce profil", - "prof.toggleProfile": "{a} le profil {n}", - "prof.assign": "Affectations intégrées", - "prof.assignBody": "Choisissez ce que fait chaque contrôle physique dans ce profil.", - "prof.assignLayer": "Couche d'affectation", - "prof.normalTab": "Normal", - "prof.keyboardShortcut": "Raccourci clavier", - "prof.customPreserved": "Mappage personnalisé (conservé)", - "prof.keyboardOpt": "Raccourci clavier…", - "prof.volUp": "Volume plus", - "prof.volDown": "Volume moins", - "prof.mute": "Muet", - "prof.playPause": "Lecture / pause", - "prof.nextTrack": "Piste suivante", - "prof.prevTrack": "Piste précédente", - "prof.recorder": "ENREGISTREUR CLAVIER", - "prof.recordTitle": "Enregistrer une séquence de commandes", - "prof.recordBody": "Démarrez l'enregistrement, appuyez sur un raccourci ou une séquence, puis arrêtez l'enregistrement.", - "prof.stopRec": "Arrêter l'enregistrement", - "prof.record": "Enregistrer", - "prof.listening": "Écoute…", - "prof.nothingRec": "Rien d'enregistré pour l'instant", - "prof.macroNote": "Cette séquence sera enregistrée dans la mémoire de macros intégrée de la souris.", - "prof.assignSeq": "Affecter la séquence", - "prof.assignShortcut": "Affecter le raccourci", - "super.actuation": "Point d'activation", - "super.both": "Les deux boutons", - "super.independent": "Indépendant", - "super.bothPrimary": "Les deux boutons principaux", - "super.bothBody": "Applique les mêmes valeurs aux boutons gauche et droit.", - "super.applyBoth": "Appliquer aux deux boutons", - "super.shortClick": "1 clic court", - "super.longClick": "{max} clic long", - "super.fast": "1 rapide", - "super.slow": "{max} lent", - "super.off0": "0 désactivé", - "super.maxFeedback": "{max} retour maximal", - "super.applyLeft": "Appliquer à gauche", - "super.applyRight": "Appliquer à droite", - "super.clickHaptics": "Retour haptique du clic", - "key.reload": "Recharger les couches", - "key.openLayer": "Ouvrir cette couche", - "key.currentLayer": "Couche actuelle sur la souris", - "key.storedLayer": "Enregistrée sur la souris", - "key.alreadyLayer": "La souris est déjà sur cette couche", - "key.switchLayer": "Basculer la souris vers {label}", - "key.switchTo": "Basculer vers {label}", - "key.active": "active", - "key.editing": "modification", - "key.layersStored": "Couches intégrées enregistrées sur la Nape Pro", - "key.inspectHint": "Cliquez sur une couche pour l'inspecter. Utilisez le cercle pour y basculer la souris.", - "key.reading": "Lecture de {label}…", - "key.layerNote": "Les modifications restent sur cette couche jusqu'à ce que vous les appliquiez. L'orientation est enregistrée par couche par pas de 45°. Le défilement horaire et antihoraire peut être configuré indépendamment.", - "key.assignBody": "Choisissez l'orientation du capteur de cette couche et ce que fait chaque contrôle physique.", - "ctl.noDevice": "Aucun appareil connecté", - "ctl.addSidebar": "Ajoutez un appareil compatible depuis la barre latérale pour lire son état actuel.", - "ctl.onboardIdle": "Les profils se chargent lorsque la souris est en mode intégré.", - "ctl.waitFlash": "Attendez la fin de la gravure en cours.", - "ctl.alreadyMatches": "{label} correspond déjà à la souris.", - "ctl.stagedFlash": "{label} préparé. Gravez pour l'écrire sur la souris.", - "ctl.discarded": "Les modifications préparées ont été annulées.", - "ctl.badKey": "Impossible de lire cette clé de profil", - "ctl.noMouse": "Aucune souris connectée", - "ctl.noMouseDetail": "Connectez la souris pour y importer les réglages.", - "ctl.keyMismatch": "La clé de profil ne correspond pas à cette souris", - "ctl.mismatchDetail": "Cette clé a été capturée depuis une {brand} {name}, pas cet appareil.", - "ctl.keyImported": "Clé de profil importée", - "ctl.keyImportedDetail": "Vérifiez les modifications en file d'attente, puis gravez pour les écrire.", - "ctl.switchingHost": "Basculement vers l'ordinateur {n}", - "ctl.switchHostDetail": "Appuyez sur le bouton sous la souris pour la récupérer.", - "ctl.unableSwitch": "Impossible de demander le basculement.", - "ctl.restoring": "Restauration des boutons au contrôle matériel…", - "ctl.restored": "Boutons restaurés au contrôle matériel.", - "ctl.unableRestore": "Impossible de restaurer les boutons.", - "ctl.waitRefresh": "Attente de l'actualisation actuelle de l'appareil…", - "ctl.flashFailed": "Échec de la gravure", - "ctl.unableFlash": "Impossible de graver les modifications préparées.", - "ctl.flashedOne": "1 modification gravée sur la souris.", - "ctl.flashedMany": "{n} modifications gravées sur la souris.", - "ctl.connected": "Connecté", - "ctl.batteryPct": "Batterie {n}%", - "ctl.currentLine": "Actuel : {dpi} DPI · {hz} Hz", - "ctl.switching": "Basculement", - "ctl.switchingPath": "Chemin de basculement", - "ctl.newDevice": "Nouvel appareil détecté", - "ctl.connFailed": "Échec de la connexion", - "ctl.reading": "Lecture de {name}…", - "ctl.preferUsb": "Préférence pour l'USB plutôt que le récepteur.", - "ctl.unableSwitchDevices": "Impossible de changer d'appareil.", - "ctl.unableRead": "Impossible de lire la souris connectée.", - "ctl.unableSwitchMouse": "Impossible de basculer vers une autre souris connectée.", - "ctl.requesting": "Demande d'autorisation", - "ctl.choosePrompt": "Choisissez votre appareil dans la fenêtre du navigateur.", - "ctl.notConnected": "Non connecté", - "ctl.noSelection": "Aucun appareil n'a été sélectionné dans la fenêtre du navigateur.", - "ctl.opening": "Ouverture de l'appareil", - "ctl.notMouse": "Ce n'est pas une souris", - "ctl.reconnecting": "Reconnexion", - "ctl.readingPrev": "Lecture de l'appareil précédemment autorisé.", - "ctl.useAdd": "Utilisez Ajouter un appareil si la souris ne se reconnecte pas automatiquement.", - "ctl.couldNotReconnect": "Impossible de reconnecter la souris", - "ctl.dpiUnsupported": "Cette valeur DPI n'est pas prise en charge par cette souris.", - "ctl.closestStep": "Cette souris ne peut pas faire {dpi} DPI. Le pas le plus proche pris en charge est {closest}.", - "ctl.dpiNotSupported": "{dpi} DPI n'est pas pris en charge par cette souris.", - "ctl.axesAdvertised": "Les deux valeurs d'axe doivent être des valeurs DPI annoncées.", - "ctl.unableProfiles": "Impossible de lire les profils intégrés.", - "ctl.switchingMode": "Basculement vers le mode {mode}…", - "ctl.unableMode": "Impossible de changer le mode intégré.", - "ctl.switchingProfile": "Basculement vers le profil {n}…", - "ctl.unableProfile": "Impossible de sélectionner ce profil.", - "ctl.unableKeychron": "Impossible de lire les affectations de boutons Keychron.", - "ctl.runningFrom": "Exécution depuis {label}. {layers}", - "ctl.layersCount": "{n} couche{s} intégrée{s}", - "ctl.readingLayers": "Lecture des couches intégrées…", - "ctl.noLayers": "La souris n'a signalé aucune couche intégrée.", - "ctl.unableLayers": "Impossible de lire les couches intégrées.", - "ctl.previewSwitched": "Aperçu : basculé vers {label}. Rien n'est écrit.", - "ctl.runningFromLabel": "Exécution depuis {label}.", - "ctl.unableLayer": "Impossible de changer de couche.", - "ctl.unableProfileState": "Impossible de changer l'état du profil.", - "ctl.resetting": "Réinitialisation de tous les profils intégrés…", - "ctl.writingDefaults": "Écriture des valeurs par défaut d'usine Logitech…", - "ctl.resetDone": "Tous les profils intégrés ont été réinitialisés aux valeurs par défaut Logitech.", - "ctl.resetComplete": "Réinitialisation terminée. Le profil 1 est actif ; les autres profils sont désactivés.", - "ctl.unableReset": "Impossible de réinitialiser tous les profils intégrés.", - "ctl.rateSupport": "Cette souris prend en charge {rates} Hz pour cette liaison de profil.", - "ctl.noLighting": "L'éclairage n'est pas disponible pour cette souris.", - "ctl.pickEffect": "Choisissez d'abord un effet.", - "ctl.waitingRefresh": "En attente d'actualisation", - "ctl.unableRefresh": "Impossible d'actualiser l'état de la souris.", - "ctl.previewG502": "Aperçu : performance, profils intégrés, réaffectation de boutons et éclairage RGB de la G502 X PLUS.", - "ctl.previewLabel": "Aperçu : {label}. Rien n'est écrit.", - "ctl.connectedTo": "Connecté à {name}", - "ctl.mouseGone": "Souris déconnectée", - "ctl.deviceRemoved": "L'appareil a été retiré.", - "ctl.savedName": "{name} enregistré", - "ctl.gone": "La souris n'est plus connectée.", - "ctl.noWebHid": "WebHID n'est pas disponible. Utilisez Chrome ou Edge sur ordinateur.", - "ctl.unableReconnect": "Impossible de se reconnecter à la souris.", - "ctl.noProfileOpen": "Aucun profil n'est ouvert pour modification.", - "ctl.receiverGone": "Le récepteur n'est plus connecté.", - "ctl.noLedControl": "Cet appareil Pulsar n'expose pas de contrôle de LED du récepteur.", - "ctl.teeGone": "La souris Teevolution n'est plus connectée.", - "ctl.previewNoMouse": "Mode aperçu : aucune souris n'est connectée, rien n'a donc été écrit.", - "ctl.atkPending": "Appliquez ou annulez les modifications en attente avant de changer de banque de configuration.", - "ctl.atkSwitching": "Basculement vers la banque de configuration {n}…", - "ctl.atkActive": "La banque de configuration {n} est active.", - "ctl.atkUnableSelect": "Impossible de sélectionner cette banque de configuration ATK R1.", - "ctl.atkUnableBank": "Impossible de sélectionner cette banque de configuration.", - "ctl.pairStarting": "Démarrage de la fenêtre d'appairage du récepteur R1 SE+…", - "ctl.pairActive": "Le récepteur a déjà une fenêtre d'appairage active. Attendez qu'elle se termine, puis démarrez l'appairage R1 SE+.", - "ctl.pairActiveTitle": "Appairage déjà actif", - "ctl.pairActiveDetail": "OpenMouse a laissé le compte à rebours du récepteur existant inchangé.", - "ctl.pairProgress": "Appairage R1 SE+… {n}s restantes.", - "ctl.pairChecking": "Vérification de l'appairage terminé…", - "ctl.pairWaiting": "En attente de la fenêtre d'appairage du récepteur…", - "ctl.pairDone": "Appairage R1 SE+ terminé. La souris est en ligne.", - "ctl.pairDoneTitle": "Récepteur appairé", - "ctl.pairDoneDetail": "La R1 SE+ est en ligne via le récepteur 1K.", - "ctl.pairEnded": "L'appairage s'est terminé sans souris en ligne (état {s}).", - "ctl.pairExpired": "La fenêtre d'appairage du récepteur a expiré avant la fin.", - "ctl.pairUnable": "Impossible d'appairer le récepteur R1 SE+.", - "ctl.pairFailed": "Échec de l'appairage", - "ctl.cmdPower": "Changer le mode de performance", - "ctl.progPower": "Changement de mode…", - "ctl.cmdRemap": "Réaffecter le bouton {button}", - "ctl.progRemap": "Réaffectation…", - "ctl.cmdProfile": "Changer le profil actif", - "ctl.progProfile": "Basculement de profil…", - "ctl.switchingLayer": "Basculement vers {label}…", - "ctl.readingProfiles": "Lecture des profils intégrés…", - "ctl.noProfiles": "Cette souris n'a signalé aucun profil intégré.", - "ctl.noNameField": "Ce format de profil n'a pas de champ nom.", - "ctl.selectedMouse": "la souris sélectionnée", - "ctl.autoSleep": "Veille automatique {v}", - "ctl.autoSleepOff": "Veille automatique désactivée", - "ctl.highestPref": "Performance maximale {v}", - "sleep.never": "Jamais", - "sleep.second1": "1 seconde", - "sleep.seconds": "{n} secondes", - "sleep.minute1": "1 minute", - "sleep.minutes": "{n} minutes", - "sleep.hour1": "1 heure", - "sleep.hours": "{n} heures", - "prof.hostName": "Host", - "prof.liveDetail": "Réglages en direct, non enregistrés sur la souris", - "prof.dpiSlots": "{n} emplacement{s} DPI", - "prof.noSlots": "aucun emplacement DPI", - "prof.profileName": "Profil {n}", - "prof.disabledTag": "désactivé", - "key.layerName": "Couche {n}", - "conn.wired": "Filaire", - "conn.wireless": "Sans fil", - "light.noEffect": "Aucun effet", - "light.speedN": "vitesse {n}", - "page.locale": "Langue", + "ai.subtitle": "إجابات سريعة واستكشاف الأخطاء", + "ai.greeting": "مرحبًا! أنا OpenMouse AI. اختر موضوعًا أدناه وسأساعدك في حلّه.", + "ai.topic1": "ماوسي لا يتصل", + "ai.topic1Ans": "تأكد من أن ماوسك موصول بالكهرباء (أو أن مستقبله في مكانه) وأنه قيد التشغيل. جرّب منفذ USB آخر، أو اتصالًا سلكيًا إن كان ماوسك يدعمه. على Linux، تحقق من أن عقد أجهزة HID قابلة للقراءة — يسرد README قواعد udev. ثم اضغط «اتصال» واختر جهازك من نافذة المتصفح.", + "ai.topic2": "DPI أو معدل الاستقصاء لا يتغير", + "ai.topic2Ans": "بعض الماوسات تقبل قيمًا محددة مسبقًا فقط، لذا جرّب أحد الإعدادات المسبقة إن رُفضت قيمة مخصّصة. اضغط «تطبيق» ودع الكتابة تكتمل قبل لمس أي شيء آخر. إذا عادت القيمة للوراء، فقد لا يكون هذا الإعداد قابلًا للكتابة على ماوسك بعد.", + "ai.topic3": "التطبيق لا يفتح في متصفحي", + "ai.topic3Ans": "يحتاج OpenMouse إلى WebHID، لذا يعمل في Chrome وEdge والمتصفحات الأخرى المبنية على Chromium. لا يدعم Firefox وSafari تقنية WebHID بعد، لذا لن يفتح التطبيق فيهما. جرّب أحدث إصدار من Chrome أو Edge.", + "ai.topic4": "إعداداتي لا تُحفظ", + "ai.topic4Ans": "تُكتب الإعدادات في الملف المخزّن للماوس وتُطبَّق على الجهاز، لا في السحابة. بعد تغيير إعداد، اضغط «تطبيق» وأبقِ الصفحة مفتوحة حتى تكتمل الكتابة. إذا استُعيدت القيمة بعد إعادة التشغيل، فقد يكون هذا الإعداد للقراءة فقط على طرازك.", + "ai.other": "شيء آخر", + "ai.otherAns": "لا بأس — انضم إلى Discord الخاص بـ OpenMouse وسيساعدك المجتمع.", + "ai.joinDiscord": "انضم إلى Discord", + "conn.add": "إضافة جهاز", + "conn.addMouse": "إضافة ماوس", + "conn.connecting": "جارٍ الاتصال…", + "conn.preview": "وضع المعاينة", + "common.apply": "تطبيق", + "common.custom": "مخصّص", + "common.current": "الحالي {v}", + "common.staged": "مُجهَّز {v}", + "common.active": "نشط", + "common.close": "إغلاق", + "common.back": "رجوع", + "common.cancel": "إلغاء", + "common.done": "تم", + "common.save": "حفظ", + "common.on": "تشغيل", + "common.off": "إيقاف", + "dpi.sensitivity": "الحساسية", + "dpi.perProfile": "لكل ملف", + "dpi.value": "قيمة DPI", + "dpi.presets": "قيم DPI الشائعة", + "dpi.presetsInUse": "الإعدادات المسبقة المستخدمة", + "dpi.slotsInUse": "الفتحات المستخدمة", + "dpi.slotsCount": "عدد فتحات DPI", + "dpi.startingSlot": "فتحة البداية", + "dpi.makeStarting": "اجعل هذه فتحة البداية", + "dpi.slotX": "DPI للمحور X للفتحة {n}", + "dpi.slotY": "DPI للمحور Y للفتحة {n}", + "dpi.linkXY": "ربط X و Y للفتحة {n}", + "dpi.linkedHint": "X و Y مرتبطان — انقر لضبطهما منفصلين", + "dpi.unlinkedHint": "X و Y منفصلان — انقر لربطهما", + "dpi.slotLiftOff": "مسافة الرفع للفتحة {n}", + "dpi.liftOffTitle": "ضبط مسافة الرفع", + "dpi.noLiftOff": "صيغة الملف هذه لا تحتوي على إعداد مسافة الرفع", + "dpi.slotReadonly": "للقراءة فقط: كتابة فتحات DPI إلى الملف غير مفعّلة بعد، لأن تسلسل كتابة التثبيت لم يُتحقق منه على العتاد.", + "dpi.slotNote": "تخزّن كل فتحة حساسية X/Y الخاصة بها ومستوى الرفع. {min}–{max} DPI بخطوات {step}. الفتحة المميّزة هي التي يبدأ عليها الماوس.", + "dpi.stagesInUse": "المراحل المستخدمة", + "dpi.stagesCount": "عدد مراحل DPI", + "dpi.activeStage": "المرحلة النشطة", + "dpi.makeActive": "اجعل هذه المرحلة النشطة", + "dpi.stageDpi": "DPI للمرحلة {n}", + "dpi.color": "اللون", + "dpi.stageColor": "لون المرحلة {n}", + "dpi.stageNoteCount": "تعدّل الإعدادات المسبقة و«مخصّص» المرحلة المميّزة. {min}–{max} DPI. يتنقل زر DPI في الماوس عبر هذه المراحل.", + "dpi.stageNoteSteps": "تعدّل الإعدادات المسبقة و«مخصّص» المرحلة المميّزة. {min}–{max} DPI بخطوات {step}. يتنقل زر DPI في الماوس عبر المراحل الـ{total}.", + "dpi.stageToggle": "تضمين مرحلة DPI هذه", + "dpi.editorCountNote": "صف واحد لكل مرحلة DPI. حدّد صفًا لتضمينه في دورة DPI؛ أزل التحديد لتعطيله والاحتفاظ بالقيمة لاحقًا. انقر رقمًا لجعله مرحلة البداية.", + "dpi.editorFixedNote": "صف واحد لكل مرحلة DPI، {total} ثابتة. عدّل القيمة أو المنزلق لتغييرها. انقر رقمًا لجعله المرحلة النشطة.", + "dpi.stagesReadOnly": "تأتي مراحل DPI هذه من الماوس للقراءة فقط، ولا يمكن تعديلها هنا. غيّرها في برنامج الشركة المصنّعة.", + "dpi.editorGenericNote": "صف واحد لكل DPI مسبق. حدّد صفًا (أو انقر رقمه) لجعله DPI الحالي؛ تبقى الصفوف غير المحددة كاختيارات لاحقًا.", + "dpi.xAxis": "المحور X", + "dpi.yAxis": "المحور Y", + "dpi.viewStages": "مراحل", + "dpi.viewSingle": "قيمة واحدة", + "dpi.viewSlots": "فتحات", + "dpi.viewSlotsToggle": "تعديل DPI كفتحات أو قيمة واحدة", + "dpi.viewToggle": "تعديل DPI كمراحل متعددة أو قيمة واحدة", + "perf.reportFrequency": "تكرار الإبلاغ", + "perf.reportRate": "معدل الإبلاغ", + "perf.sharedNote": "يُخزَّن في هذا الملف كفاصل مشترك واحد، حتى {max} هرتز.", + "perf.splitNote": "يُخزَّن في هذا الملف، معدل لكل وصلة. حتى {wireless} هرتز لاسلكيًا، و{wired} هرتز عبر الكابل.", + "perf.eggNote": "المعدلات الأعلى تحدّث حركة المؤشر أكثر وتزيد حمل معالجة المعالج/USB.", + "perf.note": "المعدلات الأعلى تحدّث حركة المؤشر أكثر، لكنها تستهلك بطارية أكثر.", + "perf.allConnections": "كل الاتصالات", + "perf.wired": "سلكي", + "perf.wireless": "لاسلكي", + "perf.gamingSurface": "سطح الألعاب", + "perf.surfaceNote": "يضبط المستشعر لوسائد الماوس المخصصة للألعاب. «تلقائي» يدع الماوس يقرر؛ أوقفه إذا ساء التتبع على سطح غير مخصص للألعاب.", + "perf.auto": "تلقائي", + "perf.liftOff": "مسافة الرفع", + "perf.liftOffMode": "وضع الرفع", + "perf.single": "مفرد", + "perf.asymmetric": "غير متماثل", + "perf.liftOffLabel": "الرفع", + "perf.landing": "الهبوط", + "perf.lodLow": "منخفض", + "perf.lodMedium": "متوسط", + "perf.lodHigh": "مرتفع", + "perf.lodNeedSurface": "فعّل سطح الألعاب أو اضبطه على «تلقائي» لضبط مسافة الرفع.", + "perf.lodNote": "يتحكم في مدى ارتفاعك للماوس قبل توقف التتبع. القيم الأعلى تُبقي التتبع أطول قليلًا.", + "perf.bunnyHop": "القفز المتكرر", + "perf.bunnyTime": "مدة القفز المتكرر بالمللي ثانية", + "perf.bunnyReadonly": "لم تُتحقق صيغة هذا الملف على العتاد، لذا فهي للقراءة فقط.", + "perf.bunnyNote": "يتجاهل النقرات المتكررة الواقعة خلال هذه النافذة، بحيث لا يُسجَّل إلا مرة واحدة عند ارتداد المفتاح أثناء النقر السريع المتكرر. الأوقات الأطول ترشّح أكثر؛ الأقصر تسمح بالنقرات السريعة الحقيقية. {min}–{max} مللي ثانية بخطوات {step}.", + "perf.hybrid": "هجين", + "perf.opticalOnly": "بصري فقط", + "perf.lightforceMode": "وضع مفتاح LightForce", + "perf.lightforceNote": "«هجين» يوفّر الطاقة باستخدام التلامس الميكانيكي ولا يوقظ المستشعر البصري إلا عند الحاجة. «بصري فقط» ثابت لكنه يستهلك بطارية أكثر.", + "light.receiverTitle": "إضاءة المستقبل", + "light.zoneTitle": "إضاءة {zone}", + "light.writeOnly": "كتابة فقط", + "light.rgbPart": "جزء RGB", + "light.rgbParts": "أجزاء RGB", + "light.stripLeds": "مصابيح الشريط الضوئي", + "light.rgbZones": "مناطق RGB", + "light.effect": "تأثير الإضاءة", + "light.brightness": "السطوع", + "light.brightnessAria": "سطوع الإضاءة", + "light.colour": "اللون", + "light.colour2": "اللون 2", + "light.colourAria": "لون الإضاءة", + "light.colour2Aria": "لون الإضاءة الثاني", + "light.speed": "سرعة التأثير", + "light.choose": "اختر تأثيرًا", + "light.writeOnlyNote": "لا يستطيع الماوس الإبلاغ عن تأثيره الحالي، لذا يعرض هذا آخر قيمة كُتبت.", + "light.zoneNote": "يختار تأثير إضاءة {zone}.", + "mx.haptics": "الاستجابة اللمسية", + "mx.hapticFeedback": "الاستجابة اللمسية", + "mx.hapticStrength": "قوة الاستجابة اللمسية", + "mx.batterySaving": "توفير البطارية", + "mx.friendlyName": "الاسم المألوف", + "mx.friendlyNameAria": "الاسم المألوف للجهاز", + "mx.stageName": "اسم المرحلة", + "mx.chars": "{n}/{max} حرفًا", + "mx.ratcheted": "بمسنّنات", + "mx.freeSpinning": "دوران حر", + "mx.wheelMode": "وضع العجلة", + "mx.ratchet": "مسنّن", + "mx.freespin": "دوران حر", + "mx.hiRes": "تمرير عالي الدقة", + "mx.invertVertical": "عكس التمرير الرأسي", + "mx.invertThumb": "عكس عجلة الإبهام", + "mx.switchThreshold": "عتبة المفتاح", + "mx.pairedComputers": "أجهزة الكمبيوتر المقترنة", + "mx.hostOf": "{a} من {b}", + "mx.switchConfirm": "التبديل إلى الكمبيوتر {n}؟ سينقطع اتصال الماوس فورًا. استخدم الزر في أسفله لإعادته.", + "mx.switch": "تبديل", + "mx.remapping": "إعادة الربط", + "mx.lockedOne": "{names} مقفل بواسطة البرنامج الثابت للماوس ولا يمكن إعادة ربطه.", + "mx.lockedMany": "{names} مقفلة بواسطة البرنامج الثابت للماوس ولا يمكن إعادة ربطها.", + "mx.divertedOne": "{name} يُدار بواسطة تطبيق آخر، لذا لا يفعل شيئًا هنا.", + "mx.divertedMany": "{names} تُدار بواسطة تطبيق آخر، لذا لا تفعل شيئًا هنا.", + "mx.restoreHardware": "استعادة التحكم بالعتاد", + "adv.sleepMin": "لا يمكن أن يقل وقت السكون عن دقيقة واحدة.", + "adv.sleepTimeout": "مهلة السكون التلقائي", + "adv.hours": "ساعات", + "adv.minutes": "دقائق", + "adv.seconds": "ثوانٍ", + "adv.signal": "قوة الإشارة", + "adv.signalUnavailable": "إشارة المستقبل غير متاحة.", + "adv.signal0": "ضعيفة جدًا", + "adv.signal1": "ضعيفة", + "adv.signal2": "مقبولة", + "adv.signal3": "جيدة", + "adv.signal4": "ممتازة", + "adv.signalLevel": "المستوى {n}", + "adv.debounce": "منع الارتداد", + "adv.autoSleep": "سكون تلقائي", + "adv.lowPower": "وضع الطاقة المنخفضة", + "adv.lowPowerNote": "يبطئ الماوس لتوفير البطارية دون هذا المستوى.", + "adv.lowPowerCeiling": "غير متاح فوق {max} هرتز. اخفض معدل الاستقصاء لتغييره.", + "adv.processing": "المعالجة", + "adv.angleSnapping": "تثبيت الزاوية", + "adv.straightLine": "تصحيح الخط المستقيم", + "adv.hyperMode": "الوضع الفائق", + "adv.turboMode": "وضع التوربو", + "adv.buttonCombos": "تركيبات الأزرار", + "adv.ultraRange": "مدى فائق الطول", + "adv.angleTune": "ضبط الزاوية", + "adv.highSpeed": "الوضع عالي السرعة", + "adv.competitive": "الوضع التنافسي", + "adv.highestPerf": "أعلى أداء", + "adv.perfMode": "وضع الأداء", + "adv.sensorMode": "وضع المستشعر", + "adv.ecoNote": "«اقتصادي» يوفّر الطاقة عند 125–1000 هرتز لاسلكيًا. «عالي» يستخدم ملف المستشعر عالي الأداء.", + "adv.lockedNote": "مقفل على {mode} عند {hz} هرتز {conn}.", + "adv.duration": "المدة", + "adv.dpiIndicator": "مؤشر DPI", + "adv.effect": "التأثير", + "adv.ledOff": "إيقاف", + "adv.ledSteady": "ثابت", + "adv.ledBreathing": "تنفّس", + "adv.brightness": "السطوع", + "adv.speed": "السرعة", + "adv.dpiStageNote": "يستخدم لون مرحلة DPI النشطة المخزّن بواسطة الماوس.", + "adv.sensorPerf": "أداء المستشعر", + "adv.systemMode": "وضع النظام", + "adv.opticalNote": "اختر أداء المستشعر وملف الطاقة. محرك «بصري» مقفل أثناء تفعيل الوضع الفائق.", + "adv.clickBehavior": "سلوك النقر", + "adv.clickNote": "يقلل HyperClick زمن استجابة النقر. يتحكم Slam-Click في الحماية من النقرات الناتجة عن الصدمات.", + "adv.dongleTournament": "الدونجل ووضع البطولات", + "adv.dongleLed": "مؤشر الدونجل", + "adv.receiverRapidFire": "المستقبل والنيران السريعة", + "adv.ledConnectRate": "الاتصال ومعدل الاستقصاء", + "adv.ledBatteryStatus": "حالة البطارية", + "adv.ledBatteryWarning": "تحذير البطارية", + "adv.fireKeyTimes": "نقرات لكل ضغطة", + "adv.fireKeyHold": "اضغط للتحرير", + "adv.fireKeyInterval": "الفاصل (مللي ثانية)", + "adv.batteryIndicator": "مؤشر البطارية", + "adv.solidWhite": "أبيض ثابت", + "adv.tournamentScroll": "تمرير البطولة", + "adv.scrollUp": "تمرير لأعلى", + "adv.scrollDown": "تمرير لأسفل", + "adv.bothDirections": "كلا الاتجاهين", + "adv.passthrough": "نافذة المرور", + "adv.oneSecond": "1 ثانية", + "adv.halfSeconds": "1.5 ثانية", + "adv.filters": "المرشحات", + "adv.slamclickFilter": "مرشح Slamclick", + "adv.jitterFilter": "مرشح اهتزاز الحركة", + "adv.gxMode": "وضع مفتاح GX", + "adv.leftButton": "الزر الأيسر", + "adv.rightButton": "الزر الأيمن", + "adv.dividerTitle": "مقسّم مخصّص", + "adv.dividerWarning": "قد تختلف المقسّمات غير القياسية لمعدل الاستقصاء بين إصدارات البرنامج الثابت.", + "adv.divider8k": "مقسّم 8K", + "adv.dividerResult": "النتيجة: {hz} هرتز", + "adv.dividerHint": "أدخل مقسّمًا من 1 إلى 255.", + "adv.applyDivider": "تطبيق المقسّم", + "adv.cpiStages": "مراحل CPI", + "adv.enabledStages": "المراحل المفعّلة", + "adv.stageCount": "{n} مرحلة", + "adv.stage": "المرحلة {n}", + "adv.separateXY": "فصل X/Y", + "adv.applyStage": "تطبيق المرحلة", + "adv.mapping": "الربط", + "adv.razerLocked": "{name} ثابت على الطبقة القياسية ولا يمكن إعادة تعيينه أو تعطيله.", + "adv.multiclick": "مرشح النقر المتعدد", + "adv.eggButtonTitle": "النقر المتعدد والربط", + "adv.proAdvanced": "متقدم", + "adv.wheelAccel": "تسارع العجلة", + "adv.angleTuning": "ضبط الزاوية", + "adv.onboardProfile": "الملف المدمج", + "adv.profileOpt": "الملف {n}", + "prof.onboardTitle": "الملف", + "prof.activeProfile": "الملف النشط", + "prof.profileStores": "يخزّن كل ملف مراحل DPI ومعدل الاستقصاء الخاصين به، لذا تتغير تلك القيم مع الملف.", + "map.remap": "إعادة ربط", + "map.defaultNote": "«افتراضي» يعيد وظيفة الزر الأصلية من المصنع.", + "pow.mode": "الوضع", + "pow.perfMode": "وضع الأداء", + "diag.details": "تفاصيل الجهاز", + "diag.diagnostics": "التشخيصات", + "diag.deviceDiag": "تشخيصات الجهاز", + "diag.download": "تنزيل التشخيصات", + "diag.verifyFormat": "التحقق من صيغة الملف", + "diag.reads": "القراءات", + "diag.rawSnapshot": "لقطة خام", + "diag.notReported": "غير مُبلَّغ", + "diag.unknown": "غير معروف", + "diag.noneHost": "لا شيء في وضع المضيف", + "diag.linkedXY": "X/Y مرتبطان", + "sup.support": "دعم الأجهزة", + "sup.requestMouse": "اطلب ماوسًا", + "sup.introVote": "أكمل فحص مكافحة البريد المزعج، ثم صوّت لماوس مُدرَج أو أرسل طلبًا جديدًا.", + "sup.introPaused": "التصويت والطلبات الجديدة متوقفة مؤقتًا أثناء إضافة حماية أقوى من إساءة الاستخدام.", + "sup.turnstile": "تحقق مكافحة البريد المزعج", + "sup.searchPlaceholder": "ابحث عن الشركة المصنّعة أو الطراز", + "sup.searchAria": "البحث في طلبات الماوسات", + "sup.protectionLoading": "جارٍ تحميل حماية التصويت", + "sup.completeCheck": "أكمل فحص مكافحة البريد المزعج أولًا", + "sup.vote": "تصويت", + "sup.loading": "جارٍ التحميل", + "sup.noMatches": "لا توجد طلبات مطابقة بعد.", + "sup.requestDifferent": "اطلب ماوسًا مختلفًا", + "sup.manufacturer": "الشركة المصنّعة", + "sup.model": "الطراز", + "sup.connection": "الاتصال", + "sup.notSure": "لست متأكدًا", + "sup.wiredUsb": "USB سلكي", + "sup.wirelessUsb": "مستقبل USB لاسلكي", + "sup.bluetooth": "بلوتوث", + "sup.wiredWireless": "سلكي ولاسلكي", + "sup.scope": "يغطي الطلب الماوس بالكامل: إعدادات الأداء والأزرار والملفات والإضاءة ومعلومات البطارية وكل قدرة أخرى يمكننا دعمها.", + "sup.consent": "يرسل هذا الحقول الظاهرة هنا فقط. لا تُرفق تشخيصات الجهاز تلقائيًا أبدًا.", + "sup.submitting": "جارٍ الإرسال…", + "sup.submit": "إرسال الطلب", + "sup.helpDiagnostics": "ساعد في إضافة الدعم عبر التشخيصات", + "sup.reviewTitle": "راجع التشخيصات قبل الرفع", + "sup.reviewBody": "قد تحتوي التقارير على البرنامج الثابت ومعرّفات المستقبل والإعدادات المدمجة وحركة HID الأخيرة. لا يُرفع أي شيء أدناه حتى توافق.", + "sup.reviewAria": "مراجعة رفع التشخيصات", + "sup.reviewConsent": "راجعت هذه البيانات وأوافق على رفعها لطلب الدعم هذا.", + "sup.upload": "رفع التشخيصات", + "sup.loadingRequests": "جارٍ تحميل الطلبات…", + "sup.loadFail": "تعذّر تحميل الطلبات.", + "sup.protectionMissing": "حماية التصويت غير مُهيأة.", + "sup.turnstileFail": "فشل تحميل تحقق مكافحة البريد المزعج.", + "sup.turnstileMissing": "لم يُحمَّل فحص مكافحة البريد المزعج.", + "sup.voteRecorded": "تم تسجيل تصويتك لـ{item}.", + "sup.alreadyVoted": "لقد صوّت لهذا الماوس بالفعل.", + "sup.voteFail": "تعذّر تسجيل تصويتك.", + "sup.saved": "تم حفظ الطلب. يمكنك الآن التصويت له من القائمة.", + "sup.saveFail": "تعذّر حفظ هذا الطلب.", + "sup.uploadedThanks": "رُفعت التشخيصات بشكل منفصل. شكرًا لمساعدتنا في التحقيق بشأن هذا الماوس.", + "sup.uploadFail": "تعذّر رفع التشخيصات.", + "cap.title": "التقاط HID++", + "cap.closeCapture": "إغلاق الالتقاط", + "cap.copyVerification": "نسخ بيانات التحقق", + "cap.verifyWrites": "التحقق من كتابات الملف", + "cap.snapshot": "لقطات الملفات", + "cap.compare": "مقارنة", + "cap.clear": "مسح", + "cap.copyComparison": "نسخ المقارنة", + "cap.whatChanged": "ما الذي غيّرته؟", + "cap.notesPlaceholder": "تفاصيل اختيارية، مثل الاستقصاء اللاسلكي من 8000 هرتز إلى 1000 هرتز", + "misc.devTesting": "اختبار التطوير", + "misc.devTestingBody": "سجّل معرّف الجهاز وإصدار البروتوكول وأي إعداد فاشل في المشكلة أو طلب السحب. لا تستخدم إعادة ضبط المصنع أثناء الاختبار الأولي.", + "prof.editing": "قيد التعديل", + "prof.active": "نشط", + "prof.editingTag": "قيد التعديل", + "prof.reload": "إعادة تحميل الملفات", + "prof.deleteReset": "حذف وإعادة تعيين كل ملف مدمج", + "prof.restoreDefaults": "استعادة كل ملف مدمج نهائيًا إلى إعدادات Logitech الافتراضية", + "prof.openHost": "فتح إعدادات المضيف", + "prof.hostAlready": "الماوس في وضع المضيف بالفعل", + "prof.switchHost": "تبديل الماوس إلى وضع المضيف", + "prof.switchHostAria": "التبديل إلى وضع المضيف", + "prof.layoutUnverified": "لم يُتحقق من تخطيط هذا الملف على العتاد", + "prof.openProfile": "افتح هذا الملف لتعديله", + "prof.noNameField": "صيغة هذا الملف لا تحتوي على حقل اسم", + "prof.contentUnverified": "لم تُتحقق كتابات محتوى الملف على العتاد", + "prof.renameProfile": "أعد تسمية هذا الملف", + "prof.runningProfile": "الماوس يشغّل هذا الملف", + "prof.enableFirst": "فعّل هذا الملف قبل التبديل إليه", + "prof.switchProfile": "بدّل الماوس إلى هذا الملف", + "prof.disable": "تعطيل", + "prof.enable": "تفعيل", + "prof.disableProfile": "عطّل هذا الملف", + "prof.enableProfile": "فعّل هذا الملف", + "prof.toggleProfile": "{a} الملف {n}", + "prof.assign": "التعيينات المدمجة", + "prof.assignBody": "اختر ما يفعله كل عنصر تحكم فعلي في هذا الملف.", + "prof.assignLayer": "طبقة التعيين", + "prof.normalTab": "عادي", + "prof.keyboardShortcut": "اختصار لوحة المفاتيح", + "prof.customPreserved": "ربط مخصّص (محفوظ)", + "prof.keyboardOpt": "اختصار لوحة المفاتيح…", + "prof.volUp": "رفع الصوت", + "prof.volDown": "خفض الصوت", + "prof.mute": "كتم", + "prof.playPause": "تشغيل / إيقاف مؤقت", + "prof.nextTrack": "المقطع التالي", + "prof.prevTrack": "المقطع السابق", + "prof.recorder": "مسجّل لوحة المفاتيح", + "prof.recordTitle": "تسجيل تسلسل أوامر", + "prof.recordBody": "ابدأ التسجيل، اضغط اختصارًا واحدًا أو تسلسلًا، ثم أوقف التسجيل.", + "prof.stopRec": "إيقاف التسجيل", + "prof.record": "تسجيل", + "prof.listening": "جارٍ الاستماع…", + "prof.nothingRec": "لم يُسجَّل شيء بعد", + "prof.macroNote": "سيُحفظ هذا التسلسل في ذاكرة الماكرو المدمجة للماوس.", + "prof.assignSeq": "تعيين التسلسل", + "prof.assignShortcut": "تعيين الاختصار", + "super.actuation": "نقطة التفعيل", + "super.both": "كلا الزرين", + "super.independent": "مستقل", + "super.bothPrimary": "كلا الزرين الأساسيين", + "super.bothBody": "طبّق القيم نفسها على الزرين الأيسر والأيمن.", + "super.applyBoth": "تطبيق على كلا الزرين", + "super.shortClick": "نقرة قصيرة واحدة", + "super.longClick": "{max} نقرة طويلة", + "super.fast": "سريع واحد", + "super.slow": "{max} بطيء", + "super.off0": "0 إيقاف", + "super.maxFeedback": "{max} أقصى استجابة", + "super.applyLeft": "تطبيق يسار", + "super.applyRight": "تطبيق يمين", + "super.clickHaptics": "استجابة النقر اللمسية", + "key.reload": "إعادة تحميل الطبقات", + "key.openLayer": "افتح هذه الطبقة", + "key.currentLayer": "الطبقة الحالية على الماوس", + "key.storedLayer": "مخزّنة على الماوس", + "key.alreadyLayer": "الماوس على هذه الطبقة بالفعل", + "key.switchLayer": "بدّل الماوس إلى {label}", + "key.switchTo": "التبديل إلى {label}", + "key.active": "نشط", + "key.editing": "قيد التعديل", + "key.layersStored": "طبقات مدمجة مخزّنة على Nape Pro", + "key.inspectHint": "انقر طبقة لفحصها. استخدم الدائرة لتبديل الماوس إليها.", + "key.reading": "جارٍ قراءة {label}…", + "key.layerNote": "تبقى التغييرات على هذه الطبقة حتى تطبّقها. يُخزَّن الاتجاه لكل طبقة بخطوات 45°. يمكن ضبط التمرير باتجاه عقارب الساعة وعكسها بشكل مستقل.", + "key.assignBody": "اختر اتجاه مستشعر هذه الطبقة وما يفعله كل عنصر تحكم فعلي.", + "ctl.noDevice": "لا يوجد جهاز متصل", + "ctl.addSidebar": "أضف جهازًا مدعومًا من الشريط الجانبي لقراءة حالته الحالية.", + "ctl.onboardIdle": "تُحمَّل الملفات عندما يكون الماوس في الوضع المدمج.", + "ctl.waitFlash": "انتظر انتهاء التثبيت الحالي.", + "ctl.alreadyMatches": "{label} يطابق الماوس بالفعل.", + "ctl.notInGameProfile": "لا يمكن حفظه في ملف لعبة", + "ctl.notInGameProfileDetail": "غيّر هذا من صفحة الجهاز بدلًا من ذلك.", + "ctl.stagedFlash": "{label} مُجهَّز. ثبّته لكتابته إلى الماوس.", + "ctl.discarded": "تم تجاهل التغييرات المُجهَّزة.", + "ctl.badKey": "تعذّرت قراءة مفتاح الملف هذا", + "ctl.noMouse": "لا يوجد ماوس متصل", + "ctl.noMouseDetail": "وصّل الماوس لاستيراد الإعدادات إليه.", + "ctl.keyMismatch": "مفتاح الملف لا يطابق هذا الماوس", + "ctl.mismatchDetail": "أُخذ هذا المفتاح من {brand} {name}، وليس من هذا الجهاز.", + "ctl.keyImported": "تم استيراد مفتاح الملف", + "ctl.keyImportedDetail": "راجع التغييرات المصطفّة، ثم ثبّتها لكتابتها.", + "ctl.switchingHost": "التبديل إلى الكمبيوتر {n}", + "ctl.switchHostDetail": "اضغط الزر أسفل الماوس لإعادته.", + "ctl.unableSwitch": "تعذّر طلب التبديل.", + "ctl.restoring": "جارٍ استعادة الأزرار إلى التحكم بالعتاد…", + "ctl.restored": "تمت استعادة الأزرار إلى التحكم بالعتاد.", + "ctl.unableRestore": "تعذّرت استعادة الأزرار.", + "ctl.waitRefresh": "بانتظار تحديث الجهاز الحالي…", + "ctl.flashFailed": "فشل التثبيت", + "ctl.unableFlash": "تعذّر تثبيت التغييرات المُجهَّزة.", + "ctl.flashedOne": "ثُبّت تغيير واحد إلى الماوس.", + "ctl.flashedMany": "ثُبّتت {n} تغييرات إلى الماوس.", + "ctl.connected": "متصل", + "ctl.batteryPct": "البطارية {n}%", + "ctl.currentLine": "الحالي: {dpi} DPI · {hz} هرتز", + "ctl.switching": "جارٍ التبديل", + "ctl.switchingPath": "مسار التبديل", + "ctl.newDevice": "تم اكتشاف جهاز جديد", + "ctl.connFailed": "فشل الاتصال", + "ctl.reading": "جارٍ قراءة {name}…", + "ctl.preferUsb": "تفضيل USB على المستقبل.", + "ctl.unableSwitchDevices": "تعذّر تبديل الأجهزة.", + "ctl.unableRead": "تعذّرت قراءة الماوس المتصل.", + "ctl.unableSwitchMouse": "تعذّر التبديل إلى ماوس متصل آخر.", + "ctl.requesting": "جارٍ طلب الإذن", + "ctl.choosePrompt": "اختر جهازك في نافذة المتصفح.", + "ctl.notConnected": "غير متصل", + "ctl.noSelection": "لم يُحدَّد أي جهاز في نافذة المتصفح.", + "ctl.opening": "جارٍ فتح الجهاز", + "ctl.notMouse": "ليس ماوسًا", + "ctl.reconnecting": "جارٍ إعادة الاتصال", + "ctl.readingPrev": "جارٍ قراءة الجهاز المصرّح به سابقًا.", + "ctl.useAdd": "استخدم «إضافة جهاز» إن لم يُعد الماوس الاتصال تلقائيًا.", + "ctl.couldNotReconnect": "تعذّرت إعادة اتصال الماوس", + "ctl.dpiUnsupported": "قيمة DPI هذه غير مدعومة من هذا الماوس.", + "ctl.closestStep": "لا يستطيع هذا الماوس تنفيذ {dpi} DPI. أقرب خطوة يدعمها هي {closest}.", + "ctl.dpiNotSupported": "{dpi} DPI غير مدعوم من هذا الماوس.", + "ctl.axesAdvertised": "يجب أن تكون قيمتا المحورين من قيم DPI المُعلَنة.", + "ctl.unableProfiles": "تعذّرت قراءة الملفات المدمجة.", + "ctl.switchingMode": "التبديل إلى وضع {mode}…", + "ctl.unableMode": "تعذّر تغيير الوضع المدمج.", + "ctl.switchingProfile": "التبديل إلى الملف {n}…", + "ctl.unableProfile": "تعذّر تحديد ذلك الملف.", + "ctl.unableKeychron": "تعذّرت قراءة تعيينات أزرار Keychron.", + "ctl.runningFrom": "يعمل من {label}. {layers}", + "ctl.layersCount": "{n} طبقة مدمجة", + "ctl.readingLayers": "جارٍ قراءة الطبقات المدمجة…", + "ctl.noLayers": "لم يُبلّغ الماوس عن طبقات مدمجة.", + "ctl.unableLayers": "تعذّرت قراءة الطبقات المدمجة.", + "ctl.previewSwitched": "معاينة: تم التبديل إلى {label}. لا يُكتب شيء.", + "ctl.runningFromLabel": "يعمل من {label}.", + "ctl.unableLayer": "تعذّر تبديل الطبقة.", + "ctl.unableProfileState": "تعذّر تغيير حالة الملف.", + "ctl.resetting": "جارٍ إعادة تعيين كل ملف مدمج…", + "ctl.writingDefaults": "جارٍ كتابة إعدادات Logitech الافتراضية…", + "ctl.resetDone": "أُعيد تعيين كل الملفات المدمجة إلى إعدادات Logitech الافتراضية.", + "ctl.resetComplete": "اكتملت إعادة التعيين. الملف 1 نشط؛ الملفات الأخرى معطّلة.", + "ctl.unableReset": "تعذّرت إعادة تعيين كل ملف مدمج.", + "ctl.rateSupport": "يدعم هذا الماوس {rates} هرتز لوصلة هذا الملف.", + "ctl.noLighting": "الإضاءة غير متاحة لهذا الماوس.", + "ctl.pickEffect": "اختر تأثيرًا أولًا.", + "ctl.waitingRefresh": "بانتظار التحديث", + "ctl.unableRefresh": "تعذّر تحديث حالة الماوس.", + "ctl.previewG502": "معاينة: أداء G502 X PLUS والملفات المدمجة وإعادة ربط الأزرار وإضاءة RGB.", + "ctl.previewLabel": "معاينة: {label}. لا يُكتب شيء.", + "ctl.connectedTo": "متصل بـ{name}", + "ctl.mouseGone": "انقطع اتصال الماوس", + "ctl.deviceRemoved": "تمت إزالة الجهاز.", + "ctl.savedName": "تم حفظ {name}", + "ctl.gone": "الماوس لم يعد متصلًا.", + "ctl.noWebHid": "WebHID غير متاح. استخدم Chrome أو Edge على سطح المكتب.", + "ctl.unableReconnect": "تعذّرت إعادة الاتصال بالماوس.", + "ctl.noProfileOpen": "لا يوجد ملف مفتوح للتعديل.", + "ctl.receiverGone": "المستقبل لم يعد متصلًا.", + "ctl.noLedControl": "جهاز Pulsar هذا لا يوفّر تحكمًا بمؤشر المستقبل.", + "ctl.teeGone": "ماوس Teevolution لم يعد متصلًا.", + "ctl.previewNoMouse": "وضع المعاينة: لا يوجد ماوس متصل، لذا لم يُكتب شيء.", + "ctl.atkPending": "طبّق أو تجاهل التغييرات المعلّقة قبل تبديل بنوك الإعدادات.", + "ctl.atkSwitching": "التبديل إلى بنك الإعدادات {n}…", + "ctl.atkActive": "بنك الإعدادات {n} نشط.", + "ctl.atkUnableSelect": "تعذّر تحديد بنك إعدادات ATK R1 هذا.", + "ctl.atkUnableBank": "تعذّر تحديد بنك الإعدادات هذا.", + "ctl.pairStarting": "جارٍ بدء نافذة اقتران مستقبل R1 SE+…", + "ctl.pairActive": "المستقبل لديه نافذة اقتران نشطة بالفعل. انتظر انتهاءها، ثم ابدأ اقتران R1 SE+.", + "ctl.pairActiveTitle": "الاقتران نشط بالفعل", + "ctl.pairActiveDetail": "ترك OpenMouse العد التنازلي للمستقبل الحالي دون تغيير.", + "ctl.pairProgress": "جارٍ اقتران R1 SE+… تبقّى {n} ث.", + "ctl.pairChecking": "جارٍ فحص الاقتران المكتمل…", + "ctl.pairWaiting": "بانتظار نافذة اقتران المستقبل…", + "ctl.pairDone": "اكتمل اقتران R1 SE+. الماوس متصل.", + "ctl.pairDoneTitle": "تم اقتران المستقبل", + "ctl.pairDoneDetail": "R1 SE+ متصل عبر مستقبل 1K.", + "ctl.pairEnded": "انتهى الاقتران دون ماوس متصل (الحالة {s}).", + "ctl.pairExpired": "انتهت نافذة اقتران المستقبل قبل الاكتمال.", + "ctl.pairUnable": "تعذّر اقتران مستقبل R1 SE+.", + "ctl.pairFailed": "فشل الاقتران", + "ctl.cmdPower": "تغيير وضع الأداء", + "ctl.progPower": "جارٍ تغيير الوضع…", + "ctl.cmdRemap": "إعادة ربط زر {button}", + "ctl.progRemap": "جارٍ إعادة الربط…", + "ctl.cmdProfile": "تغيير الملف النشط", + "ctl.progProfile": "جارٍ تبديل الملف…", + "ctl.switchingLayer": "التبديل إلى {label}…", + "ctl.readingProfiles": "جارٍ قراءة الملفات المدمجة…", + "ctl.noProfiles": "لم يُبلّغ هذا الماوس عن ملفات مدمجة.", + "ctl.noNameField": "صيغة هذا الملف لا تحتوي على حقل اسم.", + "ctl.selectedMouse": "الماوس المحدد", + "ctl.autoSleep": "سكون تلقائي {v}", + "ctl.autoSleepOff": "السكون التلقائي معطّل", + "ctl.highestPref": "أعلى أداء {v}", + "sleep.never": "أبدًا", + "sleep.second1": "ثانية واحدة", + "sleep.seconds": "{n} ثانية", + "sleep.minute1": "دقيقة واحدة", + "sleep.minutes": "{n} دقيقة", + "sleep.hour1": "ساعة واحدة", + "sleep.hours": "{n} ساعة", + "prof.hostName": "المضيف", + "prof.liveDetail": "إعدادات مباشرة، غير مخزّنة على الماوس", + "prof.dpiSlots": "{n} فتحة DPI", + "prof.noSlots": "لا فتحات DPI", + "prof.profileName": "الملف {n}", + "prof.disabledTag": "معطّل", + "key.layerName": "الطبقة {n}", + "conn.wired": "سلكي", + "conn.wireless": "لاسلكي", + "light.noEffect": "بلا تأثير", + "light.speedN": "السرعة {n}", + "page.locale": "اللغة", "page.en": "EN", "page.pt": "PT", "page.es": "ES", @@ -756,233 +825,232 @@ export const ar: Record = { "page.ja": "日本語", "page.ko": "한국어", "page.ru": "РУС", - "off.banner": "Vous êtes hors ligne. Tout ce qui nécessite le réseau ne sera pas mis à jour.", - "land.supported": "Souris compatibles", - "land.contribute": "Contribuer", - "land.donate": "Faire un don", - "land.openApp": "Ouvrir l'application", - "land.eyebrow": "Gratuit · Open source · Aucun logiciel du fabricant", - "land.hero": "Une application pour chaque souris.", - "land.lead": "OpenMouse fonctionne entièrement dans votre navigateur via WebHID — DPI, taux de sondage, boutons et RGB, pour des dizaines de souris gaming, sans compte, sans installation et sans télémétrie envoyée où que ce soit.", - "land.checkMouse": "Vérifiez votre souris", - "land.f1t": "Fonctionne dans votre navigateur", - "land.f1b": "Pas d'installateur, pas de service en arrière-plan, pas de compte. Branchez votre souris, ouvrez la page, et elle est là via WebHID.", - "land.f2t": "Des dizaines de souris, une application", - "land.f2b": "Une interface cohérente entre les marques et modèles, au lieu d'une application différente et surchargée par fabricant.", - "land.f3t": "Entièrement open source", - "land.f3b": "Chaque driver est rétro-ingénié ouvertement et revu sur GitHub — rien n'appelle chez lui, et vous pouvez lire exactement ce qu'il fait.", - "land.contribTitle": "Aidez à ajouter le support pour plus de souris", - "land.contribBody": "OpenMouse ne prend en charge que ce que la communauté a rétro-ingénié et testé. Si votre souris n'est pas encore listée, le guide de contribution explique les pratiques de rétro-ingénierie sûres et comment les dépôts de drivers s'articulent.", - "land.contribCta": "Lire le guide de contribution", - "chk.back": "← Retour au site", - "chk.overline": "DIAGNOSTIC HID", - "chk.heroBody": "Scannez vos souris gaming connectées pour voir quelles interfaces sont accessibles via WebHID — et lesquelles nécessitent un driver natif.", - "chk.webhidOk": "WebHID est disponible dans ce navigateur — le scan d'appareils est pris en charge.", - "chk.webhidMissing": "WebHID n'est pas disponible. Utilisez Chrome ou Edge sur ordinateur pour exécuter le diagnostic.", - "chk.scanning": "Scan en cours…", - "chk.scanAgain": "Scanner à nouveau", - "chk.scanBtn": "Scanner les souris", - "chk.scanNote": "Vous verrez une fenêtre du navigateur pour sélectionner les appareils.", - "chk.waitPrompt": "En attente de la fenêtre du navigateur…", - "chk.cancelled": "Scan annulé ou aucun appareil sélectionné.", - "chk.noMatch": "Aucun appareil correspondant sélectionné.", - "chk.testing": "Test de {n} appareil{s}…", - "chk.scanError": "Erreur de scan : {msg}", - "chk.resultsOne": "RÉSULTATS — {n} APPAREIL", - "chk.resultsMany": "RÉSULTATS — {n} APPAREILS", - "chk.shareDiscord": "Partagez ces résultats avec l'équipe OpenMouse sur Discord.", - "chk.copied": "Copié !", - "chk.copyDiscord": "Copier pour Discord", - "chk.collections": "COLLECTIONS HID", - "chk.txTest": "TEST RAZER TX-ID", - "chk.responded": "✓ a répondu", - "chk.noResponse": "✗ aucune réponse", - "chk.openedOk": "Appareil ouvert avec succès", - "chk.couldNotOpen": "Impossible d'ouvrir", - "chk.mouseFallback": "Souris {brand}", - "chk.noteBlocked": "Dongle HyperPolling — mouhid.sys bloque WebHID sur Windows", - "chk.noteFull": "Interface fabricant avec rapports de caractéristiques visibles", - "chk.notePartial": "Interface fabricant trouvée — la visibilité des rapports de caractéristiques varie selon l'OS/le navigateur", - "chk.noteLimited": "Seule l'interface souris de démarrage standard est visible pour WebHID", - "chk.noteUnknown": "Aucune collection visible — l'interface peut être bloquée", - "chk.noteRazerOk": "Le protocole HID Razer répond — test TX-ID réussi", - "chk.noteRazerPartial": "L'appareil s'est ouvert mais le test TX-ID n'a reçu aucune réponse valide", - "chk.noteSkipped": "{brand} — interface accessible (sondage ignoré par sécurité)", - "chk.noteReadable": "Rapport de caractéristiques lisible sur l'interface fabricant", - "chk.noteReadFailed": "Interface fabricant accessible mais la lecture du rapport de caractéristiques a échoué", - "chk.noteBlockedOpen": "L'OS/navigateur a bloqué l'ouverture : {msg}", - "chk.couldNotOpenDevice": "Impossible d'ouvrir l'appareil", - "chk.unknownVid": "Inconnu (VID {vid})", - "supp.devices": "Appareils", - "supp.contribute": "Contribuer", - "supp.support": "Support", - "supp.theme": "Changer de thème", - "supp.title": "Appareils compatibles", - "supp.sub": "Quelles souris gaming fonctionnent avec OpenMouse — modèles compatibles, demandes de la communauté et état du driver en un coup d'œil.", - "supp.search": "Rechercher par marque, modèle ou protocole…", - "supp.legend": "Légende", - "supp.brands": "Marques", - "supp.supportedNum": "{n} compatibles", - "supp.totalNum": "{n} suivies au total", - "supp.supportedWord": "compatibles", - "supp.totalWord": "suivies au total", - "supp.oneDevice": "{n} appareil", - "supp.manyDevices": "{n} appareils", - "supp.noResults": "Aucun appareil ne correspond à votre recherche.", - "supp.noFilters": "Aucun appareil ne correspond à ces filtres.", - "supp.clearFilters": "Effacer les filtres de marque et d'étiquette", - "supp.thStatus": "État", - "supp.thModel": "Modèle", - "supp.thNotes": "Notes", - "supp.thVotes": "Votes", - "supp.oneRequest": "({n} demande)", - "supp.manyRequests": "({n} demandes)", - "supp.follow": "Suivre sur X", - "supp.source": "Voir le code source", - "supp.stSupported": "Compatible", - "supp.stPr": "PR en attente", - "supp.stQuickwin": "Ajout facile", - "supp.stLikely": "Test nécessaire", - "supp.stDriver": "Driver nécessaire", - "supp.stUnknown": "Inconnu", - "supp.stBridge": "Bridge nécessaire", - "supp.stPending": "Demandé", - "supp.tabAll": "Tous", - "supp.legSupported": "Confirmé fonctionnel avec un driver enregistré", - "supp.legPr": "Une pull request ajoutant le driver est ouverte", - "supp.legQuickwin": "Protocole implémenté — il ne manque que l'entrée PID/config", - "supp.legLikely": "Le driver le couvre probablement — nécessite un test matériel", - "supp.legDriver": "Aucun driver n'existe encore", - "supp.legUnknown": "Protocole non encore identifié", - "supp.legBridge": "Non compatible avec WebHID — nécessite le compagnon OpenMouse Bridge", - "supp.legPending": "Demande active de la communauté", - "supp.kicker": "Catalogue d'appareils", - "supp.allBrands": "Toutes les marques", - "supp.showEverything": "Tout afficher", - "supp.brandWord": "Marque", - "supp.noBrands": "Aucune marque ne correspond.", - "supp.searchBrands": "Rechercher des marques…", - "supp.filterBrand": "Filtrer par marque", - "supp.allTags": "Toutes les étiquettes", - "supp.tagsWord": "Étiquettes", - "supp.tagWord": "Étiquette", - "supp.noTags": "Aucune étiquette ne correspond.", - "supp.searchTags": "Rechercher des étiquettes…", - "supp.filterTag": "Filtrer par étiquette", - "supp.legendTitle": "Que signifient les étiquettes ?", - "don.devices": "Appareils", - "don.support": "Support", - "don.check": "Tester la souris", - "don.contribute": "Contribuer", - "don.stars": "{n} étoiles", - "don.eyebrow": "Gratuit · Open source · Construit par la communauté", - "don.heroA": "Soutenez ce", - "don.heroB": "projet", - "don.lead": "OpenMouse est gratuit, open source, et conçu pour la communauté. S'il améliore votre configuration, ou vous évite le poids d'un logiciel propriétaire, envisagez de soutenir le travail derrière lui.", - "don.profileTitle": "Le projet OpenMouse", - "don.profileRole": "Mainteneurs et contributeurs", - "don.profileB1": "Bonjour ! Nous sommes les développeurs derrière OpenMouse — un configurateur de souris gratuit et open source. Nous investissons beaucoup de temps à régler de nouvelles souris, écrire des drivers filaires et sans fil, et garder le projet exempt de logiciel superflu des fabricants.", - "don.profileB2": "Nous apprécions le soutien de la communauté et de nos contributeurs. Le parrainage nous aide à couvrir le matériel, les tests et l'infrastructure, et nous permet de continuer à améliorer OpenMouse. Tout don est grandement apprécié !", - "don.thanks": "Merci de votre lecture !", - "don.optional": "Le don est facultatif.", - "don.type": "Type de don", - "don.once": "Ponctuel", - "don.monthly": "Mensuel", - "don.amount": "Montant du don (USD)", - "don.custom": "Montant personnalisé", - "don.customPh": "Entrez un montant", - "don.chargeOnce": "Vous ferez un don de {v} une fois, via GitHub Sponsors.", - "don.chargeMonthly": "Vous ferez un don de {v} chaque mois, via GitHub Sponsors.", - "don.submit": "Faire un don sur GitHub Sponsors", - "don.skip": "Non merci, continuer vers l'application", - "don.contribEyebrow": "AVEC AMOUR DE LA PART DE", - "don.contribTitle": "Nos contributeurs", - "don.stale": "Affichage des données enregistrées — ", - "don.apiFail": "Impossible de contacter GitHub ({msg}). Nouvelle tentative automatique.", - "don.contribs": "{n} contributions", - "don.contribOne": "{n} contribution", - "don.seeAll": "Voir tout le monde sur GitHub ↗", - "don.tagline": "Le configurateur de souris multiplateforme et open source.", - "don.pages": "Pages", - "don.home": "Accueil", - "don.contributeCol": "Contribuer", - "don.reportIssue": "Signaler un problème", - "don.discussions": "Discussions", - "don.source": "Code source", - "don.community": "Communauté", - "don.rights": "© {year} OpenMouse Project. Tous droits réservés.", - "don.privacy": "Politique de confidentialité", - "don.terms": "Conditions d'utilisation", - "don.created": "Créé avec ❤️ par", - "don.theCommunity": "la communauté", - "don.and": "et", - "don.contributors": "contributeurs", - "faq.title": "Foire aux questions", - "faq.q1": "OpenMouse est-il gratuit ?", - "faq.a1": "Oui. OpenMouse est gratuit et open source, sans comptes, abonnements ni paliers payants.", - "faq.q2": "OpenMouse envoie-t-il certaines de mes données quelque part ?", - "faq.a2": "Non. OpenMouse fonctionne entièrement dans votre navigateur via WebHID — il n'y a pas de télémétrie, pas de service en arrière-plan, et rien n'appelle chez lui. Vous pouvez lire exactement ce qu'il fait, car chaque driver est open source.", - "faq.q3": "Quelles souris sont compatibles ?", - "faq.a3a": "Des dizaines de souris gaming de plusieurs marques. Consultez la", - "faq.a3b": "liste des souris compatibles", - "faq.a3c": "pour l'ensemble actuel — le support dépend de ce que la communauté a rétro-ingénié et testé jusqu'à présent.", - "faq.q4": "Quels navigateurs fonctionnent avec OpenMouse ?", - "faq.a4": "OpenMouse nécessite un navigateur avec support WebHID, donc Chrome, Edge et autres navigateurs basés sur Chromium fonctionnent. Firefox et Safari ne prennent actuellement pas en charge WebHID.", - "faq.q5": "Ma souris n'est pas listée — puis-je ajouter le support pour elle ?", - "faq.a5a": "Oui. Le", - "faq.a5b": "guide de contribution", - "faq.a5c": "explique les pratiques de rétro-ingénierie sûres et comment les dépôts de drivers s'articulent.", - "faq.q6": "Dois-je installer quelque chose ?", - "faq.a6": "Pas d'installateur, pas de driver, pas d'application en arrière-plan. Branchez votre souris, ouvrez la page dans un navigateur compatible, et elle est là.", - "faq.q7": "Ma configuration est-elle stockée quelque part ?", - "faq.a7": "Vos réglages ne sont stockés que localement, dans votre navigateur — il n'y a pas de compte ni de synchronisation cloud.", - "faq.q8": "Comment puis-je soutenir le projet ?", - "faq.a8a": "Mettez une étoile au projet sur", - "faq.a8b": "rejoignez le", - "faq.a8c": "pour aider à financer le matériel de test et le développement.", - "adm.title": "Administration OpenMouse", - "adm.password": "Mot de passe", - "adm.checking": "Vérification…", - "adm.signin": "Se connecter", - "adm.loginFailed": "Échec de la connexion.", - "adm.networkError": "Erreur réseau.", - "adm.signout": "Se déconnecter", - "adm.loading": "Chargement…", - "adm.updated": "Mis à jour {time}", - "adm.live": "En direct maintenant", - "adm.peak": "Pic de tous les temps", - "adm.ofPeak": "{n}% du pic", - "adm.dailyViews": "Vues quotidiennes", - "adm.lastAvg": "DERNIERS {n}J · MOY {avg}", - "adm.viewsDays": "Vues, {n}j", - "adm.avgDay": "Moy. / jour", - "adm.medianAdj": "proche de la médiane", - "adm.bestDay": "Meilleur jour", - "adm.bestWeekday": "Meilleur jour de la semaine", - "adm.byViews": "par vues totales", - "adm.regions": "Régions", - "adm.regionsSub": "{views} vues · {n} régions", - "adm.country": "Pays", - "adm.views": "Vues", - "adm.mice": "Souris les plus utilisées", - "adm.miceSub": "{n} connexions · {m} modèles", - "adm.model": "Modèle", - "adm.uses": "Utilisations", - "adm.traffic": "Trafic par jour de la semaine", - "adm.trafficSub": "Vues par jour, par semaine", - "adm.session": "Détail de session", - "adm.sessionSub": "Dérivé de la plage actuelle", - "adm.trackedSince": "Suivi depuis", - "adm.daysTracked": "Jours suivis", - "adm.quietest": "Jour le plus calme", - "adm.trend7d": "Tendance 7j", - "adm.noHistory": "Pas encore d'historique.", - "adm.noData": "Pas encore de données.", - "adm.unknown": "Inconnu", - "adm.loadFail": "Impossible de charger les statistiques.", - "adm.viewsWord": "vues", - "adm.peakConcurrent": "pic simultané {n}", - - "tab.unavailable": "Les commandes de {tab} ne sont pas disponibles pour cet appareil.", - "tab.chooseAnother": "Choisissez un autre onglet pour continuer à configurer l’appareil.", -} + "off.banner": "أنت غير متصل بالإنترنت. لن يُحدَّث أي شيء يحتاج إلى الشبكة.", + "land.supported": "الماوسات المدعومة", + "land.contribute": "ساهم", + "land.donate": "تبرّع", + "land.openApp": "افتح التطبيق", + "land.eyebrow": "مجاني · مفتوح المصدر · بلا برامج الشركات المصنّعة", + "land.hero": "تطبيق واحد لكل ماوس.", + "land.lead": "يعمل OpenMouse بالكامل في متصفحك عبر WebHID — DPI ومعدل الاستقصاء والأزرار وإضاءة RGB، لعشرات الماوسات المخصصة للألعاب، بلا حسابات أو تثبيتات أو إرسال أي بيانات.", + "land.checkMouse": "افحص ماوسك", + "land.f1t": "يعمل في متصفحك", + "land.f1b": "لا مثبّت ولا خدمة خلفية ولا حساب. وصّل ماوسك، افتح الصفحة، وستجده هناك عبر WebHID.", + "land.f2t": "عشرات الماوسات، تطبيق واحد", + "land.f2b": "واجهة متسقة واحدة عبر العلامات التجارية والطرازات، بدلًا من تطبيق منتفخ مختلف لكل مصنّع.", + "land.f3t": "مفتوح المصدر بالكامل", + "land.f3b": "كل تعريف يُهندس عكسيًا في العلن ويُراجع على GitHub — لا شيء يتصل بالخارج، ويمكنك قراءة ما يفعله بالضبط.", + "land.contribTitle": "ساعد في إضافة دعم مزيد من الماوسات", + "land.contribBody": "لا يدعم OpenMouse إلا ما هندسه المجتمع عكسيًا واختبره. إن لم يكن ماوسك مُدرَجًا بعد، يشرح دليل المساهمة ممارسات الهندسة العكسية الآمنة وكيف تترابط مستودعات التعريفات.", + "land.contribCta": "اقرأ دليل المساهمة", + "chk.back": "← العودة إلى الموقع", + "chk.overline": "تشخيصات HID", + "chk.heroBody": "افحص ماوسات الألعاب المتصلة لديك لترى الواجهات المتاحة عبر WebHID — وأيها يحتاج إلى تعريف أصلي.", + "chk.webhidOk": "WebHID متاح في هذا المتصفح — فحص الأجهزة مدعوم.", + "chk.webhidMissing": "WebHID غير متاح. استخدم Chrome أو Edge على سطح المكتب لتشغيل التشخيصات.", + "chk.scanning": "جارٍ الفحص…", + "chk.scanAgain": "إعادة الفحص", + "chk.scanBtn": "افحص بحثًا عن ماوسات", + "chk.scanNote": "ستظهر لك نافذة المتصفح لاختيار الأجهزة.", + "chk.waitPrompt": "بانتظار نافذة المتصفح…", + "chk.cancelled": "أُلغي الفحص أو لم يُحدَّد أي جهاز.", + "chk.noMatch": "لم تُحدَّد أجهزة مطابقة.", + "chk.testing": "جارٍ اختبار {n} جهاز…", + "chk.scanError": "خطأ في الفحص: {msg}", + "chk.resultsOne": "النتائج — جهاز واحد", + "chk.resultsMany": "النتائج — {n} جهاز", + "chk.shareDiscord": "شارك هذه النتائج مع فريق OpenMouse على Discord.", + "chk.copied": "تم النسخ!", + "chk.copyDiscord": "نسخ لـ Discord", + "chk.collections": "مجموعات HID", + "chk.txTest": "اختبار RAZER TX-ID", + "chk.responded": "✓ استجاب", + "chk.noResponse": "✗ لا استجابة", + "chk.openedOk": "فُتح الجهاز بنجاح", + "chk.couldNotOpen": "تعذّر الفتح", + "chk.mouseFallback": "ماوس {brand}", + "chk.noteBlocked": "دونجل HyperPolling — يحجب mouhid.sys تقنية WebHID على Windows", + "chk.noteFull": "واجهة المصنّع مع تقارير الميزات ظاهرة", + "chk.notePartial": "وُجدت واجهة المصنّع — تختلف رؤية تقارير الميزات حسب نظام التشغيل/المتصفح", + "chk.noteLimited": "واجهة الماوس القياسية فقط ظاهرة لـ WebHID", + "chk.noteUnknown": "لا مجموعات ظاهرة — قد تكون الواجهة محجوبة", + "chk.noteRazerOk": "بروتوكول Razer HID يستجيب — اجتاز اختبار TX-ID", + "chk.noteRazerPartial": "فُتح الجهاز لكن اختبار TX-ID لم يتلقَّ استجابة صالحة", + "chk.noteSkipped": "{brand} — الواجهة متاحة (تم تخطي الفحص للسلامة)", + "chk.noteReadable": "تقرير الميزات قابل للقراءة على واجهة المصنّع", + "chk.noteReadFailed": "واجهة المصنّع متاحة لكن قراءة تقرير الميزات فشلت", + "chk.noteBlockedOpen": "حجب نظام التشغيل/المتصفح الفتح: {msg}", + "chk.couldNotOpenDevice": "تعذّر فتح الجهاز", + "chk.unknownVid": "غير معروف (VID {vid})", + "supp.devices": "الأجهزة", + "supp.contribute": "ساهم", + "supp.support": "الدعم", + "supp.theme": "تبديل السمة", + "supp.title": "الأجهزة المدعومة", + "supp.sub": "أي ماوسات الألعاب تعمل مع OpenMouse — الطرازات المدعومة وطلبات المجتمع وحالة التعريفات في لمحة.", + "supp.search": "ابحث حسب العلامة أو الطراز أو البروتوكول…", + "supp.legend": "المفتاح", + "supp.brands": "العلامات التجارية", + "supp.supportedNum": "{n} مدعوم", + "supp.totalNum": "{n} متتبَّع إجمالًا", + "supp.supportedWord": "مدعوم", + "supp.totalWord": "متتبَّع إجمالًا", + "supp.oneDevice": "جهاز واحد", + "supp.manyDevices": "{n} جهاز", + "supp.noResults": "لا أجهزة تطابق بحثك.", + "supp.noFilters": "لا أجهزة تطابق هذه المرشحات.", + "supp.clearFilters": "مسح مرشحات العلامة والوسم", + "supp.thStatus": "الحالة", + "supp.thModel": "الطراز", + "supp.thNotes": "ملاحظات", + "supp.thVotes": "الأصوات", + "supp.oneRequest": "(طلب واحد)", + "supp.manyRequests": "({n} طلب)", + "supp.follow": "تابعنا على X", + "supp.source": "عرض المصدر", + "supp.stSupported": "مدعوم", + "supp.stPr": "طلب سحب معلّق", + "supp.stQuickwin": "فوز سريع", + "supp.stLikely": "يحتاج اختبارًا", + "supp.stDriver": "يحتاج تعريفًا", + "supp.stUnknown": "غير معروف", + "supp.stBridge": "يحتاج Bridge", + "supp.stPending": "مطلوب", + "supp.tabAll": "الكل", + "supp.legSupported": "مؤكَّد عمله مع تعريف مسجَّل", + "supp.legPr": "طلب سحب يضيف التعريف مفتوح", + "supp.legQuickwin": "البروتوكول مُنفَّذ — ينقص فقط إدخال PID/الإعداد", + "supp.legLikely": "التعريف يغطيه على الأرجح — يحتاج اختبار عتاد", + "supp.legDriver": "لا يوجد تعريف بعد", + "supp.legUnknown": "لم يُحدَّد البروتوكول بعد", + "supp.legBridge": "غير متوافق مع WebHID — يحتاج إلى رفيق OpenMouse Bridge", + "supp.legPending": "طلب مجتمعي مباشر", + "supp.kicker": "كتالوج الأجهزة", + "supp.allBrands": "كل العلامات", + "supp.showEverything": "إظهار الكل", + "supp.brandWord": "العلامة", + "supp.noBrands": "لا علامات مطابقة.", + "supp.searchBrands": "ابحث في العلامات…", + "supp.filterBrand": "تصفية حسب العلامة", + "supp.allTags": "كل الوسوم", + "supp.tagsWord": "الوسوم", + "supp.tagWord": "الوسم", + "supp.noTags": "لا وسوم مطابقة.", + "supp.searchTags": "ابحث في الوسوم…", + "supp.filterTag": "تصفية حسب الوسم", + "supp.legendTitle": "ماذا تعني الوسوم؟", + "don.devices": "الأجهزة", + "don.support": "الدعم", + "don.check": "فحص الماوس", + "don.contribute": "ساهم", + "don.stars": "{n} نجمة", + "don.eyebrow": "مجاني · مفتوح المصدر · من بناء المجتمع", + "don.heroA": "ادعم هذا", + "don.heroB": "المشروع", + "don.lead": "OpenMouse مجاني ومفتوح المصدر ومبني للمجتمع. إن جعل إعدادك أفضل، أو وفّر عليك برامج مغلقة منتفخة، فكّر في دعم العمل الذي يقف خلفه.", + "don.profileTitle": "مشروع OpenMouse", + "don.profileRole": "المشرفون والمساهمون", + "don.profileB1": "مرحبًا! نحن المطوّرون خلف OpenMouse — مكوّن ماوس مجاني ومفتوح المصدر. نستثمر وقتًا كبيرًا في ضبط ماوسات جديدة وكتابة تعريفات لاسلكية وسلكية وإبقاء المشروع خاليًا من برامج الشركات المنتفخة.", + "don.profileB2": "نقدّر دعم المجتمع ومساهمينا. تساعدنا الرعاية في تغطية العتاد والاختبار والبنية التحتية، وتتيح لنا مواصلة تحسين OpenMouse. نقدّر أي تبرّع تقديرًا كبيرًا!", + "don.thanks": "شكرًا لقراءتك!", + "don.optional": "التبرّع اختياري.", + "don.type": "نوع التبرّع", + "don.once": "لمرة واحدة", + "don.monthly": "شهري", + "don.amount": "مبلغ التبرّع (دولار)", + "don.custom": "مبلغ مخصّص", + "don.customPh": "أدخل مبلغًا", + "don.chargeOnce": "ستتبرّع بمبلغ {v} مرة واحدة، عبر GitHub Sponsors.", + "don.chargeMonthly": "ستتبرّع بمبلغ {v} كل شهر، عبر GitHub Sponsors.", + "don.submit": "تبرّع على GitHub Sponsors", + "don.skip": "لا شكرًا، تابع إلى التطبيق", + "don.contribEyebrow": "بحب من", + "don.contribTitle": "مساهمونا", + "don.stale": "عرض بيانات محفوظة — ", + "don.apiFail": "تعذّر الوصول إلى GitHub ({msg}). جارٍ إعادة المحاولة تلقائيًا.", + "don.contribs": "{n} مساهمة", + "don.contribOne": "مساهمة واحدة", + "don.seeAll": "شاهد الجميع على GitHub ↗", + "don.tagline": "مكوّن الماوس مفتوح المصدر ومتعدد المنصات.", + "don.pages": "الصفحات", + "don.home": "الرئيسية", + "don.contributeCol": "ساهم", + "don.reportIssue": "أبلغ عن مشكلة", + "don.discussions": "النقاشات", + "don.source": "الشيفرة المصدرية", + "don.community": "المجتمع", + "don.rights": "© {year} مشروع OpenMouse. جميع الحقوق محفوظة.", + "don.privacy": "سياسة الخصوصية", + "don.terms": "شروط الخدمة", + "don.created": "صُنع بـ❤️ بواسطة", + "don.theCommunity": "المجتمع", + "don.and": "و", + "don.contributors": "المساهمون", + "faq.title": "الأسئلة الشائعة", + "faq.q1": "هل OpenMouse مجاني؟", + "faq.a1": "نعم. OpenMouse مجاني ومفتوح المصدر، بلا حسابات أو اشتراكات أو مستويات مدفوعة.", + "faq.q2": "هل يرسل OpenMouse أيًا من بياناتي إلى مكان ما؟", + "faq.a2": "لا. يعمل OpenMouse بالكامل في متصفحك عبر WebHID — لا تتبع ولا خدمة خلفية ولا أي اتصال بالخارج. يمكنك قراءة ما يفعله بالضبط، لأن كل تعريف مفتوح المصدر.", + "faq.q3": "ما الماوسات المدعومة؟", + "faq.a3a": "عشرات ماوسات الألعاب عبر عدة علامات تجارية. اطّلع على", + "faq.a3b": "قائمة الماوسات المدعومة", + "faq.a3c": "للمجموعة الحالية — يعتمد الدعم على ما هندسه المجتمع عكسيًا واختبره حتى الآن.", + "faq.q4": "ما المتصفحات التي تعمل مع OpenMouse؟", + "faq.a4": "يحتاج OpenMouse إلى متصفح يدعم WebHID، لذا يعمل Chrome وEdge والمتصفحات الأخرى المبنية على Chromium. لا يدعم Firefox وSafari تقنية WebHID حاليًا.", + "faq.q5": "ماوسي غير مُدرَج — هل يمكنني إضافة دعم له؟", + "faq.a5a": "نعم.", + "faq.a5b": "دليل المساهمة", + "faq.a5c": "يشرح ممارسات الهندسة العكسية الآمنة وكيف تترابط مستودعات التعريفات.", + "faq.q6": "هل أحتاج إلى تثبيت أي شيء؟", + "faq.a6": "لا مثبّت ولا تعريف ولا تطبيق خلفي. وصّل ماوسك، افتح الصفحة في متصفح مدعوم، وستجده هناك.", + "faq.q7": "هل يُخزَّن إعدادي في أي مكان؟", + "faq.a7": "تُخزَّن إعداداتك محليًا فقط، في متصفحك — لا حساب ولا مزامنة سحابية.", + "faq.q8": "كيف يمكنني دعم المشروع؟", + "faq.a8a": "ضع نجمة للمشروع على", + "faq.a8b": "انضم إلى", + "faq.a8c": "للمساعدة في تمويل عتاد الاختبار والتطوير.", + "adm.title": "إدارة OpenMouse", + "adm.password": "كلمة المرور", + "adm.checking": "جارٍ التحقق…", + "adm.signin": "تسجيل الدخول", + "adm.loginFailed": "فشل تسجيل الدخول.", + "adm.networkError": "خطأ في الشبكة.", + "adm.signout": "تسجيل الخروج", + "adm.loading": "جارٍ التحميل…", + "adm.updated": "حُدِّث {time}", + "adm.live": "مباشر الآن", + "adm.peak": "الذروة على الإطلاق", + "adm.ofPeak": "{n}% من الذروة", + "adm.dailyViews": "المشاهدات اليومية", + "adm.lastAvg": "آخر {n} يوم · المتوسط {avg}", + "adm.viewsDays": "المشاهدات، {n} يوم", + "adm.avgDay": "المتوسط / يوم", + "adm.medianAdj": "قريب من الوسيط", + "adm.bestDay": "أفضل يوم", + "adm.bestWeekday": "أفضل يوم من الأسبوع", + "adm.byViews": "حسب إجمالي المشاهدات", + "adm.regions": "المناطق", + "adm.regionsSub": "{views} مشاهدة · {n} منطقة", + "adm.country": "الدولة", + "adm.views": "المشاهدات", + "adm.mice": "أكثر الماوسات استخدامًا", + "adm.miceSub": "{n} اتصال · {m} طراز", + "adm.model": "الطراز", + "adm.uses": "الاستخدامات", + "adm.traffic": "الحركة حسب يوم الأسبوع", + "adm.trafficSub": "المشاهدات يوميًا، حسب الأسبوع", + "adm.session": "تفاصيل الجلسة", + "adm.sessionSub": "مستخلص من النطاق الحالي", + "adm.trackedSince": "متتبَّع منذ", + "adm.daysTracked": "الأيام المتتبَّعة", + "adm.quietest": "أهدأ يوم", + "adm.trend7d": "اتجاه 7 أيام", + "adm.noHistory": "لا سجل بعد.", + "adm.noData": "لا بيانات بعد.", + "adm.unknown": "غير معروف", + "adm.loadFail": "تعذّر تحميل الإحصاءات.", + "adm.viewsWord": "مشاهدات", + "adm.peakConcurrent": "ذروة متزامنة {n}", + "tab.unavailable": "عناصر تحكم {tab} غير متاحة لهذا الجهاز.", + "tab.chooseAnother": "اختر تبويبًا آخر لمتابعة ضبط الجهاز.", +}; From 75296686916af0b36e15b05d744b97efaf1a3f06 Mon Sep 17 00:00:00 2001 From: snekxs <26660858+snekxs@users.noreply.github.com> Date: Thu, 24 Sep 2026 01:45:13 -0600 Subject: [PATCH 4/4] build: raise the JS bundle budget for the Arabic locale The Arabic table ships as its own lazy chunk (i18n-ar-*.js, ~69 kB, loaded only when Arabic is selected), so the initial English bundle is untouched. The aggregate now measures 1,817.7 kB, which is 38 kB over the 1,780 kB budget; raise it to 1,845 kB. Same documented pattern as every previous locale (pt, es/fr/de/zh, ja/ko, ru, vi). --- build/check-bundle-size.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/build/check-bundle-size.ts b/build/check-bundle-size.ts index f8de21e2..ab39bb3c 100644 --- a/build/check-bundle-size.ts +++ b/build/check-bundle-size.ts @@ -146,7 +146,14 @@ const BUDGET_BYTES: Record = { // scripts/sync-supported-devices.mjs), plus the hw.* and // nav.hardwareTest strings in all ten locale tables. Measured aggregate // is 1,748.7 kB, leaving ~31 kB of headroom. - ".js": 1_780_000, + // Raised to 1,845 kB for the Arabic (ar) interface locale: i18n-ar.ts is a + // full native translation of all ~1,050 keys and ships as its own lazy + // chunk (i18n-ar-*.js, ~69 kB, loaded only when Arabic is selected) — the + // initial (English) bundle is untouched. This is the same lazy-chunk pattern + // as the pt/es/fr/de/zh/ja/ko/ru/vi locales above, and the aggregate counts + // it only because the check sums every emitted chunk. Measured aggregate is + // 1,817.7 kB, leaving ~27 kB of headroom. + ".js": 1_845_000, }; const ASSETS = join("dist", "assets");