// French translations
window.LANG_FR = {
  // Common
  common: {
    save: "Enregistrer",
    cancel: "Annuler",
    confirm: "Confirmer",
    loading: "Chargement...",
    success: "Succès",
    failed: "Échec",
    delete: "Supprimer",
    edit: "Modifier",
    add: "Ajouter",
    enable: "Activer",
    disable: "Désactiver",
    enabled: "Activé",
    disabled: "Désactivé",
    yes: "Oui",
    no: "Non",
    on: "Marche",
    off: "Arrêt",
    apply: "Appliquer",
    reset: "Réinitialiser",
    refresh: "Actualiser",
    close: "Fermer",
    back: "Retour",
    next: "Suivant",
    previous: "Précédent",
    submit: "Soumettre",
    action: "Action",
    chinese: "中文",
    traditionalChinese: "繁體中文",
    english: "English",
    spanish: "Español",
    japanese: "日本語",
    korean: "한국어",
    german: "Deutsch",
    french: "Français",
    portuguese: "Português",
    russian: "Русский",
    italian: "Italiano",
    turkish: "Türkçe",
    continue: "Continuer",
    copy: "Copier",
    copied: "Copié"
  },

  preview: {
    flvRequired: "Veuillez activer le flux FLV.",
    flvOrHlsRequired: "Veuillez activer au moins un flux en direct : FLV ou HLS.",
    hlsUnsupportedEnableFlv: "L'aperçu HLS n'est pas pris en charge par ce navigateur. Veuillez activer FLV."
  },

  play: {
    mainFlvRequired: "Le flux FLV principal doit être activé",
    browserFlvUnsupported: "Ce navigateur ne prend pas en charge la lecture FLV. Veuillez utiliser un navigateur moderne comme Chrome, Edge ou Firefox"
  },

  // Page titles
  title: {
    ndi: "NDI",
    encoder: "Encodeur H.265/H.264",
    status: "État",
    mainStream: "Flux principal",
    subStream1: "Flux secondaire 1",
    subStream2: "Flux secondaire 2",
    subStream3: "Flux secondaire 3",
    videoSettings: "Paramètres vidéo",
    audioSettings: "Paramètres audio",
    advancedSettings: "Paramètres avancés",
    osdMain: "OSD - Flux principal",
    osdSub1: "OSD - Flux secondaire 1",
    osdSub2: "OSD - Flux secondaire 2",
    osdSub3: "OSD - Flux secondaire 3",
    logoUpload: "Téléchargement du logo",
    network: "Paramètres réseau",
    record: "Paramètres d'enregistrement",
    gb28181: "GB28181",
    wifi: "Paramètres WiFi",
    password: "Paramètres du mot de passe",
    serial: "Transport série",
    update: "Mise à jour et sauvegarde",
    reboot: "Redémarrer l'appareil",
    timedReboot: "Redémarrage programmé",
    factoryReset: "Réinitialisation d'usine",
    recordFiles: "Fichiers d'enregistrement",
    netTest: "Test réseau",
    recordSet: "Paramètres d'enregistrement",
    alirtcTokenPage: "AliRTC Token"
  },

  // Menu
  menu: {
    status: "État",
    encoder: "Encodeur",
    mainStream: "Flux principal",
    subStream1: "Flux secondaire 1",
    subStream2: "Flux secondaire 2",
    subStream3: "Flux secondaire 3",
    videoSettings: "Paramètres vidéo",
    audioSettings: "Paramètres audio",
    advancedSettings: "Paramètres avancés",
    osd: "OSD",
    logoUpload: "Téléchargement du logo",
    system: "Système",
    scheduleRecord: "Enregistrement programmé",
    network: "Réseau",
    record: "Enregistrement",
    gb28181: "GB28181",
    wifi: "WiFi",
    password: "Mot de passe",
    serial: "Transport série",
    update: "Mise à jour et sauvegarde",
    reboot: "Redémarrage",
    timedReboot: "Redémarrage programmé",
    factoryReset: "Réinitialisation d'usine"
  },

  // Status page
  status: {
    // Device status
    deviceStatus: "État de l'appareil",
    runningTime: "Temps de fonctionnement : ",
    runtimeDayWithTime: "{0}j {1}",
    deviceTime: "Heure de l'appareil : ",
    syncTime: " (Synchroniser l'heure avec l'appareil)",
    cpuUsage: "Utilisation CPU : ",
    memoryUsage: "Utilisation mémoire : ",
    codecUsage: "Utilisation des ressources d'encodage : ",
    encPpsUsage: "Utilisation des ressources d'encodage : ",
    memoryWarning: " (Si l'utilisation mémoire est trop élevée après 1 minute de démarrage, veuillez désactiver certains flux HLS ou réduire le débit)",
    cpuWarning: " (Si l'utilisation CPU reste au-dessus de 85%, veuillez désactiver certains flux ou réduire la résolution des flux secondaires)",
    networkStatus: "État du réseau : ",
    inputVideo: "Vidéo d'entrée : ",
    inputBeyondCapability: "(dépasse la capacité de l'appareil, réglez la source sur 1080p)",
    inputVideoStatus: "État vidéo d'entrée : ",
    vgaAutoAdjust: " (Ajustement auto VGA)",
    capturedFrames: "Images vidéo capturées : ",
    lostFrames: "Images vidéo perdues : ",
    audioSampleRate: "Taux d'échantillonnage audio d'entrée : ",
    inputAudioStatus: "État audio d'entrée : ",
    capturedAudioFrames: "Images audio capturées : ",
    bFrameMode: "Mode de compression avancé : ",
    bFrameModeEnabled: "Activé",
    packetsSent: "Paquets envoyés : ",
    netTxRate: "Débit réseau sortant : ",
    netTestLink: " (Test réseau & Journal système)",
    packetsDropped: "Paquets perdus : ",
    videoTcpConnections: "Connexions vidéo TCP : {0}",
    tcpDetailsLink: " (Détails)",
    canAccessInternet: "Accès Internet",
    canAccessInternetIP: "Accès IP Internet",
    lanOnly: "LAN uniquement",
    localNetwork: "Réseau local",

    // Recording status
    recordStatus: "État d'enregistrement",
    recordType: "Type d'enregistrement : ",
    diskStatus: "État du disque : ",
    diskNotExist: "Non trouvé",
    mountStatus: "État du montage : ",
    notMounted: "Non monté",
    mounted: "Monté",
    totalSpace: "Espace total : ",
    freeSpace: "Espace libre : ",
    recordingStatus: "État d'enregistrement : ",
    diskFull: "Disque plein",
    diskSlow: "Disque trop lent",
    recordFileList: "Liste des fichiers d'enregistrement",
    notRecording: "Pas d'enregistrement",
    recording: "Enregistrement en cours",
    recordingNoVideo: " (Les fichiers peuvent ne pas être sauvegardés sans entrée vidéo)",
    startRecord: "(Démarrer l'enregistrement)",
    stopRecord: "(Arrêter l'enregistrement)",
    usbTfCard: "USB/Carte TF",

    // DHCP status
    dhcpStatus: "État DHCP",
    ip: "IP : ",
    subnetMask: "Masque de sous-réseau : ",
    gateway: "Passerelle : ",

    // WIFI status
    wifiStatus: "État WiFi",
    wifiDisabled: "WiFi : Désactivé",
    wifiState: "État WiFi : ",
    wifiSSID: "SSID WiFi : ",
    wifiIP: "IP WiFi : ",
    wifiMAC: "MAC WiFi : ",
    wifiRSSI: "Signal WiFi (RSSI) : ",
    wifiFreq: "Fréquence WiFi : ",
    wifiConnected: "Connecté",
    wifiDisconnected: "Déconnecté",
    wifiConnecting: "Connexion en cours (Si la connexion prend trop de temps, veuillez vérifier les paramètres WiFi)",

    noSigPicOnly: "Only transmit no-signal image:",

    timeHour: "h",
    timeMinute: "m",
    timeSecond: "s",

    // Streams
    mainStream: "Flux principal",
    subStream1: "Flux secondaire 1",
    subStream2: "Flux secondaire 2",
    subStream3: "Flux secondaire 3",
    streamDisabled: "Désactivé (Capacité d'encodage saturée : la somme résolution×fréquence d'images du flux principal et des flux secondaires dépasse la limite de 1080p@90 ; ce flux secondaire a été désactivé automatiquement. Réduisez la résolution/fréquence d'images du flux principal ou des flux secondaires précédents, puis réessayez)",
    codecType: "Codec : ",
    encodeResolution: "Résolution d'encodage : ",
    videoBitrate: "Débit vidéo : ",
    realTimeBitrate: "Débit en temps réel : ",
    realTimeFps: "FPS en temps réel : ",
    videoEncoded: "Vidéo encodée : ",
    reconnect: " (Reconnecter)",
	    previewWebRTC: "Aperçu vidéo (WebRTC)",
	    previewHTML5: "Aperçu vidéo (HTML5)",
	    previewLowLatency: "Aperçu vidéo (faible latence)",

    // URL related
    disabled: "Désactivé",
    connected: "Connecté",
    disconnected: "Déconnecté",
    statusNormal: "Normal",
    statusNoData: "Aucune donnée",
    bufferPackets: "Paquets en buffer",
    bufferPacketsLabel: "Paquets en buffer : ",
    pushSpeed: "Vitesse d'envoi",
    pushSpeedLabel: "Vitesse d'envoi : ",
    pushed: "Envoyé",
    pushedLabel: "Envoyé : ",
    sendBytesLabel: "Données envoyées : ",
    memoryUsed: "Mémoire utilisée",
    memoryUsedLabel: "Mémoire utilisée : ",
    cacheFiles: "Fichiers en cache",
    cacheFilesLabel: "Fichiers en cache : ",
    multicastUrl: "URL Multicast : ",
    mjpgUrl: "URL flux MJPG : ",
    jpgUrl: "URL flux JPG : ",
    tsUrl: "URL du flux TS : ",
    flvUrl: "URL flux FLV : ",
    hlsTsUrl: "URL flux HLS TS : ",
    hlsMp4Url: "URL flux HLS MP4 : ",
    mp4Url: "URL flux MP4 : ",
    rtspUrl: "URL flux RTSP : ",
    rtmpUrl: "URL flux RTMP : ",
    srtListenerUrl: "URL SRT Listener : ",
    webrtcP2pUrl: "URL flux WebRTC P2P : ",
    rtmpPushUrlAny: "URL publication RTMP(S)/RTSP {0} : ",
    rtmpPushUrlAny0: "URL publication RTMP(S)/RTSP 0 : ",
    rtmpPushUrlAny1: "URL publication RTMP(S)/RTSP 1 : ",
    rtmpPushUrlAny2: "URL publication RTMP(S)/RTSP 2 : ",
    rtmpPushUrl: "URL publication RTMP(S) {0} : ",
    rtspPushUrl: "URL publication RTSP {0} : ",
    srtCallerUrl: "URL SRT Caller : ",
    hlsPushUrl: "URL PUSH HLS : ",
    icecastPushUrl: "URL PUSH ICECAST : ",
    shoutcastPushUrl: "URL PUSH Shoutcast : ",
    whipLabel: "WHIP : ",
    viewers: "Spectateurs",
    viewersLabel: "Spectateurs : ",

    // TRTC status
    trtcRoomId: "ID de salle TRTC : ",
    inRoom: "Dans la salle",
    notInRoom: "Pas dans la salle",
    initializingServer: "Initialisation de la connexion serveur",
    serverDisconnected: "Serveur déconnecté",
    connectingServer: "Connexion au serveur",
    serverConnected: "Connecté au serveur",
    networkUnknown: "État du réseau inconnu",
    networkExcellent: "Excellent réseau",
    networkGood: "Bon réseau",
    networkNormal: "Réseau normal",
    networkPoor: "Réseau médiocre",
    networkBad: "Mauvais réseau",
    networkNotMeet: "Le réseau ne répond pas aux exigences minimales TRTC",
    errorCode: "Code d'erreur",
    errorCodeLabel: "Code d'erreur : ",
    trtcError1: "Erreur générale, vérifiez les fichiers journaux",
    trtcError100: "Erreur de logique métier : appel illégal",
    trtcError101: "Erreur de logique métier : paramètre illégal",
    trtcError102: "Impossible de lire actuellement, veuillez réessayer",
    trtcError103: "Impossible de se connecter au réseau",
    trtcError200: "Échec d'entrée dans la salle",
    trtcError201: "Paramètre user_sig invalide",
    trtcError202: "Format d'ID de salle invalide",
    trtcError203: "sdk_app_id invalide",
    trtcError204: "Service indisponible. Vérifiez si les minutes du forfait > 0 et que le compte Tencent Cloud n'est pas en retard",
    trtcError205: "L'utilisateur a été expulsé de la salle par le serveur",

    // WHIP status
    whipInitializing: "Initialisation",
    whipConnected: "Connecté",
    whipDisconnected: "Déconnecté",
    whipUnknown: "État inconnu",
    alirtcLabel: "AliRTC : ",
    alirtcConnecting: "Connexion en cours",
    alirtcConnected: "Connecté",
    alirtcDisconnected: "Déconnecté",
    alirtcUnknown: "État inconnu",
    alirtcRoomId: "ID de salle AliRTC : ",
    alirtcRoomIdLabel: "ID de salle : ",
    alirtcUserIdLabel: "ID utilisateur : ",
    alirtcUserNameLabel: "Nom d'utilisateur : ",
    alirtcVideoBitrateLabel: "Vidéo : ",
    alirtcAudioBitrateLabel: "Audio : ",
    alirtcRttLabel: "RTT : ",

    // GB28181
    gb28181: "GB28181 : ",
    gb28181Online: "En ligne",
    gb28181Offline: "Hors ligne"
  },

  // Reboot page
  tcp: {
    pageTitle: "État des connexions TCP",
    subtitle: "Connexions HTTP / HTTPS / RTSP / RTMP actuelles et enregistrements récemment fermés",
    refreshAria: "État d’actualisation",
    reading: "Lecture en cours",
    refreshNow: "Actualiser",
    summaryAria: "Résumé des connexions",
    activeConnections: "Connexions actives",
    waitingSnapshot: "En attente de l’instantané",
    tcpVideoConnections: "Connexions vidéo TCP",
    pendingData: "Données en attente",
    maxPendingPerConnection: "Maximum en attente par connexion",
    recentlyClosed: "Fermées récemment",
    recentRecords: "Enregistrements récents conservés par l’interface",
    stateAria: "État de la connexion",
    allRecords: "Tous les enregistrements",
    currentConnections: "Connexions actuelles",
    typeAria: "Type de connexion",
    allTypes: "Tous les types",
    tcpVideoOnly: "Vidéo TCP uniquement",
    nonVideoConnections: "Connexions non vidéo",
    searchPlaceholder: "Rechercher une IP, un port, un protocole, une requête, un URI ou un ID de flux",
    columnState: "État",
    columnConnection: "Connexion",
    columnClient: "Client",
    columnLocalService: "Service local",
    columnRequestStream: "Requête / Flux vidéo",
    columnSent: "Envoyé",
    columnPending: "En attente",
    columnDropped: "Abandonné",
    loadingSnapshot: "Lecture de l’instantané des connexions…",
    tableNote: "Les données ne sont lues qu’à l’ouverture de cette page ou lors d’un clic sur « Actualiser ». La requête d’actualisation elle-même peut apparaître brièvement comme une connexion HTTP non classée ; les données en attente n’incluent pas la file d’attente socket du noyau.",
    lessThanSecond: "<1 s",
    durationSeconds: "{0} s",
    durationMinutesSeconds: "{0} min {1} s",
    durationHoursMinutes: "{0} h {1} min",
    durationDaysHours: "{0} j {1} h",
    unclassified: "Non classé",
    dropQueuePackets: "Limite de paquets en file",
    dropQueueBytes: "Limite d’octets en file",
    dropNone: "Aucun",
    noConnections: "Aucune connexion actuelle",
    pendingConnectionsSummary: "{0} connexions avec des données en attente · {1} paquets",
    maxPendingConnection: "Connexion #{0} · {1}",
    noPending: "Aucune donnée en attente",
    stateActive: "Active",
    stateClosed: "Fermée",
    connectedFor: "Connectée depuis {0}",
    closedDuration: "Durée {0} · fermée il y a {1}",
    unclassifiedRequest: "Requête non classée",
    streamDescription: "Canal {0} · Groupe {1} / Flux {2}",
    noVideoStream: "Aucun flux vidéo",
    tcpVideo: "Vidéo TCP",
    packets: "{0} paquets",
    packetsAndReason: "{0} paquets · {1}",
    noMatches: "Aucune connexion ne correspond aux filtres actuels",
    filterResult: "Affichage de {0} / {1}",
    invalidXml: "La réponse n’est pas un XML valide",
    readSuccess: "Lecture réussie",
    parseFailed: "Échec de l’analyse",
    snapshotParseFailed: "Impossible d’analyser l’instantané des connexions",
    readFailed: "Échec de la lecture",
    endpointReadFailed: "Impossible de lire /debug?cmd=tcp. Vérifiez la connexion de l’appareil ou reconnectez-vous.",
    readTimeout: "Délai de lecture dépassé",
    timeoutMessage: "L’appareil n’a pas renvoyé d’instantané des connexions dans les 10 secondes.",
    networkError: "Erreur réseau",
    networkMessage: "Impossible de se connecter à l’appareil. Vérifiez le réseau.",
  },

  reboot: {
    title: "Redémarrer l'appareil",
    description: "Cliquez sur ce bouton pour redémarrer l'encodeur.",
    button: "Redémarrer",
    success: "Commande de redémarrage envoyée !",
    failed: "Échec du redémarrage !",
    confirm: "Êtes-vous sûr de vouloir redémarrer l'appareil ?"
  },

  // Factory reset page
  reset: {
    title: "Réinitialisation d'usine",
    description: "Cliquez sur ce bouton pour restaurer tous les paramètres de l'encodeur à leur état d'usine par défaut.",
    button: "Réinitialiser",
    success: "Réinitialisation d'usine réussie ! Le système redémarrera automatiquement, veuillez patienter.",
    failed: "Échec de la réinitialisation d'usine !",
    confirm: "Êtes-vous sûr de vouloir restaurer les paramètres d'usine ?"
  },

  // Scheduled reboot page
  scheduleRecord: {
    title: "Enregistrement programmé",
    allDay: "Toute la journée",
    timeRange: "Plage horaire",
    segment: "Plage horaire",
    to: "à",
    monday: "Lun",
    tuesday: "Mar",
    wednesday: "Mer",
    thursday: "Jeu",
    friday: "Ven",
    saturday: "Sam",
    sunday: "Dim",
    nextDay: "(jour+1)",
    hint: "Chaque plage peut être Toute la journée ou une Plage horaire, avec ses jours actifs ; dans une plage, une fin antérieure au début signifie nuit (enregistre le lendemain, selon le jour de début). Synchronisez l'heure (NTP) dans Réseau, sinon rien ne se déclenche.",
    saveSuccess: "Enregistré avec succès !",
    saveFailed: "Échec de l'enregistrement !",
    invalidTime: "Heure invalide !",
    needWeekday: "Sélectionnez au moins un jour !",
  },
  timedReboot: {
    title: "Redémarrage programmé",
    enable: "Redémarrage programmé",
    enableLabel: "Redémarrage programmé :",
    timeLabel: "Heure de redémarrage :",
    enabled: "Activer",
    disabled: "Désactiver",
    time: "Heure de redémarrage",
    weekdays: "Jours de redémarrage",
    everyday: "Tous les jours",
    monday: "Lundi",
    tuesday: "Mardi",
    wednesday: "Mercredi",
    thursday: "Jeudi",
    friday: "Vendredi",
    saturday: "Samedi",
    sunday: "Dimanche",
    save: "Enregistrer",
    saveSuccess: "Paramètres enregistrés !",
    saveFailed: "Échec des paramètres !",
    invalidTime: "Valeur de temps invalide !"
  },

  // Network test page
  netTest: {
    title: "Test réseau & Journal système",
    command: "Commande :",
    run: "Exécuter",
    address: "Adresse :",
    result: "Résultat :",
    invalidAddr: "Veuillez entrer une adresse valide !"
  },

  // Record files page
  recordFiles: {
    title: "Liste des fichiers",
    fileName: "Nom du fichier",
    time: "Heure",
    fileSize: "Taille du fichier",
    action: "Action",
    delete: "Supprimer",
    confirmDelete: "Êtes-vous sûr de vouloir supprimer",
    deleteSuccess: "Commande de suppression envoyée avec succès !",
    deleteFailed: "Échec de la suppression !",
    noFiles: "Aucun fichier d'enregistrement",
    loadError: "Échec du chargement"
  },

  // Password settings page
  password: {
    title: "Paramètres du mot de passe",
    oldPassword: "Ancien mot de passe",
    oldPasswordLabel: "Ancien mot de passe :",
    newPassword: "Nouveau mot de passe",
    newPasswordLabel: "Nouveau mot de passe :",
    confirmPassword: "Confirmer le mot de passe",
    confirmPasswordLabel: "Confirmer le mot de passe :",
    save: "Enregistrer",
    success: "Paramètres enregistrés !",
    failed: "Échec du paramétrage du mot de passe, veuillez vérifier l'ancien mot de passe !",
    mismatch: "Les nouveaux mots de passe ne correspondent pas !",
    empty: "Le mot de passe ne peut pas être vide !"
  },

  // Encoding common (only actually used keys)
  encoding: {
    sameAsInput: "Identique à la résolution d'entrée",
    mp3Required: "Veuillez régler l'encodage audio sur MP3 !",
    choosePrimaryColor: "Choisir la couleur principale",
    toggleTheme: "Changer de thème"
  },

  // OSD settings
  osd: {
    title: "Paramètres OSD",
    globalSettings: "Paramètres OSD globaux",
    followVideoTransformLabel: "Suivre la rotation/miroir vidéo :",
    mainStream: "OSD Flux principal",
    subStream1: "OSD Flux secondaire 1",
    subStream2: "OSD Flux secondaire 2",
    subStream3: "OSD Flux secondaire 3",
    alpha: "Transparence",
    alphaLabel: "Transparence :",
    alphaRange: "[0-255]",
    alphaError: "La transparence doit être un entier entre 0-128 !",
    region: "Région",
    regionLabel: "Région :",
    region1: "Région 1",
    region2: "Région 2",
    region3: "Région 3",
    region4: "Région 4",
    type: "Type",
    typeLabel: "Type :",
    typeText: "Texte",
    typeImage: "Image",
    typeScroll: "Texte défilant",
    typeTime: "Heure",
    typeAudioStatus: "Etat audio",
    typeVolumeMeter: "Vumètre",
    timeFormatLabel: "Format de l'heure :",
    position: "Position",
    positionLabel: "Position :",
    speed: "Vitesse",
    speedLabel: "Vitesse :",
    xLabel: "X :",
    yLabel: "Y :",
    textLabel: "Texte :",
    fontSize: "Taille de police",
    fontSizeLabel: "Taille de police :",
    fontSizeRange: "[8-72]",
    backgroundColor: "Couleur d'arrière-plan",
    backgroundLabel: "Couleur d'arrière-plan :",
    sizeLabel: "Taille (L×H) :",
    sizeHint: "[px]",
    sizeError: "{0} : la taille (L×H) doit être des entiers positifs valides",
    bgTransparent: "Transparent",
    bgWhite: "Blanc",
    bgBlack: "Noir",
    fontColor: "Couleur de police",
    fontColorLabel: "Couleur de police :",
    pickColor: "Choisir la couleur",
    closeColor: "Fermer",
    logoLabel: "LOGO :",
    success: "Paramètres enregistrés avec succès !",
    failed: "Échec des paramètres !",
    xRangeError: "{0} La valeur X doit être un entier entre 0-{1} !",
    yRangeError: "{0} La valeur Y doit être un entier entre 0-{1} !",
    textEmpty: "{0} Le texte ne peut pas être vide !",
    fontSizeError: "{0} La taille de police doit être un entier entre 8-72 !",
    speedRangeError: "{0} La vitesse doit être un entier entre 0-30 !",
    positionRangeError: "{0} La position doit être un entier entre 0-{1} !",
    selectLogo: "Veuillez sélectionner un LOGO pour {0} !",
    webrtcPreview: "Aperçu vidéo"
  },

  // LOGO upload
  logo: {
    title: "Téléchargement du logo",
    logoLabel: "LOGO :",
    upload: "Télécharger",
    hint: "Veuillez téléverser une image de moins de 500 Ko. Formats pris en charge : PNG / JPG / BMP (pour la transparence, utilisez un PNG ou un BMP 32 bits avec canal alpha).",
    hint2: "Le nom de fichier doit être logo1 / logo2 / logo3 / logo4, extension .png / .jpg / .jpeg / .bmp.",
    hint3: "ex. logo1.png, logo1.jpg, logo1.jpeg, logo1.bmp",
    noFileSelected: "Veuillez sélectionner un fichier à télécharger !",
    invalidFile: "Veuillez télécharger les images selon les exigences !",
    uploadSuccess: "Téléchargement réussi !",
    uploadFailed: "Échec du téléchargement !",
    imageSizeExceeded: "La taille du fichier image dépasse la limite !",
    imageResolutionExceeded: "La résolution du fichier image dépasse la limite !",
    storageInsufficient: "Fichier de mise à jour trop volumineux, espace de stockage insuffisant !",
    listTitle: "LOGO téléchargé",
    refresh: "Actualiser",
    preview: "Aperçu",
    logoFile: "Fichier LOGO",
    fileType: "Type",
    fileSize: "Taille",
    operation: "Opération",
    loading: "Chargement...",
    emptyList: "Aucun LOGO téléchargé",
    loadListFailed: "Échec du chargement de la liste des LOGO",
    confirmDelete: "Supprimer {0} ?\nLes fichiers PNG/BMP/OSD du même nom seront également supprimés. Si ce LOGO est utilisé, l'OSD d'image associé sera effacé.",
    deleteSuccess: "Suppression réussie !",
    deleteFailed: "Échec de la suppression !"
  },

  // WIFI settings
  wifi: {
    title: "Paramètres WiFi",
    mode: "Mode",
    ap: "Point d'accès",
    sta: "Mode client",
    ssid: "SSID",
    password: "Mot de passe",
    security: "Sécurité",
    channel: "Canal",
    scan: "Scanner",
    connect: "Connecter",
    disconnect: "Déconnecter",
    status: "État",
    connected: "Connecté",
    disconnected: "Déconnecté",
    signalStrength: "Puissance du signal",
    basicSettings: "Paramètres de base",
    wifiModule: "Module WiFi :",
    wifiMode: "Mode WiFi :",
    staMode: "Mode STA",
    apMode: "Mode AP",
    mainConfig: "Config principale WiFi",
    backupConfig1: "Config de secours WiFi 1",
    backupConfig2: "Config de secours WiFi 2",
    apModeSettings: "Mode AP",
    wifiList: "Liste WiFi :",
    wifiEssid: "ESSID WiFi :",
    wifiPassword: "Mot de passe WiFi :",
    wifiDhcp: "DHCP WiFi :",
    wifiIp: "IP WiFi :",
    wifiNetmask: "Masque réseau WiFi :",
    wifiGateway: "Passerelle WiFi :",
    backupEnable1: "Config de secours 1 :",
    backupEnable2: "Config de secours 2 :",
    wifiBand: "Bande WiFi :",
    wifiChannel: "Canal WiFi :",
    refresh: "Actualiser",
    success: "Paramètres enregistrés avec succès !",
    failed: "Échec de l'enregistrement des paramètres !",
    mainConfigEmpty: "Config principale WiFi : {0} ne peut pas être vide !",
    mainConfigInvalid: "Config principale WiFi : {0} format invalide !",
    backupConfigEmpty: "WiFi {0} : {1} ne peut pas être vide !",
    backupConfigInvalid: "WiFi {0} : {1} format invalide !",
    ipAddr: "Adresse IP",
    netmask: "Masque réseau",
    gateway: "Passerelle",
    essidEmpty: "Le nom WiFi ne peut pas être vide !",
    passwordTooShort: "Le mot de passe WiFi doit avoir au moins 8 caractères !"
  },


  // Upgrade and backup
  updateBackup: {
    title: "Mise à jour système",
    uploadTitle: "Télécharger le firmware et la configuration",
    backupTitle: "Sauvegarder le firmware et la configuration",
    systemVersion: "Version système",
    systemVersionLabel: "Version système : ",
    hardware: "Matériel",
    hardwareLabel: "Matériel : ",
    selectFile: "Sélectionner un fichier",
    selectFileLabel: "Sélectionner un fichier :",
    uploadHint: "Nom du fichier à télécharger : up.rar ou box.ini",
    uploadHintEncrypted: "Nom du fichier à télécharger : up.bin ou box.ini",
    uploadWarning: "Ne pas télécharger simultanément. Ne pas éteindre pendant le téléchargement.",
    upload: "Télécharger",
    backupFirmware: "Sauvegarder le firmware",
    backupConfig: "Sauvegarder la configuration",
    noFileSelected: "Veuillez sélectionner un fichier à télécharger !",
    uploadSuccess: "Téléchargement réussi, veuillez redémarrer le système !",
    uploadFailed: "Échec du téléchargement !",
    kernelUpdating: "La mise à jour du noyau prend quelques minutes ; n'éteignez pas l'appareil. L'appareil redémarrera automatiquement une fois terminé — aucun redémarrage manuel n'est nécessaire.",
    kernelUpdatingBin: "La mise à jour du noyau prend quelques minutes ; n'éteignez pas l'appareil. L'appareil redémarrera automatiquement une fois terminé — aucun redémarrage manuel n'est nécessaire !",
    imageSizeExceeded: "La taille du fichier image dépasse la limite !",
    imageResolutionExceeded: "La résolution du fichier image dépasse la limite !",
    storageInsufficient: "Fichier de mise à jour trop volumineux, espace de stockage insuffisant !"
  },

  // Serial transport settings
  serial: {
    title: "Transport série",
    frpTitle: "Paramètres client FRP",
    serialTitle: "Passthrough port série",
    enable: "Activer",
    disable: "Désactiver",
    enableLabel: "Activer :",
    serverAddr: "Adresse du serveur",
    serverAddrLabel: "Adresse du serveur :",
    serverPort: "Port du serveur",
    serverPortLabel: "Port du serveur :",
    serverToken: "Token du serveur",
    serverTokenLabel: "Token du serveur :",
    channel: "Canal",
    channel1: "Canal 1",
    channel2: "Canal 2",
    channel3: "Canal 3",
    channel4: "Canal 4",
    protocolLabel: "Protocole :",
    localPort: "Port local",
    localPortLabel: "Port local :",
    remotePort: "Port distant",
    remotePortLabel: "Port distant :",
    serialMode: "Mode série",
    serialModeLabel: "Mode :",
    server: "Serveur",
    client: "Client",
    baudRate: "Débit en bauds",
    baudRateLabel: "Débit en bauds :",
    listenPort: "Port d'écoute",
    listenPortLabel: "Port d'écoute :",
    save: "Enregistrer",
    success: "Paramètres enregistrés, veuillez redémarrer l'appareil !",
    failed: "Échec des paramètres !",
    emptyError: "Les paramètres ne peuvent pas être vides !",
    remoteAddrError: "Adresse du serveur distant invalide (saisissez une IP ou un nom d'hôte valide) !",
    portRangeError: "Le port d'écoute TCP doit être un entier entre 1-65535 !",
    frpAddrEmpty: "L'adresse du serveur FRP ne peut pas être vide !",
    frpPortError: "Le port du serveur FRP doit être un entier entre 1-65535 !"
  },

  // Advanced Settings
  advanced: {
    title: "Paramètres avancés",
    // Section titles
    videoInput: "Entrée vidéo",
    avTransmission: "Transmission A/V",
    recordSettings: "Paramètres d'enregistrement",
    hlsSettings: "Paramètres HLS",
    networkTransmission: "Transmission de flux",
    serviceSettings: "Paramètres de service",
    logSettings: "Paramètres de journal",
    encoderParams: "Paramètres d'encodeur",
    imageEnhancement: "Amélioration d'image",
    autoRestart: "Redémarrage auto",
    // Video Input
    edidSelect: "Sélection EDID :",
    colorGamut: "Gamme de couleurs :",
    colorRange: "Plage de couleurs :",
    bFrameMode: "Advanced compression mode:",

    interlaceMode: "Mode entrelacé :",
    noSignal: "Pas de signal :",
    noSigPicOnly: "Only transmit no-signal image:",

    vgaAutoAdjust: "Ajustement auto VGA au démarrage :",
    interlaceWeaving: "Tissage (fusionner les champs)",
    interlaceBottom: "Champ inférieur uniquement",
    interlaceTop: "Champ supérieur uniquement",
    interlaceBobbing: "Bobbing (champ vers image)",
    noSignalHide: "Masquer",
    noSignalImage: "Show no-signal image",
    noSignalColor: "Afficher une couleur unie",
    // A/V Transmission
    videoOnly: "Vidéo uniquement :",
    audioOnly: "Audio uniquement :",
    avSync: "Sync A/V :",
    audioDelay: "Délai audio (ms) :",
    syncAuto: "Auto",
    syncResample: "Rééchantillonnage",
    audioDelayHint: "Les valeurs négatives avancent l'audio, les positives le retardent. À utiliser uniquement pour le réglage de la sync A/V.",
    // Recording Settings
    recordType: "Type d'enregistrement :",
    cycleRecord: "Enregistrement cyclique :",
    diskOverwriteOldest: "Supprimer les plus anciens si plein :",
    noRecordNoSig: "Pas d'enregistrement sans signal :",
    recordSplitTime: "Temps de division d'enregistrement (sec) :",
    // HLS Settings
    hlsSplitTime: "Temps de segment HLS (sec) :",
    hlsBufferNum: "Nombre de segments HLS :",
    hlsIndexUri: "URI d'index global HLS :",
    // Network Transmission
    tsMuxer: "Muxeur TS :",
    sliceNumber: "SLICE Number:",

    netDropThreshold: "Seuil de perte de paquets :",
    tsOnce: "Paquets TS par envoi :",
    rtspPackType: "Encapsulation RTSP :",
    multicastType: "Type multicast :",
    enableSap: "Activer SAP :",
    mtuSize: "Taille MTU :",
    ethSpeed: "Ethernet speed:",

    natAddr: "NAT mapped address:",

    udpTtl: "TTL UDP :",
    udpSockBuf: "UDP SOCKET_BUF_SIZE :",
    rtpH264PacketMode: "Paquetisation RTP H264 :",
    packetizeByAccessUnit: "packetize_by_access_unit",
    packetizeByNalu: "packetize_by_nalu",
    vlcCompat: "Compatible VLC",
    ffmpegCompat: "Compatible FFMPEG",
    esStream: "Flux ES",
    tsStream: "Flux TS",
    // Service Settings
    tsRtspAuth: "Auth TS/RTSP requise :",
    httpNoAuth: "Accès web sans auth :",
    netCheck: "Vérification état réseau :",
    telnetService: "Service Telnet :",
    sshService: "Service SSH :",
    ndiService: "Service NDI :",
    sambaService: "Service Samba :",
    onvifService: "Service ONVIF :",
    onvifLocation: "ONVIF Location:",
    onvifMode: "Mode ONVIF :",
    onvifModeLegacy: "Legacy XML (port HTTP/ONVIF partagé)",
    onvifModeProfileST: "Profile S/T (port ONVIF dédié)",
    onvifModeProfileSCompat: "Profile S compatible Hikvision (port ONVIF dédié)",
    onvifPassword: "ONVIF password required:",

    rtspDefaultStream: "Flux RTSP par défaut :",
    vmixCompat: "Compatible VMix :",
    readOnlyConfig: "Lock all settings:",

    telnetLan: "LAN uniquement",
    // Log Settings
    localLog: "Service de journal local :",
    trtcLogLevel: "Niveau de journalisation SDK TRTC :",
    alirtcLogLevel: "Niveau de journalisation SDK AliRTC :",
    sdkLogDebug: "Débogage",
    sdkLogInfo: "Info",
    sdkLogWarning: "Avertissement",
    sdkLogError: "Erreur",
    sdkLogFatal: "Fatal",
    sdkLogNone: "Aucun",
    lokiAddr: "Adresse serveur Loki :",
    lokiPort: "Port serveur Loki :",
    // Encoder Parameters
    sliceSplit: "Division SLICE :",
    sliceBytes: "Octets SLICE :",
    minQp: "MIN_QP :",
    maxQp: "MAX_QP :",
    deblocking: "Deblocking filter:",
    deblockingAlpha: "Deblocking alpha:",
    deblockingBeta: "Deblocking beta:",



    debreath: "Debreathing :",
    sar: "PAR:",
    cbrOnlyHint: "Effectif uniquement quand le mode de contrôle de débit est CBR",
    // Image Enhancement
    contrastEnhance: "Amélioration du contraste :",
    sharpnessEnhance: "Amélioration de la netteté :",
    lumaSfStrength: "Débruitage spatial luma :",
    lumaTfStrength: "Débruitage temporel luma :",
    chromaSfStrength: "Débruitage spatial chroma :",
    chromaTfStrength: "Débruitage temporel chroma :",
    // Auto Restart
    kickAllOnChange: "Déconnecter les utilisateurs au changement d'entrée :",
    noVideoReboot: "Redémarrage auto sans vidéo :",
    noAudioReboot: "Redémarrage auto sans audio :",
    picStillRestart: "Restart on frozen video:",

    // Button
    save: "Enregistrer",
    // Messages
    success: "Paramètres enregistrés, veuillez redémarrer l'appareil !",
    failed: "Échec des paramètres !",
    emptyError: "Les paramètres ne peuvent pas être vides !",
    netDropError: "Le seuil de perte de paquets doit être un entier entre 50-50000 !",
    tsOnceError: "TS packets per send must be an integer between 3-128!",
    sliceError: "SLICE Number must be an integer between 1-255!",
    minQpError: "MIN_QP doit être un entier entre 1-35 !",
    maxQpError: "MAX_QP doit être supérieur à MIN_QP et au maximum 50 !",
    udpTtlError: "TTL UDP doit être un entier entre 1-254 !",
    contrastError: "L'amélioration du contraste doit être un entier entre 0-63 !",
    sharpnessError: "L'amélioration de la netteté doit être un entier entre 0-16 !",
    lumaSfError: "Le débruitage spatial luma doit être un entier entre 0-255 !",
    lumaTfError: "Le débruitage temporel luma doit être un entier entre 0-63 !",
    chromaSfError: "Le débruitage spatial chroma doit être un entier entre 0-255 !",
    chromaTfError: "Le débruitage temporel chroma doit être un entier entre 0-32 !",
    hlsSplitError: "Le temps de segment HLS doit être un entier entre 3-10 !",
    hlsBufferError: "Le nombre de segments HLS doit être un entier entre 3-10 !",
    hlsUriError: "Le format de l'URI d'index global HLS est invalide !",
    udpSockBufError: "UDP SOCKET_BUF_SIZE doit être un entier entre 0-20971520 !",
    mtuError: "La taille MTU doit être un entier entre 500-1500 !",
    deblockingAlphaError: "Deblocking alpha must be an integer between -6 and 6!",
    deblockingBetaError: "Deblocking beta must be an integer between -6 and 6!",


    audioCacheError: "Le délai audio doit être un entier entre -2000 et 2000 !",
    recordSplitError: "Le temps de division d'enregistrement doit être un entier entre 60-7200 !",
    lokiPortError: "Le port serveur Loki doit être entre 1-65535"
  },

  // Audio Encoding Settings
  audioEnc: {
    blkInput: "Entrée",
    blkEncode: "Encodage",
    blkVolume: "Volume",
    blkVolumeNote: "Gain fixe manuel",
    blkAgc: "Gain automatique",
    blkAgcNote: "Ramène automatiquement le volume fluctuant à la cible",
    blkDenoise: "Réduction du bruit",
    blkDenoiseNote: "Supprime le bruit de fond ; CPU élevé, généralement désactivé",
    mute: "Muet",
    gain0: "0 dB (inchangé)",
    agcLevel: "Niveau cible AGC (dBFS) :",
    agc: "Contrôle automatique de gain :",
    agcLevelError: "Le niveau cible AGC doit être compris entre -42 et -12 dBFS !",
    title: "Paramètres audio",
    // Tabs
    tabAudio: "Paramètres audio",
    tabOnvif: "Audio ONVIF",
    // Tips
    tipAudio: "Ne réglez pas le gain de volume numérique trop haut, cela peut causer des distorsions ou du bruit.<br>Dans la plupart des cas, réglez le gain sur 0.<br>Ajustez le volume global avec les contrôles frontaux.",
    tipVolVsAgc: "<b>Gain de volume vs gain automatique (AGC)</b><br>Le gain de volume est un gain fixe réglé manuellement : les valeurs positives amplifient, les valeurs négatives atténuent. Il ne varie pas avec le signal d'entrée et convient aux sources dont le niveau est stable et prévisible.<br>Le gain automatique (AGC) ajuste le gain en fonction du niveau en temps réel du signal d'entrée, maintient la sortie près du niveau cible et lisse un audio qui passe du fort au faible.<br>Lorsque l'AGC est activé, maintenez le gain de volume à 0 dB pour que l'AGC contrôle seul le niveau et éviter de superposer deux réglages.",
    tipAgcLevel: "<b>Niveau cible de l'AGC (dBFS)</b><br>Définit la référence de niveau finale. Plus la cible est proche de 0 dBFS, plus la sortie est forte, mais moins il reste de marge pour les crêtes transitoires et plus l'écrêtage survient facilement.<br>• -18 dBFS (recommandé) : équilibre entre volume et marge, adapté à la plupart des situations.<br>• -12 dBFS : l'option la plus forte, idéale pour le direct et autres scénarios à fort volume ; mais avec seulement 12 dB de marge, les sons forts soudains écrêtent facilement.<br>• -20 ~ -24 dBFS : adapté à la voix, aux performances live et autres entrées à fortes variations de crête.<br>• -30 ~ -42 dBFS : adapté aux entrées microphone à gain élevé ou aux environnements bruyants.",
    tipOnvif: "Pour se connecter à un NVR, réglez l'encodage RTSP G711 sur 'Activer et rééchantillonner à 8K'",
    // Audio Settings
    audioInput: "Entrée audio :",
    sampleRate: "Taux d'échantillonnage :",
    codec: "Codec :",
    channel: "Canaux :",
    bitrate: "Débit :",
    digitalGain: "Gain de volume numérique :",
    analogGain: "Gain de volume analogique :",
    denoise: "Débruitage :",
    denoiseStrength: "Force de débruitage (dB) :",
    pteG711: "Flux PTE G711 :",
    // Audio Input Options
    inputDigital: "Numérique",
    inputAnalog: "Analogique",
    inputMixed: "Mixte",
    // Sample Rate Options
    sampleSameAsInput: "Identique à l'entrée",
    // ONVIF Audio
    rtspG711: "Encodage RTSP G711 :",
    rtspG711Resample: "Activer et rééchantillonner à 8K",
    g711Codec: "Codec G711 :",
    // Buttons and Messages
    save: "Enregistrer",
    success: "Paramètres enregistrés !",
    failed: "Échec des paramètres !",
    emptyError: "Les paramètres ne peuvent pas être vides !",
    bitrateError: "Le débit doit être un entier entre {0}-{1} !",
    gainError: "Le gain de volume numérique doit être un entier entre -20 et 10 !",
    denoiseError: "La force de débruitage doit être un entier entre 1-100 !",
    analogVolEmpty: "Le gain de volume analogique ne peut pas être vide !",
    analogVolError: "Le gain de volume analogique doit être un entier entre {0} et {1} !"
  },

  // Recording Settings Page
  recordSet: {
    title: "Paramètres d'enregistrement",
    // Card Titles
    statusTitle: "État d'enregistrement",
    settingsTitle: "Paramètres d'enregistrement",
    // Status
    recordType: "Type d'enregistrement :",
    diskStatus: "État du disque :",
    currentAddr: "Adresse actuelle :",
    mountDevice: "Périphérique de montage :",
    mountStatus: "État du montage :",
    totalSpace: "Espace total :",
    freeSpace: "Espace libre :",
    recordStatus: "État d'enregistrement :",
    recordFiles: "Fichiers d'enregistrement :",
    fileList: "Liste des fichiers",
    // Disk Status
    diskNotExist: "Non présent",
    diskFull: "Disque plein",
    diskSlow: "Disque trop lent",
    mounted: "Monté",
    unmounted: "Non monté",
    notRecording: "Pas d'enregistrement",
    recording: "Enregistrement en cours",
    noVideoWarning: " (Les fichiers peuvent ne pas être sauvegardés sans entrée vidéo)",
    // Action Links
    startRecord: "(Démarrer l'enregistrement)",
    stopRecord: "(Arrêter l'enregistrement)",
    mountDisk: "(Monter le disque)",
    unmountDisk: "(Démonter le disque)",
    deleteAll: "(Supprimer tous les enregistrements)",
    // Settings
    storageType: "Type de stockage :",
    partition: "Partition :",
    partitionInfo: "Info partition :",
    diskInfo: "Info disque :",
    formatDisk: "(Reformater le disque)",
    exampleAddr: "Adresse exemple :",
    storageAddr: "Adresse de stockage :",
    username: "Nom d'utilisateur :",
    password: "Mot de passe :",
    // Storage Type Options
    storageDisabled: "Désactivé",
    storageUsb: "USB/Carte TF",
    storageNfs: "NFS",
    storageSamba: "SAMBA/CIFS",
    // Format Dialog
    formatTitle: "Information du disque",
    formatDevice: "Périphérique :",
    formatType: "Type :",
    formatModel: "Modèle :",
    formatRemovable: "Amovible :",
    formatPartTable: "Table de partition :",
    formatCapacity: "Capacité :",
    formatPartitions: "Information des partitions",
    formatPartition: "Partition",
    formatAvailable: "(disponible)",
    formatTotal: "(total)",
    formatConfirm: "Continuer le formatage du disque ?",
    formatDanger: "Attention : Le formatage va repartitionner et toutes les données seront perdues. Continuer ?",
    formatContinue: "Continuer",
    formatCancel: "Annuler",
    formatConfirmBtn: "Confirmer",
    formatting: "Formatage...",
    // Buttons and Messages
    save: "Enregistrer",
    yes: "Oui",
    no: "Non",
    success: "Paramètres enregistrés !",
    failed: "Échec des paramètres !",
    formatSuccess: "Formatage réussi !",
    formatFailed: "Échec du formatage !",
    deleteSuccess: "Commande de suppression envoyée !",
    deleteFailed: "Échec de la suppression !",
    confirmDeleteAll: "Supprimer tous les fichiers d'enregistrement ?",
    recordingWarning: "Enregistrement en cours. Arrêtez l'enregistrement avant de démonter.",
    diskMountedWarning: "Le disque est monté. Démontez avant de formater.",
    diskMountedSettingWarning: "Le disque est monté. Démontez avant de modifier les paramètres.",
    storageLockedHint: "Verrouillé lorsque le disque est monté ; démontez-le pour modifier.",
    partitionNotExist: "La partition n'existe pas",
    partitionRemoved: " (Supprimée)",
    unpartitioned: " (non partitionné)",
    unpartitionedHint: "Le disque n'a aucune partition, veuillez d'abord le repartitionner et le formater",
    // Address Validation
    addrEmpty: "L'adresse de stockage ne peut pas être vide !",
    addrNfsFormat: "Format d'adresse invalide, doit contenir le séparateur ':'",
    addrIpError: "Format d'adresse IP invalide",
    addrPathSlash: "Le chemin doit commencer par '/'",
    addrPathInvalid: "Le chemin contient des caractères invalides",
    addrSambaStart: "L'adresse doit commencer par '\\\\'",
    addrSambaFormat: "Adresse invalide, doit contenir IP et chemin séparés par '\\'",
    addrPathEmpty: "Le chemin ne peut pas être vide",
    addrPathChars: "Le chemin contient des caractères invalides, seuls les lettres, chiffres, tirets bas et tirets sont autorisés",
    // Disk size info "{available} / {total}"
    diskSizeInfo: "{0} (disponible) / {1} (total)"
  },
  // GB28181 Settings
  gb28181: {
    title: "Paramètres GB28181",
    basicSettings: "Paramètres de base",
    heartbeatSettings: "Paramètres de battement de cœur",
    sipServerSettings: "Paramètres du serveur SIP",
    authSettings: "Paramètres d'authentification",
    enable: "Activer :",
    disabled: "Désactivé",
    enabled: "Activé",
    localSipPort: "Port SIP local :",
    videoChannelId: "ID du canal vidéo :",
    streamSelect: "Sélection du flux :",
    mainStream: "Flux principal",
    subStream1: "Flux secondaire 1",
    subStream2: "Flux secondaire 2",
    subStream3: "Flux secondaire 3",
    regExpiry: "Expiration d'enregistrement :",
    heartbeatCycle: "Cycle de battement de cœur :",
    maxHeartbeatTimeout: "Timeout max de battement de cœur :",
    sipServerId: "ID du serveur SIP :",
    sipServerDomain: "Domaine du serveur SIP :",
    sipServerAddr: "Adresse du serveur SIP :",
    sipServerPort: "Port du serveur SIP :",
    sipUserId: "ID utilisateur SIP :",
    sipPassword: "Mot de passe SIP :",
    emptyError: "Les paramètres ne peuvent pas être vides !",
    localPortError: "Le port SIP local doit être un entier entre 1-65535 !",
    serverPortError: "Le port du serveur SIP doit être un entier entre 1-65535 !",
    regExpiryError: "L'expiration d'enregistrement doit être un entier entre 100-100000 !",
    heartbeatError: "Le cycle de battement de cœur doit être un entier entre 5-3600 !",
    maxTimeoutError: "Le timeout max de battement de cœur doit être un entier entre 3-255 !",
    success: "Paramètres enregistrés avec succès !",
    failed: "Échec des paramètres !"
  },
  // Video Source Settings
  videoSource: {
    title: "Paramètres de source vidéo",
    videoInput: "Paramètres d'entrée vidéo",
    brightAdjust: "Ajustement de luminosité d'entrée",
    videoOutput: "Paramètres de sortie vidéo",
    inputFormat: "Format d'entrée vidéo :",
    yuv422: "YUV422",
    yuv420: "YUV420 (Rotation supportée)",
    rotation: "Angle de rotation :",
    flipMirror: "Retournement/Miroir :",
    flipDisable: "Désactivé",
    mirror: "Miroir",
    flip: "Retournement",
    flipAndMirror: "Miroir et Retournement",
    cropEnable: "Recadrage vidéo :",
    cropLeft: "Point de départ du recadrage (Gauche) :",
    cropTop: "Point de départ du recadrage (Haut) :",
    cropWidth: "Largeur de recadrage :",
    cropHeight: "Hauteur de recadrage :",
    monochrome: "Monochrome :",
    colorMode: "Mode couleur d'entrée :",
    unknown: "Inconnu",
    brightEnable: "Ajustement de luminosité :",
    gain: "Gain :",
    gainHint: "[10-1000], défaut 100",
    offset: "Décalage :",
    offsetHint: "[0-100], défaut 0",
    note: "Note :",
    brightNote1: "1. Luminosité = (Luminosité originale * Gain / 100) + Décalage",
    brightNote2: "2. L'ajustement de luminosité ne fonctionne qu'en mode couleur d'entrée RVB",
    outputRes: "Résolution de sortie vidéo :",
    auto: "Auto",
    cscEnable: "Ajustement CSC :",
    luminance: "Luminance :",
    contrast: "Contraste :",
    hue: "Teinte :",
    saturation: "Saturation :",
    cscHint: "[0-100], défaut 50",
    rotateHint: "Les rotations 180° et 270° peuvent être obtenues en combinant une rotation 0°/90° avec un retournement/miroir.",
    emptyError: "Les paramètres ne peuvent pas être vides !",
    gainError: "Le gain doit être un entier entre 10-1000 !",
    offsetError: "Le décalage doit être un entier entre 0-100 !",
    leftError: "La valeur gauche doit être un entier entre 0-{0} !",
    topError: "La valeur haut doit être un entier entre 0-{0} !",
    widthError: "La valeur de largeur doit être un entier entre 400-{0} !",
    heightError: "La valeur de hauteur doit être un entier entre 400-{0} !",
    luminanceError: "La luminance doit être un entier entre 0-100 !",
    contrastError: "Le contraste doit être un entier entre 0-100 !",
    hueError: "La teinte doit être un entier entre 0-100 !",
    saturationError: "La saturation doit être un entier entre 0-100 !",
    success: "Paramètres enregistrés avec succès !",
    failed: "Échec des paramètres !"
  },
  // Network Settings
  network: {
    title: "Paramètres réseau",
    ipv4Title: "Paramètres IPv4",
    ipv6Status: "État IPv6",
    ipv6Title: "Paramètres IPv6",
    ipv6TypeGlobal: "IP globale",
    ipv6TypeLinkLocal: "IP lien-local",
    ipv6TypeUniqueLocal: "IP locale",
    ipv6TypeMulticast: "IP multicast",
    ipv6TypeGeneric: "IP",
    ipv6StatusGateway: "Passerelle",
    dnsTitle: "Paramètres DNS",
    ntpTitle: "Paramètres NTP",
    portTitle: "Paramètres de port",
    httpsTitle: "Paramètres HTTPS",
    hostnameTitle: "Paramètres HOSTNAME",
    dhcp: "DHCP :",
    dhcpHint: "Après avoir activé DHCP, l'appareil peut être trouvé par les outils de recherche compatibles ONVIF.",
    ipAddr: "Adresse IP :",
    netmask: "Masque de sous-réseau :",
    gateway: "Passerelle filaire :",
    macAddr: "Adresse MAC :",
    defaultGateway: "Passerelle par défaut :",
    lanFirst: "Filaire d'abord",
    wifiFirst: "WiFi d'abord",
    g4First: "4G/5G d'abord",
    ipv6Mode: "Mode :",
    ipv6Disable: "Désactivé",
    ipv6Auto: "Configuration auto",
    ipv6Manual: "Configuration manuelle",
    ipv6Addr: "Adresse IPv6 :",
    ipv6Prefix: "Longueur du préfixe IPv6 :",
    ipv6Gateway: "Passerelle par défaut IPv6 :",
    dns1: "DNS1 :",
    dns2: "DNS2 :",
    ntpSync: "Synchronisation NTP :",
    ntpServer: "Serveur :",
    timezone: "Fuseau horaire :",
    httpPort1: "Port HTTP 1 :",
    httpPort2: "Port HTTP 2 :",
    rtspPort1: "Port RTSP 1 :",
    rtspPort2: "Port RTSP 2 :",
    onvifPort: "Port ONVIF:",
    sadpProtocol: "Port SADP:",
    httpsService: "Service HTTPS :",
    httpsPort1: "Port HTTPS 1 :",
    httpsPort2: "Port HTTPS 2 :",
    httpsPrivatePass: "Mot de passe clé privée HTTPS :",
    socks5Title: "SOCKS5 Proxy",
    socks5Enable: "SOCKS5 Proxy:",
    socks5Host: "Proxy Host:",
    socks5Port: "Proxy Port:",
    socks5User: "Username:",
    socks5Pass: "Password:",
    socks5AuthHint: "(Optional authentication, username and password must both be set)",
    privatePassHint: "(Laisser vide si pas de mot de passe)",
    uploadCert: "Télécharger le certificat :",
    uploadCertHint: "(Le nom de fichier doit être private.key ou public.crt. Ne pas télécharger simultanément ou éteindre pendant le téléchargement)",
    uploadBtn: "Télécharger le certificat",
    deleteCert: "Supprimer le certificat",
    hostname: "HOSTNAME :",
    mdnsService: "Service mDNS :",
    mdnsAddr: "Adresse d'accès mDNS :",
    portRange: "[1-65535]",
    prefixRange: "[0-128]",
    emptyError: "Les paramètres ne peuvent pas être vides !",
    ipError: "Format d'adresse IP invalide !",
    netmaskError: "Format de masque de sous-réseau invalide !",
    gatewayError: "Format de passerelle invalide !",
    dns1Error: "Format de DNS primaire invalide !",
    dns2Error: "Format de DNS secondaire invalide !",
    macError: "Format d'adresse MAC invalide !",
    ipv6Error: "Format d'adresse IPv6 invalide !",
    ipv6PrefixError: "Longueur de préfixe IPv6 invalide (1-128) !",
    ipv6GatewayError: "Format de passerelle IPv6 invalide !",
    httpPort1Error: "Le port HTTP 1 doit être un entier entre 1-65535 !",
    httpPort2Error: "Le port HTTP 2 doit être un entier entre 1-65535 !",
    rtspPort1Error: "Le port RTSP 1 doit être un entier entre 1-65535 !",
    rtspPort2Error: "Le port RTSP 2 doit être un entier entre 1-65535 !",
    httpsPort1Error: "Le port HTTPS 1 doit être un entier entre 1-65535 !",
    httpsPort2Error: "Le port HTTPS 2 doit être un entier entre 1-65535 !",
    onvifPortError: "Le port ONVIF doit être un entier entre 1-65535 !",
    sadpPortError: "Le port SADP doit être un entier entre 1-65535 !",
    httpBothDisableError: "Le port HTTP 1 et le port 2 ne peuvent pas être tous les deux désactivés !",
    httpsBothDisableError: "Quand HTTPS est activé, le port 1 et le port 2 ne peuvent pas être tous les deux désactivés !",
    socks5HostError: "Invalid SOCKS5 proxy host!",
    socks5PortError: "SOCKS5 proxy port must be an integer between 1-65535!",
    socks5AuthPairError: "SOCKS5 username and password must both be set or both be empty!",
    socks5AuthLengthError: "SOCKS5 username and password must not exceed 255 characters!",
    ntpEmptyError: "Le serveur NTP ne peut pas être vide !",
    ntpFormatError: "Adresse du serveur NTP invalide !",
    hostnameEmptyError: "HOSTNAME ne peut pas être vide !",
    hostnameFormatError: "HOSTNAME invalide !\n\n1. HOSTNAME ne doit pas dépasser 63 caractères !\n2. Seuls les lettres (a-z), chiffres (0-9), tirets (-) et tirets bas (_) sont autorisés !\n3. '-' et '_' ne peuvent pas apparaître consécutivement, seuls, ou au début/fin !",
    deleteCertConfirm: "Êtes-vous sûr de vouloir supprimer le certificat HTTPS téléchargé ?",
    selectFile: "Veuillez sélectionner un fichier à télécharger !",
    uploadSuccess: "Téléchargement réussi !",
    uploadFailed: "Échec du téléchargement !",
    fileSizeError: "La taille du fichier image dépasse la limite !",
    fileResError: "La résolution de l'image dépasse la limite !",
    spaceError: "Fichier de mise à jour trop volumineux, espace de stockage insuffisant !",
    deleteSuccess: "Supprimé avec succès !",
    deleteFailed: "Échec de la suppression !",
    successReboot: "Paramètres enregistrés, veuillez redémarrer l'appareil !",
    failed: "Échec des paramètres !"
  },

  // Output Settings Page (Stream Settings)
  output: {
    // Tab names
    tabs: {
      ndi: "NDI",
      encode: "Encodage",
      ts: "TS/Multicast",
      mjpeg: "MJPEG",
      rtsp: "RTSP",
      rtmp: "RTMP",
      srt: "SRT",
      webrtc: "WebRTC",
      trtc: "TRTC",
      alirtc: "AliRTC",
      hls: "HLS",
      other: "MP4/FLV/Autre"
    },

    // Encoding settings
    encode: {
      codecType: "Type de codec :",
      frameRate: "Fréquence d'images :",
      sameAsInput: "Identique à l'entrée",
      auto: "Auto",
      customFrameRate: "Fréquence personnalisée",
      customFrameRateLabel: "Fréquence personnalisée :",
      gopInterval: "Intervalle GOP (images) :",
      bitrate: "Débit (kbit) :",
      qualityRange: "Plage de qualité :",
      qualityStrict: "Strict (Haut)",
      qualityTight: "Serré (Proche-Haut~Haut)",
      qualityNormal: "Normal (Moyen~Haut)",
      qualityLoose: "Souple (Proche-Bas~Haut)",
      qualityWide: "Large (Bas~Haut)",
      mjpegQuality: "Qualité MJPEG :",
      outputResolution: "Résolution de sortie :",
      h264Profile: "Profil H.264 :",
      bitrateControl: "Contrôle de débit :",
      cbrStableRange: "CBR Stability Range:",
      cbrStableMin: "min",
      cbrStableMax: "max",
      bFramesMode: "B-Frame Mode:",
      bFramesDisable: "Disabled",
      bFramesIbp: "IBP",
      bFramesIbbp: "IBBP",
      // Tips
      tipCodec: "H.265 offre une meilleure qualité vidéo que H.264. Utilisez H.265 si votre décodeur le supporte.",
      tipVbr: "En mode VBR, le débit est régulé par \"Plage de qualité\"; La plage de qualité limite les valeurs QP;<br>Sélectionner \"Proche-Haut~Haut\" ou \"Haut\" donne un débit réel très élevé, rendant le débit défini sans signification;<br>Seul quand la plage de qualité est \"Proche-Bas~Haut\" le débit a une valeur de référence;",
      tipCbr: "\"CBR fort\" est utilisé pour les systèmes CATV pour assurer un débit TS stable. Avec \"CBR fort\" à 1080P, le débit ne doit pas être inférieur à 5000kbit/s, 8000kbit/s recommandé.",
      tipGop: "En supposant que la fréquence d'images vidéo d'entrée est n, les valeurs courantes sont 60, 50, 30, 25;<br>L'intervalle GOP est typiquement réglé à n * 2, les valeurs courantes sont 120, 100, 60, 50;<br>Quand la fréquence d'images est sur Auto, si n > 30, la fréquence d'encodage est n / 2, sinon elle égale n"
    },

    // TS/Multicast settings
    ts: {
      tsUri: "URL du flux TS :",
      multicastIp: "IP Multicast :",
      multicastPort: "Port Multicast :",
      sapName: "Nom SAP :",
      tsVideoPid: "PID vidéo TS :",
      tsAudioPid: "PID audio TS :",
      tsTransportStreamId: "ID flux transport TS :",
      tsOriginalNetworkId: "ID réseau original TS :",
      tsPmtStartPid: "PID départ PMT TS :",
      tsStartPid: "PID départ TS :",
      tsTablesVersion: "Version tables TS :",
      tsServiceId: "ID service TS :",
      tsServiceName: "Nom service TS :",
      tsProviderName: "Nom fournisseur TS :",
      tsPcrPeriod: "Période PCR TS (ms) :",
      conformSystemB: "Conforme Système B (DVB) :",
      tsNullPacket: "Paquets nuls TS :",
      noInsert: "Pas d'insertion",
      insert12: "Insérer (1.2x)",
      insert13: "Insérer (1.3x)",
      insert15: "Insérer (1.5x)",
      insert20: "Insérer (2x)",
      insert25: "Insérer (2.5x)",
      tsTdt: "TS TDT :",
      // Tips
      tipMulticast: "L'adresse multicast peut aussi accepter des adresses broadcast ou unicast, le système détecte automatiquement.",
      tipVlc: "Si VLC ne peut pas lire le multicast, vérifiez si votre ordinateur a plusieurs adaptateurs réseau, essayez d'en changer.",
      tipSap: "Le nom SAP peut être vu sur les appareils supportés, comme la playlist VLC -> Réseau local.",
      tipAdvanced: "Les paramètres avancés TS n'ont généralement pas besoin d'être ajustés.",
      tipIptv: "Lors de la connexion aux systèmes IPTV, les paquets nuls TS doivent être ajustés à 1.3x, l'appareil insère automatiquement des paquets nuls pour assurer un débit stable;<br>Ce paramètre ne s'applique qu'au mode \"CBR fort\"."
    },

    // MJPEG settings

    mjpeg: {

      jpgUri: "JPG Image URL:",

      mjpgUri: "MJPG Stream URL:",

      // Tips

      tipJpg: "JPG is a still image; MJPG is a motion image.",

      tipMjpg: "Both can be opened directly in a browser."

    },


    // RTSP settings
    rtsp: {
      rtspUri: "URL flux RTSP :",
      enableMulticast: "Activer (Multicast)",
      enableTcpOnly: "Activer (TCP uniquement)",
      multicastIp: "IP Multicast RTSP :",
      multicastPort: "Port Multicast RTSP :",
      // Tips
      tipEnable: "Si Activer est sélectionné, le transport réel (UDP ou TCP) est déterminé par le client. Par exemple, dans VLC vous pouvez cocher \"RTP over RTSP(TCP)\" pour utiliser TCP.",
      tipTcpOnly: "Sélectionner Activer (TCP uniquement) force l'appareil à utiliser TCP.",
      tipUdp: "UDP peut occasionnellement perdre des paquets à cause de problèmes réseau. Si tous les clients le supportent, TCP est recommandé.",
      tipMulticast: "Sélectionner Activer (Multicast) utilisera 4 ports consécutifs à partir du \"Port Multicast RTSP\"."
    },

    // RTMP settings
    rtmp: {
      rtmpUri: "URL flux RTMP :",
      publishUri0: "URL publication RTMP(S)/RTSP 0 :",
      publishUri1: "URL publication RTMP(S)/RTSP 1 :",
      publishUri2: "URL publication RTMP(S)/RTSP 2 :",
      mode: "Mode de diffusion RTMP :",
      modeStandard: "Standard (Enhanced RTMP)",
      modeLegacy: "Legacy (CodecID 12)",
      // Tips
      tipPublish: "Les URL de publication 0-2 sont pour pousser les flux vers d'autres serveurs RTMP/RTSP LAN ou publics, supportant H.265/H.264.",
      tipBuiltin: "Cet appareil intègre un serveur RTMP compatible avec la lecture en H.264/H.265;<br>Si l'URL du flux RTMP est définie sur \"/live/0\", PotPlayer peut lire via http://IP-appareil/live/0.",
      tipMode: "Le mode de diffusion RTMP s'applique uniquement au H.265 et affecte aussi le flux FLV ;"
    },

    // SRT settings
    srt: {
      listenerUri: "URL SRT Listener :",
      callerUri: "URL SRT Caller :",
      // Tips
      tipListener: "Le mode SRT Listener écoute sur un port local pour que les lecteurs puissent tirer le flux.<br>Par exemple, définir srt://0.0.0.0:9000;<br>VLC peut alors lire \"srt://IP-appareil:9000\".<br>Ajout streamid exemple:<br>srt://0.0.0.0:9000?streamid=channel100<br>Ajout mot de passe exemple (minimum 10 caractères):<br>srt://0.0.0.0:9000?passphrase=0123456789<br>Ajout streamid et mot de passe:<br>srt://0.0.0.0:9000?streamid=channel100&passphrase=0123456789",
      tipCaller: "Le mode SRT Caller pousse le flux vers un autre serveur, ex.:<br>srt://live.example.com:9000?streamid=channel100&latency=120&maxbw=8000000",
      tipParams: "Paramètres SRT supportés (voir protocole SRT pour détails):<br>streamid - identifiant de flux pour multiplexage<br>passphrase - mot de passe de chiffrement, SRT requiert 10-79 caractères<br>pbkeylen - longueur de clé: 16 (AES-128), 24 (AES-192), 32 (AES-256)<br>latency - latence en ms (20-8000ms)<br>maxbw - bande passante max en octets/sec<br>rcvbuf - taille buffer de réception<br>sndbuf - taille buffer d'envoi<br>ipttl - valeur IP TTL<br>conntimeo - timeout de connexion en ms"
    },

    ndi: {
      enable: "Sortie NDI :",
      name: "Nom de la source :",
      mainStream: "Flux pleine qualité :",
      previewStream: "Flux d'aperçu (fixé à 640x360) :",
      groups: "Groupes NDI :",
      tipScope: "Une fois NDI activé, les récepteurs du LAN (NDI Studio Monitor, vMix, OBS, etc.) détectent automatiquement cette source ; elle apparaît sous la forme : NomDeLAppareil (Nom de la source).",
      tipPreview: "NDI exige un flux pleine qualité plus un flux d'aperçu de 640 pixels de large. Une fois activé, la résolution du flux d'aperçu sélectionné est fixée à 640x360.",
      unlicensed: "Saisissez un code de licence pour activer.",
      unlicensedHint: "Version sans licence, limitée à 30 minutes. ",
      licenseCode: "Code de licence :",
      activate: "Activer",
      deviceId: "ID de l'appareil :",
      deviceTypeLabel: "Type d'appareil :",
      globalTitle: "Paramètres globaux (appliqués à tous les ports)",
      tabGlobal: "Paramètres globaux",
      gotoLicense: "Aller à l'activation",
      discoveryEnable: "Discovery Server :",
      discoveryServer: "Adresse du serveur :",
      serverHint: "Le port par défaut du Discovery Server est 5959.",
      sendMode: "Mode d'envoi des données :",
      sendModeAuto: "Automatique (unicast)",
      sendModeMulticast: "Multicast",
      multicastAddr: "Préfixe d'adresse multicast :",
      multicastMask: "Masque multicast :",
      tipDiscovery: "Lorsque le Discovery Server est activé, cet appareil n'utilise plus mDNS ; les récepteurs doivent être configurés avec la même adresse de Discovery Server pour trouver les sources. Adapté aux réseaux routés ou sans multicast. Séparez plusieurs serveurs par des virgules.",
      tipMulticast: "L'envoi multicast permet à plusieurs récepteurs de partager un même flux, mais exige un IGMP snooping correctement configuré sur les commutateurs ; l'activer sur un réseau non préparé peut le saturer. À utiliser uniquement sur des réseaux administrés."
    },
    // WebRTC settings
    webrtc: {
      previewTitle: "Aperçu web",
      previewNote: "(aperçu à faible latence sur la page d'état)",
      whipTitle: "Publication WHIP",
      whipNote: "(envoi vers un serveur, pour de nombreux spectateurs)",
      p2pTitle: "P2P à distance",
      p2pNote: "(traversée NAT, pour quelques spectateurs distants)",
      optional: "facultatif",
      preview: "Aperçu web",
      whipServer: "URL de diffusion",
      whipToken: "Jeton Bearer",
      p2pServer: "URL du serveur de signalisation",
      p2pUuid: "UUID de l'appareil",
      p2pToken: "Token auth P2P :",
      p2pAuthToken: "Jeton d'autorisation",
      regenerate: "Régénérer",
      // Tips
      tipPreview: "L'aperçu WebRTC dans les navigateurs courants supporte l'encodage vidéo H.264 et audio Opus/G.711.<br>Régler l'audio sur Opus donne de meilleurs résultats. Si non réglé sur Opus, défaut G.711 8K.",
      tipWhip: "Le streaming WHIP se connecte aux serveurs WHIP standard. Copiez l'adresse depuis votre serveur.<br>Le token Bearer peut être vide.",
      tipP2p: "Après avoir activé le serveur P2P, l'URL de visionnage est affichée sur la page d'état.<br>Le token auth P2P peut être vide.",
      tipP2pNote: "P2P peut ne pas se connecter dans des environnements intranet complexes."
    },

    // TRTC settings
    trtc: {
      roomId: "ID de salle TRTC :",
      userId: "Nom d'utilisateur TRTC :",
      roomKey: "Clé de salle TRTC :",
      userSig: "UserSig TRTC :",
      sdkAppId: "SDKAppID TRTC :",
      roomIdType: "Type d'ID de salle TRTC :",
      roomIdNumber: "Nombre",
      roomIdString: "Chaîne",
      // Short enum labels for template use
      number: "Nombre",
      string: "Chaîne",
      // Tips
      tipTrtc: "Pousser les flux vers le serveur Tencent TRTC. Copiez l'adresse depuis le serveur.<br>Tencent TRTC ne supporte actuellement que H.264."
    },

    alirtc: {
      roomId: "ID de salle AliRTC :",
      userId: "ID utilisateur AliRTC :",
      userName: "Nom d'utilisateur AliRTC :",
      region: "Région AliRTC :",
      token: "AliRTC Token :",
      tipAliRtcToken: "Pousse les flux vers Alibaba Cloud RTC avec prise en charge H.265/H.264.<br>Vous pouvez saisir directement le token fourni par le service, ou cliquer sur AliRTC Token pour générer un token avec l'AppID/AppKey dans la page séparée.<br>Si le token est vide, l'appareil essaiera de le générer automatiquement au démarrage à partir de l'AppID/AppKey enregistrés dans la page séparée.<br>Si l'ID de salle, l'ID utilisateur ou le nom d'utilisateur change, il peut être nécessaire de régénérer le token."
    },

    alirtcTokenPage: {
      title: "AliRTC Token",
      roomId: "ID de salle AliRTC :",
      userId: "ID utilisateur AliRTC :",
      userName: "Nom d'utilisateur AliRTC :",
      appId: "AliRTC AppID :",
      appKey: "AliRTC AppKey :",
      token: "AliRTC Token :",
      generate: "Générer et enregistrer le token",
      appFieldsRequired: "L'AppID et l'AppKey AliRTC sont obligatoires.",
      identityRequired: "L'ID de salle, l'ID utilisateur et le nom d'utilisateur AliRTC sont obligatoires dans les paramètres de sortie du flux actuel.",
      generateSuccess: "Le token AliRTC a été généré et enregistré.",
      generateFailed: "Échec de la génération du token AliRTC.",
      unavailable: "AliRTC n'est pas disponible sur cet appareil."
    },

    // HLS settings
    hls: {
      hlsTsUri: "URL flux HLS TS :",
      hlsMp4Uri: "URL flux HLS MP4 :",
      hlsPushUri: "URL PUSH HLS :",
      hlsPushUrl: "URL PUSH HLS :",
      // Tips
      tipHls: "Quand HLS TS/MP4 est activé, l'appareil met en buffer les données en mémoire selon le temps et le nombre de segments dans les paramètres avancés.<br>Régler le temps et le nombre de segments à 3 réduit l'utilisation mémoire.",
      tipPush: "L'URL de publication HLS est pour pousser vers des serveurs comme YouTube."
    },

    // MP4/FLV/Other settings
    other: {
      mp4Uri: "URL flux MP4 :",
      flvUri: "URL flux FLV :",
      icecastUri: "URL PUSH ICECAST :",
      icecastPushUrl: "URL PUSH ICECAST :",
      shoutcastUri: "URL PUSH Shoutcast :",
      shoutcastPushUrl: "URL PUSH Shoutcast :",
      // Tips
      tipMp4: "Quand le flux MP4 est activé, il peut être lu directement dans le navigateur.<br>Le flux FLV supporte H.265/H.264 sur cet appareil, mais VLC et autres lecteurs ne supportent actuellement que H.264.<br>ICECAST/Shoutcast ne supporte que MP3, pour pousser vers des serveurs audio.",
      tipShoutcast: "Shoutcast supporte v1 et v2;<br>Exemples:<br>http://motdepasse@serveur_shoutcast:8000<br>http://motdepasse@serveur_shoutcast:8000?sid=100<br>http://motdepasse@serveur_shoutcast:8000?icy-name=Stream&icy-genre=Pop<br>Format:<br>http://motdepasse@IP-serveur:port-écoute[?params...]; le nom d'utilisateur peut être omis (défaut \"source\").<br>Utilisez le \"port d'écoute\" du serveur, l'appareil se connecte automatiquement au port source (port d'écoute + 1).<br>Paramètres supportés:<br>sid: ID de flux Shoutcast v2 (défaut 1)<br>icy-name: nom du flux (optionnel)<br>icy-genre: genre (optionnel)<br>icy-url: URL du site web (optionnel)<br>icy-pub: public 0/1 (optionnel)"
    },

    // Common
    common: {
      save: "Enregistrer",
      disabled: "Désactivé",
      enabled: "Activé"
    },

    // Error and success messages
    messages: {
      success: "Paramètres enregistrés !",
      failed: "Échec des paramètres !",
      emptyError: "Les paramètres ne peuvent pas être vides !",
      trtcH264Only: "Quand TRTC est activé, seul l'encodage H.264 est supporté. Changé automatiquement.",
      mp3Required: "Veuillez régler l'encodage audio sur MP3 !",
      subStreamDisabled: "Sub-stream settings are disabled.",
      // Encoding validation
      frameRateError: "La fréquence d'images doit être un entier entre 5-60 !",
      gopError: "L'intervalle GOP doit être un entier entre 5-300 !",
      mjpegQualityError: "La qualité MJPEG doit être un entier entre 10-99 !",
      hlsBitrateWarning: "Débit hors plage 32~8000, flux HLS TS/MP4/PUSH désactivés.",
      trtcCodecWarning: "Le codec n'est pas H.264, TRTC désactivé.",
      alirtcFieldsRequired: "Lorsque AliRTC est activé, l'AppID, l'AppKey, l'ID de salle, l'ID utilisateur et le nom d'utilisateur sont obligatoires.",
      alirtcIdentityRequired: "Lorsque AliRTC est activé, l'ID de salle, l'ID utilisateur et le nom d'utilisateur ne peuvent pas être vides.",
      hlsBitrateError: "Débit hors plage 32~8000, impossible d'activer les flux HLS TS/MP4/PUSH",
      // SRT validation
      srtListenerPortError: "Le port SRT Listener doit être un entier entre 1-65535 !",
      srtListenerFormatError: "Format d'URL SRT Listener invalide !",
      srtCallerFormatError: "Format d'URL SRT Caller invalide !",
      srtPasswordLengthError: "La phrase secrète SRT après décodage URL doit contenir entre 10 et 79 octets !",
      srtLatencyError: "La latence SRT doit être un entier entre 1-10000 !",
      srtBandwidthError: "La bande passante SRT doit être un entier entre 0-102400 !",
      // RTMP validation
      rtmpFormatError: "L'URL de publication doit commencer par rtmp://, rtmps://, rtsp:// ou rtmpt://",
      // HLS validation
      hlsFormatError: "Format d'URL de publication HLS invalide !",
      // RTSP validation
      rtspMulticastIpError: "Format d'IP multicast RTSP invalide !",
      rtspMulticastPortError: "Le port multicast RTSP doit être un entier entre 1-65535 !",
      // TS validation
      multicastIpError: "Format d'IP multicast invalide !",
      multicastPortError: "Le port multicast doit être un entier entre 1-65535 !",
      tsTransportIdError: "L'ID flux transport TS doit être un entier entre 1-65535 !",
      tsNetworkIdError: "L'ID réseau original TS doit être un entier entre 1-65535 !",
      tsPmtPidError: "Le PID départ PMT TS doit être un entier entre 32-8186 !",
      tsStartPidError: "Le PID départ TS doit être un entier entre 32-3840 !",
      tsPidConflict: "Le PID départ TS et le PID départ PMT TS doivent être différents !",
      tsVersionError: "La version tables TS doit être un entier entre 0-31 !",
      tsServiceIdError: "L'ID service TS doit être un entier entre 1-65535 !",
      tsVideoPidError: "Le PID vidéo TS doit être un entier entre 16-8190 !",
      tsAudioPidError: "Le PID audio TS doit être un entier entre 16-8190 !",
      tsPcrPeriodError: "La période PCR TS doit être un entier entre 0-100 (0=automatique) !",
      tsVideoPidConflict: "Le PID vidéo TS et le PID audio TS doivent être différents !",
      tsAudioPmtConflict: "Le PID audio TS et le PID départ PMT TS doivent être différents !",
      tsVideoPmtConflict: "Le PID vidéo TS et le PID départ PMT TS doivent être différents !",
      // Other validation
      icecastFormatError: "Format d'URL de publication Icecast invalide !",
      shoutcastFormatError: "Format d'URL de publication Shoutcast invalide !",
      ndiNameEmpty: "Le nom de la source NDI ne peut pas être vide !",
      ndiSameStream: "Le flux principal et le flux d'aperçu NDI doivent être différents !",
      ndiLicenseOk: "Licence activée avec succès !",
      ndiLicenseFail: "Code de licence invalide !",
      ndiDiscoveryServerEmpty: "L'adresse du Discovery Server ne peut pas être vide !",
      ndiMulticastAddrError: "Adresse ou masque multicast invalide !"
    }
  }
};
