// English translations
window.LANG_EN = {
  // Common
  common: {
    save: "Save",
    cancel: "Cancel",
    confirm: "Confirm",
    loading: "Loading...",
    success: "Success",
    failed: "Failed",
    delete: "Delete",
    edit: "Edit",
    add: "Add",
    enable: "Enable",
    disable: "Disable",
    enabled: "Enabled",
    disabled: "Disabled",
    yes: "Yes",
    no: "No",
    on: "On",
    off: "Off",
    apply: "Apply",
    reset: "Reset",
    refresh: "Refresh",
    close: "Close",
    back: "Back",
    next: "Next",
    previous: "Previous",
    submit: "Submit",
    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: "Continue",
    copy: "Copy",
    copied: "Copied"
  },

  preview: {
    flvRequired: "Please enable the FLV stream.",
    flvOrHlsRequired: "Please enable at least one live stream: FLV or HLS.",
    hlsUnsupportedEnableFlv: "HLS preview is not supported in this browser. Please enable FLV."
  },

  play: {
    mainFlvRequired: "Main-stream FLV must be enabled",
    browserFlvUnsupported: "This browser does not support FLV playback. Please use a modern browser such as Chrome, Edge, or Firefox"
  },

  // Page titles
  title: {
    encoder: "H.265/H.264 Encoder",
    status: "Status",
    mainStream: "Main Stream",
    subStream1: "Sub Stream 1",
    subStream2: "Sub Stream 2",
    subStream3: "Sub Stream 3",
    videoSettings: "Video Settings",
    audioSettings: "Audio Settings",
    advancedSettings: "Advanced Settings",
    osdMain: "OSD - Main Stream",
    osdSub1: "OSD - Sub Stream 1",
    osdSub2: "OSD - Sub Stream 2",
    osdSub3: "OSD - Sub Stream 3",
    logoUpload: "LOGO Upload",
    network: "Network Settings",
    record: "Record Settings",
    gb28181: "GB28181",
    wifi: "WIFI Settings",
    password: "Password Settings",
    serial: "Serial Transport",
    update: "Upgrade and Backup",
    reboot: "Reboot Device",
    timedReboot: "Schedule Reboot",
    factoryReset: "Factory Reset",
    recordFiles: "Record Files",
    netTest: "Network Test",
    recordSet: "Record Settings",
    alirtcTokenPage: "AliRTC Token"
  },

  // Menu
  menu: {
    status: "Status",
    encoder: "Encoder",
    mainStream: "Main Stream",
    subStream1: "Sub Stream 1",
    subStream2: "Sub Stream 2",
    subStream3: "Sub Stream 3",
    videoSettings: "Video Settings",
    audioSettings: "Audio Settings",
    advancedSettings: "Advanced Settings",
    osd: "OSD",
    logoUpload: "LOGO Upload",
    system: "System",
    scheduleRecord: "Scheduled Recording",
    network: "Network",
    record: "Record",
    gb28181: "GB28181",
    wifi: "WIFI",
    password: "Password",
    serial: "Serial Transport",
    update: "Upgrade and Backup",
    reboot: "Reboot",
    timedReboot: "Schedule Reboot",
    factoryReset: "Factory Reset"
  },

  // Status page
  status: {
    // Device status
    deviceStatus: "Device Status",
    runningTime: "Running Time: ",
    runtimeDayWithTime: "{0}d {1}",
    deviceTime: "Device Time: ",
    syncTime: " (Sync time to device)",
    cpuUsage: "CPU Usage: ",
    cpuTemp: "CPU Temperature: ",
    memoryUsage: "Memory Usage: ",
    encPpsUsage: "Encoding Resource Usage: ",
    memoryWarning: " (If memory usage is too high after 1 minute of boot, please disable some HLS streams or reduce bitrate)",
    cpuWarning: " (If CPU usage stays above 85%, please disable some streams or reduce sub-stream resolution)",
    networkStatus: "Network Status: ",
    inputVideo: "Input Video: ",
    vgaAutoAdjust: " (VGA Auto Adjust)",
    capturedFrames: "Captured Video Frames: ",
    lostFrames: "Lost Video Frames: ",
    audioSampleRate: "Input Audio Sample Rate: ",
    capturedAudioFrames: "Captured Audio Frames: ",
    packetsSent: "Packets Sent: ",
    netTestLink: " (Network Test & System Log)",
    packetsDropped: "Packets Dropped: ",
    canAccessInternet: "Internet Access",
    canAccessInternetIP: "Internet IP Access",
    lanOnly: "LAN Only",
    localNetwork: "Local Network",

    // Recording status
    recordStatus: "Recording Status",
    recordType: "Recording Type: ",
    diskStatus: "Disk Status: ",
    diskNotExist: "Not Found",
    mountStatus: "Mount Status: ",
    notMounted: "Not Mounted",
    mounted: "Mounted",
    totalSpace: "Total Space: ",
    freeSpace: "Free Space: ",
    recordingStatus: "Recording Status: ",
    diskFull: "Disk Full",
    diskSlow: "Disk Too Slow",
    recordFileList: "Recording File List",
    notRecording: "Not Recording",
    recording: "Recording",
    recordingNoVideo: " (Files may not be saved without video input)",
    startRecord: "(Start Recording)",
    stopRecord: "(Stop Recording)",
    usbTfCard: "USB/TF Card",

    // DHCP status
    dhcpStatus: "DHCP Status",
    ip: "IP: ",
    subnetMask: "Subnet Mask: ",
    gateway: "Gateway: ",

    // WIFI status
    wifiStatus: "WIFI Status",
    wifiDisabled: "WIFI: Disabled",
    wifiState: "WIFI State: ",
    wifiSSID: "WIFI SSID: ",
    wifiIP: "WIFI IP: ",
    wifiMAC: "WIFI MAC: ",
    wifiRSSI: "WIFI Signal (RSSI): ",
    wifiFreq: "WIFI Frequency: ",
    wifiConnected: "Connected",
    wifiDisconnected: "Disconnected",
    wifiConnecting: "Connecting (If connection takes too long, please check WIFI settings)",

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

    // Streams
    mainStream: "Main Stream",
    subStream1: "Sub Stream 1",
    subStream2: "Sub Stream 2",
    subStream3: "Sub Stream 3",
    streamDisabled: "Disabled (this sub-stream is turned off automatically when encoding capacity is insufficient)",
    codecType: "Codec: ",
    encodeResolution: "Encode Resolution: ",
    videoBitrate: "Video Bitrate: ",
    realTimeBitrate: "Real-time Bitrate: ",
    realTimeFps: "Real-time FPS: ",
    videoEncoded: "Video Encoded: ",
    reconnect: " (Reconnect)",
	    previewWebRTC: "Video Preview (WebRTC)",
	    previewHTML5: "Video Preview (HTML5)",

    // URL related
    disabled: "Disabled",
    connected: "Connected",
    disconnected: "Disconnected",
    bufferPackets: "Buffer Packets",
    bufferPacketsLabel: "Buffer Packets: ",
    pushSpeed: "Push Speed",
    pushSpeedLabel: "Push Speed: ",
    pushed: "Pushed",
    pushedLabel: "Pushed: ",
    memoryUsed: "Memory Used",
    memoryUsedLabel: "Memory Used: ",
    cacheFiles: "Cache Files",
    cacheFilesLabel: "Cache Files: ",
    multicastUrl: "Multicast URL: ",
    mjpgUrl: "MJPG URL: ",
    jpgUrl: "JPG URL: ",
    tsUrl: "TS URL: ",
    flvUrl: "FLV URL: ",
    hlsTsUrl: "HLS TS URL: ",
    hlsMp4Url: "HLS MP4 URL: ",
    mp4Url: "MP4 URL: ",
    rtspUrl: "RTSP URL: ",
    rtmpUrl: "RTMP URL: ",
    srtListenerUrl: "SRT Listener URL: ",
    webrtcP2pUrl: "WebRTC P2P URL: ",
    rtmpPushUrlAny: "RTMP(S) PUSH URL{0}: ",
    rtmpPushUrlAny0: "RTMP(S) PUSH URL0: ",
    rtmpPushUrlAny1: "RTMP(S) PUSH URL1: ",
    rtmpPushUrlAny2: "RTMP(S) PUSH URL2: ",
    rtmpPushUrl: "RTMP PUSH URL{0}: ",
    rtspPushUrl: "RTSP PUSH URL{0}: ",
    srtCallerUrl: "SRT Caller URL: ",
    hlsPushUrl: "HLS PUSH URL: ",
    icecastPushUrl: "ICECAST PUSH URL: ",
    shoutcastPushUrl: "Shoutcast PUSH URL: ",
    whipLabel: "WHIP: ",
    viewers: "Viewers",
    viewersLabel: "Viewers: ",

    // TRTC status
    trtcRoomId: "TRTC Room ID: ",
    inRoom: "In Room",
    notInRoom: "Not In Room",
    initializingServer: "Initializing server connection",
    serverDisconnected: "Server disconnected",
    connectingServer: "Connecting to server",
    serverConnected: "Connected to server",
    networkUnknown: "Network status unknown",
    networkExcellent: "Excellent network",
    networkGood: "Good network",
    networkNormal: "Normal network",
    networkPoor: "Poor network",
    networkBad: "Bad network",
    networkNotMeet: "Network does not meet TRTC minimum requirements",
    errorCode: "Error Code",
    errorCodeLabel: "Error Code: ",
    trtcError1: "General error, check log files for troubleshooting",
    trtcError100: "Business logic error: illegal call",
    trtcError101: "Business logic error: illegal parameter",
    trtcError102: "Cannot read currently, please retry",
    trtcError103: "Cannot connect to network",
    trtcError200: "Failed to enter room",
    trtcError201: "Invalid user_sig parameter",
    trtcError202: "Invalid room ID format",
    trtcError203: "Invalid sdk_app_id",
    trtcError204: "Service unavailable. Check if package minutes > 0 and Tencent Cloud account is not overdue",
    trtcError205: "User was kicked out of room by server",

    // WHIP status
    whipInitializing: "Initializing",
    whipConnected: "Connected",
    whipDisconnected: "Disconnected",
    whipUnknown: "Unknown Status",
    alirtcLabel: "AliRTC: ",
    alirtcConnecting: "Connecting",
    alirtcConnected: "Connected",
    alirtcDisconnected: "Disconnected",
    alirtcUnknown: "Unknown Status",
    alirtcRoomId: "AliRTC Room ID: ",
    alirtcRoomIdLabel: "Room ID: ",
    alirtcUserIdLabel: "User ID: ",
    alirtcUserNameLabel: "User Name: ",
    alirtcVideoBitrateLabel: "Video: ",
    alirtcAudioBitrateLabel: "Audio: ",
    alirtcRttLabel: "RTT: ",

    // GB28181
    gb28181: "GB28181: ",
    gb28181Online: "Online",
    gb28181Offline: "Offline"
  },

  // Reboot page
  reboot: {
    title: "Reboot Device",
    description: "Click this button to restart the encoder.",
    button: "Reboot",
    success: "Reboot command sent!",
    failed: "Reboot failed!",
    confirm: "Are you sure you want to reboot the device?"
  },

  // Factory reset page
  reset: {
    title: "Factory Reset",
    description: "Click this button to restore all encoder settings to their factory default state.",
    button: "Reset",
    success: "Factory reset successful! The system will restart automatically, please wait.",
    failed: "Factory reset failed!",
    confirm: "Are you sure you want to restore to factory settings?"
  },

  // Scheduled reboot page
  scheduleRecord: {
    title: "Scheduled Recording",
    allDay: "All day",
    timeRange: "Time range",
    segment: "Time Segment",
    to: "to",
    monday: "Mon",
    tuesday: "Tue",
    wednesday: "Wed",
    thursday: "Thu",
    friday: "Fri",
    saturday: "Sat",
    sunday: "Sun",
    nextDay: "(next day)",
    hint: "Each segment can be All day or a Time range, with its own active weekdays; in a time range, an end earlier than the start means overnight (records into the next day, judged by the start day). Sync the device time (NTP) in Network Settings first, or the schedule will not trigger.",
    saveSuccess: "Saved successfully!",
    saveFailed: "Save failed!",
    invalidTime: "Invalid time!",
    needWeekday: "Select at least one day!",
  },
  timedReboot: {
    title: "Schedule Reboot",
    enable: "Schedule Reboot",
    enableLabel: "Schedule Reboot:",
    timeLabel: "Reboot Time:",
    enabled: "Enable",
    disabled: "Disable",
    time: "Reboot Time",
    weekdays: "Reboot Days",
    everyday: "Every day",
    monday: "Monday",
    tuesday: "Tuesday",
    wednesday: "Wednesday",
    thursday: "Thursday",
    friday: "Friday",
    saturday: "Saturday",
    sunday: "Sunday",
    save: "Save",
    saveSuccess: "Settings saved!",
    saveFailed: "Settings failed!",
    invalidTime: "Invalid time value!"
  },

  // Network test page
  netTest: {
    title: "Network Test & System Log",
    command: "Command:",
    run: "Run",
    address: "Address:",
    result: "Result:",
    invalidAddr: "Please enter a valid address!"
  },

  // Record files page
  recordFiles: {
    title: "File List",
    fileName: "File Name",
    time: "Time",
    fileSize: "File Size",
    action: "Action",
    delete: "Delete",
    confirmDelete: "Are you sure you want to delete",
    deleteSuccess: "Delete command sent successfully!",
    deleteFailed: "Failed to delete!",
    noFiles: "No recording files",
    loadError: "Failed to load"
  },

  // Password settings page
  password: {
    title: "Password Settings",
    oldPassword: "Old Password",
    oldPasswordLabel: "Old Password:",
    newPassword: "New Password",
    newPasswordLabel: "New Password:",
    confirmPassword: "Confirm Password",
    confirmPasswordLabel: "Confirm Password:",
    save: "Save",
    success: "Settings saved!",
    failed: "Password setting failed, please check if the old password is correct!",
    mismatch: "New passwords do not match!",
    empty: "Password cannot be empty!"
  },

  // Encoding common (only actually used keys)
  encoding: {
    sameAsInput: "Same as input resolution",
    mp3Required: "Please set audio encoding to MP3!",
    choosePrimaryColor: "Choose primary color",
    toggleTheme: "Toggle theme"
  },

  // OSD settings
  osd: {
    title: "OSD Settings",
    mainStream: "Main Stream OSD",
    subStream1: "Sub Stream 1 OSD",
    subStream2: "Sub Stream 2 OSD",
    subStream3: "Sub Stream 3 OSD",
    alpha: "Transparency",
    alphaLabel: "Transparency:",
    alphaRange: "[0-255]",
    alphaError: "Transparency should be an integer between 0-255!",
    region: "Region",
    regionLabel: "Region:",
    region1: "Region 1",
    region2: "Region 2",
    region3: "Region 3",
    region4: "Region 4",
    type: "Type",
    typeLabel: "Type:",
    typeText: "Text",
    typeImage: "Image",
    typeScroll: "Scrolling Text",
    typeTime: "Time",
    typeAudioStatus: "Audio Status",
    typeVolumeMeter: "Volume Meter",
    typeMosaic: "Mosaic",
    position: "Position",
    positionLabel: "Position:",
    speed: "Speed",
    speedLabel: "Speed:",
    xLabel: "X:",
    yLabel: "Y:",
    textLabel: "Text:",
    fontSize: "Font Size",
    fontSizeLabel: "Font Size:",
    fontSizeRange: "[8-72]",
    backgroundColor: "Background Color",
    backgroundLabel: "Background Color:",
    sizeLabel: "Size (W×H):",
    sizeHint: "[px]",
    blkSizeLabel: "Block Size:",
    sizeError: "{0}: size (W×H) must be valid positive integers",
    bgTransparent: "Transparent",
    bgWhite: "White",
    bgBlack: "Black",
    fontColor: "Font Color",
    fontColorLabel: "Font Color:",
    pickColor: "Pick Color",
    closeColor: "Close",
    logoLabel: "LOGO:",
    success: "Settings saved successfully!",
    failed: "Settings failed!",
    xRangeError: "{0} X value should be an integer between 0-{1}!",
    yRangeError: "{0} Y value should be an integer between 0-{1}!",
    textEmpty: "{0} text cannot be empty!",
    fontSizeError: "{0} font size should be an integer between 8-72!",
    speedRangeError: "{0} speed value should be an integer between 0-30!",
    positionRangeError: "{0} position value should be an integer between 0-{1}!",
    selectLogo: "Please select a LOGO for {0}!",
    webrtcPreview: "Video Preview"
  },

  // LOGO upload
  logo: {
    title: "LOGO Upload",
    logoLabel: "LOGO:",
    upload: "Upload",
    hint: "Please upload an image under 500KB. Supported formats: PNG / JPG / BMP (for transparency use a PNG or 32-bit BMP with an alpha channel).",
    hint2: "Filename must be logo1 / logo2 / logo3 / logo4, with extension .png / .jpg / .jpeg / .bmp.",
    hint3: "e.g. logo1.png, logo1.jpg, logo1.jpeg, logo1.bmp",
    noFileSelected: "Please select a file to upload!",
    invalidFile: "Please upload images as required!",
    uploadSuccess: "Upload successful!",
    uploadFailed: "Upload failed!",
    imageSizeExceeded: "Image file size exceeded limit!",
    imageResolutionExceeded: "Image file resolution exceeded limit!",
    storageInsufficient: "Upgrade file too large, insufficient storage space!",
    listTitle: "Uploaded LOGO",
    refresh: "Refresh",
    preview: "Preview",
    logoFile: "LOGO File",
    fileType: "Type",
    fileSize: "Size",
    operation: "Operation",
    loading: "Loading...",
    emptyList: "No uploaded LOGO",
    loadListFailed: "Failed to load LOGO list",
    confirmDelete: "Delete {0}?\nThe same-name PNG/BMP files will also be deleted. If this LOGO is in use, the related image OSD will be cleared.",
    deleteSuccess: "Deleted successfully!",
    deleteFailed: "Delete failed!"
  },

  // WIFI settings
  wifi: {
    title: "WIFI Settings",
    mode: "Mode",
    ap: "Access Point",
    sta: "Client Mode",
    ssid: "SSID",
    password: "Password",
    security: "Security",
    channel: "Channel",
    scan: "Scan",
    connect: "Connect",
    disconnect: "Disconnect",
    status: "Status",
    connected: "Connected",
    disconnected: "Disconnected",
    signalStrength: "Signal Strength",
    basicSettings: "Basic Settings",
    wifiModule: "Wifi Module:",
    wifiMode: "Wifi Mode:",
    staMode: "STA Mode",
    apMode: "AP Mode",
    mainConfig: "WIFI Main Config",
    backupConfig1: "WIFI Backup Config 1",
    backupConfig2: "WIFI Backup Config 2",
    apModeSettings: "AP Mode",
    wifiList: "Wifi List:",
    wifiEssid: "Wifi Essid:",
    wifiPassword: "Wifi Password:",
    wifiDhcp: "Wifi DHCP:",
    wifiIp: "Wifi IP:",
    wifiNetmask: "Wifi Netmask:",
    wifiGateway: "Wifi Gateway:",
    backupEnable1: "Backup Config 1:",
    backupEnable2: "Backup Config 2:",
    wifiBand: "Wifi Band:",
    wifiChannel: "Wifi Channel:",
    refresh: "Refresh",
    success: "Settings saved successfully!",
    failed: "Settings save failed!",
    mainConfigEmpty: "WIFI Main Config: {0} cannot be empty!",
    mainConfigInvalid: "WIFI Main Config: {0} format is invalid!",
    backupConfigEmpty: "WIFI {0}: {1} cannot be empty!",
    backupConfigInvalid: "WIFI {0}: {1} format is invalid!",
    ipAddr: "IP Address",
    netmask: "Netmask",
    gateway: "Gateway",
    essidEmpty: "WiFi name cannot be empty!",
    passwordTooShort: "WiFi password must be at least 8 characters!"
  },


  // Upgrade and backup
  updateBackup: {
    title: "System Upgrade",
    uploadTitle: "Upload Firmware and Config",
    backupTitle: "Backup Firmware and Config",
    systemVersion: "System Version",
    systemVersionLabel: "System Version: ",
    hardware: "Hardware",
    hardwareLabel: "Hardware: ",
    selectFile: "Select File",
    selectFileLabel: "Select File:",
    uploadHint: "Upload file name: up.rar or box.ini",
    uploadWarning: "Do not upload simultaneously. Do not power off during upload.",
    upload: "Upload",
    backupFirmware: "Backup Firmware",
    backupConfig: "Backup Config",
    noFileSelected: "Please select a file to upload!",
    uploadSuccess: "Upload successful, please restart the system!",
    uploadFailed: "Upload failed!",
    kernelUpdating: "The kernel update takes a few minutes; do not power off. The device will reboot automatically when done — no manual restart needed.",
    kernelUpdatingBin: "The kernel update takes a few minutes; do not power off. The device will reboot automatically when done — no manual restart needed!",
    imageSizeExceeded: "Image file size exceeded limit!",
    imageResolutionExceeded: "Image file resolution exceeded limit!",
    storageInsufficient: "Upgrade file too large, insufficient storage space!"
  },

  // Serial transport settings
  serial: {
    title: "Serial Transport",
    frpTitle: "FRP Client Settings",
    serialTitle: "Serial Port Passthrough",
    enable: "Enable",
    disable: "Disable",
    enableLabel: "Enable:",
    serverAddr: "Server Address",
    serverAddrLabel: "Server Address:",
    serverPort: "Server Port",
    serverPortLabel: "Server Port:",
    serverToken: "Server Token",
    serverTokenLabel: "Server Token:",
    channel: "Channel",
    channel1: "Channel 1",
    channel2: "Channel 2",
    channel3: "Channel 3",
    channel4: "Channel 4",
    protocolLabel: "Protocol:",
    localPort: "Local Port",
    localPortLabel: "Local Port:",
    remotePort: "Remote Port",
    remotePortLabel: "Remote Port:",
    serialMode: "Serial Mode",
    serialModeLabel: "Mode:",
    server: "Server",
    client: "Client",
    baudRate: "Baud Rate",
    baudRateLabel: "Baud Rate:",
    listenPort: "Listen Port",
    listenPortLabel: "Listen Port:",
    save: "Save",
    success: "Settings saved, please restart the device!",
    failed: "Settings failed!",
    emptyError: "Settings cannot be empty!",
    remoteAddrError: "Remote server address is invalid (enter a valid IP or hostname)!",
    portRangeError: "TCP listen port must be an integer between 1-65535!",
    frpAddrEmpty: "FRP server address cannot be empty!",
    frpPortError: "FRP server port must be an integer between 1-65535!"
  },

  // Advanced Settings
  advanced: {
    title: "Advanced Settings",
    // Section titles
    videoInput: "Video Input",
    avTransmission: "A/V Transmission",
    recordSettings: "Recording Settings",
    hlsSettings: "HLS Settings",
    networkTransmission: "Stream Transmission",
    serviceSettings: "Service Settings",
    logSettings: "Log Settings",
    encoderParams: "Encoder Parameters",
    imageEnhancement: "Image Enhancement",
    autoRestart: "Auto Restart",
    // Video Input
    edidSelect: "EDID Select:",
    colorGamut: "Color Gamut:",
    colorRange: "Color Range:",
    interlaceMode: "Interlace Mode:",
    noSignal: "No Signal:",
    vgaAutoAdjust: "VGA Auto Adjust on Startup:",
    interlaceWeaving: "Weaving (merge fields)",
    interlaceBottom: "Bottom field only",
    interlaceTop: "Top field only",
    interlaceBobbing: "Bobbing (field to frame)",
    noSignalHide: "Hide",
    noSignalImage: "Show image",
    noSignalColor: "Show solid color",
    noVideoRestartStream: "Restart Stream on No Signal:",
    // A/V Transmission
    videoOnly: "Video Only:",
    audioOnly: "Audio Only:",
    avSync: "A/V Sync:",
    audioDelay: "Audio Delay (ms):",
    syncAuto: "Auto",
    syncResample: "Resample",
    audioDelayHint: "Negative values make audio earlier, positive values later. Use only for A/V sync tuning.",
    // Recording Settings
    recordType: "Record Type:",
    cycleRecord: "Cycle Recording:",
    diskOverwriteOldest: "Auto-delete oldest when full:",
    noRecordNoSig: "No Recording Without Signal:",
    recordSplitTime: "Record Split Time (sec):",
    // HLS Settings
    hlsSplitTime: "HLS Segment Time (sec):",
    hlsBufferNum: "HLS Segment Count:",
    hlsIndexUri: "HLS Global Index URI:",
    // Network Transmission
    tsMuxer: "TS Muxer:",
    netDropThreshold: "Packet Drop Threshold:",
    tsOnce: "TS Packets Per Send:",
    rtspPackType: "RTSP Encapsulation:",
    multicastType: "Multicast Type:",
    enableSap: "Enable SAP:",
    mtuSize: "MTU Size:",
    udpTtl: "UDP TTL:",
    udpSockBuf: "UDP SOCKET_BUF_SIZE:",
    rtpH264PacketMode: "RTP H264 Packetization:",
    packetizeByAccessUnit: "packetize_by_access_unit",
    packetizeByNalu: "packetize_by_nalu",
    vlcCompat: "VLC Compatible",
    ffmpegCompat: "FFMPEG Compatible",
    esStream: "ES Stream",
    tsStream: "TS Stream",
    // Service Settings
    tsRtspAuth: "TS/RTSP Auth Required:",
    httpNoAuth: "Web Access No Auth:",
    netCheck: "Network Status Check:",
    telnetService: "Telnet Service:",
    sshService: "SSH Service:",
    sambaService: "Samba Service:",
    onvifService: "ONVIF Service:",
    onvifLocation: "ONVIF Location:",
    onvifMode: "ONVIF Mode:",
    onvifModeLegacy: "Legacy XML (shared HTTP/ONVIF port)",
    onvifModeProfileST: "Profile S/T (dedicated ONVIF port)",
    onvifModeProfileSCompat: "Profile S Hikvision-compatible (dedicated ONVIF port)",
    rtspDefaultStream: "RTSP Default Stream:",
    vmixCompat: "VMix Compatible:",
    telnetLan: "LAN Only",
    // Log Settings
    localLog: "Local Log Service:",
    trtcLogLevel: "TRTC SDK Log Level:",
    alirtcLogLevel: "AliRTC SDK Log Level:",
    sdkLogDebug: "Debug",
    sdkLogInfo: "Info",
    sdkLogWarning: "Warning",
    sdkLogError: "Error",
    sdkLogFatal: "Fatal",
    sdkLogNone: "None",
    lokiAddr: "Loki Server Address:",
    lokiPort: "Loki Server Port:",
    // Encoder Parameters
    sliceSplit: "SLICE Split:",
    sliceBytes: "SLICE Bytes:",
    minQp: "MIN_QP:",
    maxQp: "MAX_QP:",
    debreath: "Debreathing:",
    sar: "SAR:",
    cbrOnlyHint: "Effective only when rate control mode is set to CBR",
    // Image Enhancement
    contrastEnhance: "Contrast Enhancement:",
    sharpnessEnhance: "Sharpness Enhancement:",
    lumaSfStrength: "Luma Spatial Denoise:",
    lumaTfStrength: "Luma Temporal Denoise:",
    chromaSfStrength: "Chroma Spatial Denoise:",
    chromaTfStrength: "Chroma Temporal Denoise:",
    // Auto Restart
    kickAllOnChange: "Disconnect Users on Input Change:",
    noVideoReboot: "Auto Reboot on No Video:",
    noAudioReboot: "Auto Reboot on No Audio:",
    // Button
    save: "Save",
    // Messages
    success: "Settings saved, please restart the device!",
    failed: "Settings failed!",
    emptyError: "Settings cannot be empty!",
    netDropError: "Packet drop threshold must be an integer between 50-50000!",
    tsOnceError: "TS packets per send must be an integer between 1-128!",
    sliceError: "SLICE bytes must be an integer between 128-65535!",
    minQpError: "MIN_QP must be an integer between 1-35!",
    maxQpError: "MAX_QP must be greater than MIN_QP and at most 50!",
    udpTtlError: "UDP TTL must be an integer between 1-254!",
    contrastError: "Contrast enhancement must be an integer between 0-63!",
    sharpnessError: "Sharpness enhancement must be an integer between 0-16!",
    lumaSfError: "Luma spatial denoise must be an integer between 0-255!",
    lumaTfError: "Luma temporal denoise must be an integer between 0-63!",
    chromaSfError: "Chroma spatial denoise must be an integer between 0-255!",
    chromaTfError: "Chroma temporal denoise must be an integer between 0-32!",
    hlsSplitError: "HLS segment time must be an integer between 3-20!",
    hlsBufferError: "HLS segment count must be an integer between 3-20!",
    hlsUriError: "HLS global index URI format is invalid!",
    udpSockBufError: "UDP SOCKET_BUF_SIZE must be an integer between 0-20971520!",
    mtuError: "MTU size must be an integer between 500-1500!",
    audioCacheError: "Audio delay must be an integer between -2000 and 2000!",
    recordSplitError: "Record split time must be an integer between 60-7200!",
    lokiPortError: "Loki server port must be between 1-65535"
  },

  // Audio Encoding Settings
  audioEnc: {
    blkInput: "Input",
    blkEncode: "Encoding",
    blkVolume: "Volume",
    blkVolumeNote: "Manual fixed gain",
    blkAgc: "Auto Gain",
    blkAgcNote: "Automatically levels fluctuating volume to the target",
    blkDenoise: "Noise Reduction",
    blkDenoiseNote: "Suppresses background noise; high CPU, usually left off",
    mute: "Mute",
    gain0: "0 dB (unchanged)",
    title: "Audio Settings",
    // Tabs
    tabAudio: "Audio Settings",
    tabOnvif: "ONVIF Audio",
    // Tips
    tipAudio: "Do not set the digital volume gain too high, as it may cause distortion or introduce noise.<br>In most cases, set the gain to 0.<br>Adjust overall volume using the front-end controls.",
    tipVolVsAgc: "<b>Volume Gain vs Auto Gain (AGC)</b><br>Volume gain is a manually set, fixed gain: positive values amplify, negative values attenuate. It does not change with the input signal, making it suitable for sources with a stable, predictable level.<br>Auto Gain (AGC) automatically adjusts the gain according to the real-time level of the input signal, keeping the output near the target level and smoothing out audio that swings between loud and soft.<br>With AGC enabled, keep the volume gain at 0 dB so that AGC controls the level on its own and you avoid stacking two controls.",
    tipAgcLevel: "<b>AGC Target Level (dBFS)</b><br>Sets the final level reference. The closer the target is to 0 dBFS, the louder the output, but the less headroom is left for transient peaks and the more easily it clips.<br>• -18 dBFS (recommended): a balance between loudness and headroom, suitable for most situations.<br>• -12 dBFS: the loudest option, good for live streaming and other high-volume scenarios; but with only 12 dB of headroom, sudden loud sounds clip easily.<br>• -20 to -24 dBFS: suited to voice, live performances and other inputs with large peak swings.<br>• -30 to -42 dBFS: suited to high-gain microphone inputs or noisy environments.",
    tipOnvif: "To connect to NVR, set RTSP G711 encoding to 'Enable and resample to 8K'",
    // Audio Settings
    audioInput: "Audio Input:",
    sampleRate: "Sample Rate:",
    codec: "Codec:",
    channel: "Channels:",
    bitrate: "Bitrate:",
    digitalGain: "Digital Volume Gain:",
    analogGain: "Analog Volume Gain:",
    denoise: "Denoise:",
    denoiseStrength: "Denoise Strength (dB):",
    agc: "Auto Gain Control:",
    agcLevel: "AGC Target Level (dBFS):",
    pteG711: "PTE Stream G711:",
    // Audio Input Options
    inputDigital: "Digital",
    inputAnalog: "Analog",
    inputMixed: "Mixed",
    // Sample Rate Options
    sampleSameAsInput: "Same as input",
    // ONVIF Audio
    rtspG711: "RTSP G711 Encoding:",
    rtspG711Resample: "Enable and resample to 8K",
    g711Codec: "G711 Codec:",
    // Buttons and Messages
    save: "Save",
    success: "Settings saved!",
    failed: "Settings failed!",
    emptyError: "Settings cannot be empty!",
    bitrateError: "Bitrate must be an integer between {0}-{1}!",
    gainError: "Digital volume gain must be an integer between -50 and 50!",
    denoiseError: "Denoise strength must be an integer between 1-100!",
    agcLevelError: "AGC target level must be between -42 and -12 dBFS!",
    analogVolEmpty: "Analog volume gain cannot be empty!",
    analogVolError: "Analog volume gain must be an integer between {0} and {1}!"
  },

  // Recording Settings Page
  recordSet: {
    title: "Recording Settings",
    // Card Titles
    statusTitle: "Recording Status",
    settingsTitle: "Recording Settings",
    // Status
    recordType: "Record Type:",
    diskStatus: "Disk Status:",
    currentAddr: "Current Address:",
    mountDevice: "Mount Device:",
    mountStatus: "Mount Status:",
    totalSpace: "Total Space:",
    freeSpace: "Free Space:",
    recordStatus: "Record Status:",
    recordFiles: "Record Files:",
    fileList: "File List",
    // Disk Status
    diskNotExist: "Not Present",
    diskFull: "Disk Full",
    diskSlow: "Disk Too Slow",
    mounted: "Mounted",
    unmounted: "Unmounted",
    notRecording: "Not Recording",
    recording: "Recording",
    noVideoWarning: " (Files may not be saved without video input)",
    // Action Links
    startRecord: "(Start Recording)",
    stopRecord: "(Stop Recording)",
    mountDisk: "(Mount Disk)",
    unmountDisk: "(Unmount Disk)",
    deleteAll: "(Delete All Recordings)",
    // Settings
    storageType: "Storage Type:",
    partition: "Partition:",
    partitionInfo: "Partition Info:",
    diskInfo: "Disk Info:",
    formatDisk: "(Reformat Disk)",
    exampleAddr: "Example Address:",
    storageAddr: "Storage Address:",
    username: "Username:",
    password: "Password:",
    // Storage Type Options
    storageDisabled: "Disabled",
    storageUsb: "USB/TF Card",
    storageNfs: "NFS",
    storageSamba: "SAMBA/CIFS",
    // Format Dialog
    formatTitle: "Disk Information",
    formatDevice: "Device:",
    formatType: "Type:",
    formatModel: "Model:",
    formatRemovable: "Removable:",
    formatPartTable: "Partition Table:",
    formatCapacity: "Capacity:",
    formatPartitions: "Partition Information",
    formatPartition: "Partition",
    formatAvailable: "(available)",
    formatTotal: "(total)",
    formatConfirm: "Continue with disk format?",
    formatDanger: "Warning: Formatting will repartition and all data will be lost. Continue?",
    formatContinue: "Continue",
    formatCancel: "Cancel",
    formatConfirmBtn: "Confirm",
    formatting: "Formatting...",
    // Buttons and Messages
    save: "Save",
    yes: "Yes",
    no: "No",
    success: "Settings saved!",
    failed: "Settings failed!",
    formatSuccess: "Format successful!",
    formatFailed: "Format failed!",
    deleteSuccess: "Delete command sent!",
    deleteFailed: "Delete failed!",
    confirmDeleteAll: "Delete all recording files?",
    recordingWarning: "Currently recording. Stop recording before unmounting.",
    diskMountedWarning: "Disk is mounted. Unmount before formatting.",
    diskMountedSettingWarning: "Disk is mounted. Unmount before changing settings.",
    storageLockedHint: "Locked while mounted; unmount the disk to change.",
    partitionNotExist: "Partition does not exist",
    partitionRemoved: " (Removed)",
    unpartitioned: " (unpartitioned)",
    unpartitionedHint: "Disk has no partition, please repartition & format it first",
    // Address Validation
    addrEmpty: "Storage address cannot be empty!",
    addrNfsFormat: "Invalid address format, must contain ':' separator",
    addrIpError: "Invalid IP address format",
    addrPathSlash: "Path must start with '/'",
    addrPathInvalid: "Path contains invalid characters",
    addrSambaStart: "Address must start with '\\\\'",
    addrSambaFormat: "Invalid address, must contain IP and path separated by '\\'",
    addrPathEmpty: "Path cannot be empty",
    addrPathChars: "Path contains invalid characters, only letters, numbers, underscores and hyphens allowed",
    // Disk size info "{available} / {total}"
    diskSizeInfo: "{0} (available) / {1} (total)"
  },
  // GB28181 Settings
  gb28181: {
    title: "GB28181 Settings",
    basicSettings: "Basic Settings",
    heartbeatSettings: "Heartbeat Settings",
    sipServerSettings: "SIP Server Settings",
    authSettings: "Authentication Settings",
    enable: "Enable:",
    disabled: "Disabled",
    enabled: "Enabled",
    localSipPort: "Local SIP Port:",
    videoChannelId: "Video Channel ID:",
    streamSelect: "Stream Select:",
    mainStream: "Main Stream",
    subStream1: "Sub Stream 1",
    subStream2: "Sub Stream 2",
    subStream3: "Sub Stream 3",
    regExpiry: "Registration Expiry:",
    heartbeatCycle: "Heartbeat Cycle:",
    maxHeartbeatTimeout: "Max Heartbeat Timeout:",
    sipServerId: "SIP Server ID:",
    sipServerDomain: "SIP Server Domain:",
    sipServerAddr: "SIP Server Address:",
    sipServerPort: "SIP Server Port:",
    sipUserId: "SIP User ID:",
    sipPassword: "SIP Password:",
    emptyError: "Settings cannot be empty!",
    localPortError: "Local SIP port must be an integer between 1-65535!",
    serverPortError: "SIP server port must be an integer between 1-65535!",
    regExpiryError: "Registration expiry must be an integer between 100-100000!",
    heartbeatError: "Heartbeat cycle must be an integer between 5-3600!",
    maxTimeoutError: "Max heartbeat timeout must be an integer between 3-255!",
    success: "Settings saved successfully!",
    failed: "Settings failed!"
  },
  // Video Source Settings
  videoSource: {
    title: "Video Source Settings",
    videoInput: "Video Input Settings",
    brightAdjust: "Input Brightness Adjustment",
    videoOutput: "Video Output Settings",
    inputFormat: "Video Input Format:",
    yuv422: "YUV422",
    yuv420: "YUV420 (Rotation Supported)",
    rotation: "Rotation Angle:",
    flipMirror: "Flip/Mirror:",
    flipDisable: "Disabled",
    mirror: "Mirror",
    flip: "Flip",
    flipAndMirror: "Mirror and Flip",
    cropEnable: "Video Crop:",
    cropLeft: "Crop Start Point (Left):",
    cropTop: "Crop Start Point (Top):",
    cropWidth: "Crop Width:",
    cropHeight: "Crop Height:",
    colorMode: "Input Color Mode:",
    unknown: "Unknown",
    brightEnable: "Brightness Adjustment:",
    gain: "Gain:",
    gainHint: "[10-1000], default 100",
    offset: "Offset:",
    offsetHint: "[0-100], default 0",
    note: "Note:",
    brightNote1: "1. Brightness = (Original Brightness * Gain / 100) + Offset",
    brightNote2: "2. Brightness adjustment only works in RGB input color mode",
    outputRes: "Video Output Resolution:",
    auto: "Auto",
    cscEnable: "CSC Adjustment:",
    luminance: "Luminance:",
    contrast: "Contrast:",
    hue: "Hue:",
    saturation: "Saturation:",
    cscHint: "[0-100], default 50",
    rotateHint: "Rotation is only supported when video input format is YUV420.",
    emptyError: "Settings cannot be empty!",
    gainError: "Gain must be an integer between 10-1000!",
    offsetError: "Offset must be an integer between 0-100!",
    leftError: "Left value must be an integer between 0-{0}!",
    topError: "Top value must be an integer between 0-{0}!",
    widthError: "Width value must be an integer between 400-{0}!",
    heightError: "Height value must be an integer between 400-{0}!",
    luminanceError: "Luminance must be an integer between 0-100!",
    contrastError: "Contrast must be an integer between 0-100!",
    hueError: "Hue must be an integer between 0-100!",
    saturationError: "Saturation must be an integer between 0-100!",
    success: "Settings saved successfully!",
    failed: "Settings failed!"
  },
  // Network Settings
  network: {
    title: "Network Settings",
    ipv4Title: "IPv4 Settings",
    ipv6Status: "IPv6 Status",
    ipv6Title: "IPv6 Settings",
    ipv6TypeGlobal: "Global IP",
    ipv6TypeLinkLocal: "Link-Local IP",
    ipv6TypeUniqueLocal: "Local IP",
    ipv6TypeMulticast: "Multicast IP",
    ipv6TypeGeneric: "IP",
    ipv6StatusGateway: "Gateway",
    dnsTitle: "DNS Settings",
    ntpTitle: "NTP Settings",
    portTitle: "Port Settings",
    httpsTitle: "HTTPS Settings",
    hostnameTitle: "HOSTNAME Settings",
    dhcp: "DHCP:",
    dhcpHint: "After enabling DHCP, the device can be found by ONVIF compatible search tools.",
    ipAddr: "IP Address:",
    netmask: "Subnet Mask:",
    gateway: "Wired Gateway:",
    macAddr: "MAC Address:",
    defaultGateway: "Default Gateway:",
    lanFirst: "Wired First",
    wifiFirst: "WIFI First",
    g4First: "4G/5G First",
    ipv6Mode: "Mode:",
    ipv6Disable: "Disabled",
    ipv6Auto: "Auto Configuration",
    ipv6Manual: "Manual Configuration",
    ipv6Addr: "IPv6 Address:",
    ipv6Prefix: "IPv6 Prefix Length:",
    ipv6Gateway: "IPv6 Default Gateway:",
    dns1: "DNS1:",
    dns2: "DNS2:",
    ntpSync: "NTP Sync:",
    ntpServer: "Server:",
    timezone: "Timezone:",
    httpPort1: "HTTP Port 1:",
    httpPort2: "HTTP Port 2:",
    rtspPort1: "RTSP Port 1:",
    rtspPort2: "RTSP Port 2:",
    onvifPort: "ONVIF Port:",
    sadpProtocol: "SADP Port:",
    httpsService: "HTTPS Service:",
    httpsPort1: "HTTPS Port 1:",
    httpsPort2: "HTTPS Port 2:",
    httpsPrivatePass: "HTTPS Private Key Password:",
    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: "(Leave empty if no password)",
    uploadCert: "Upload Certificate:",
    uploadCertHint: "(File name must be private.key or public.crt. Do not upload simultaneously or power off during upload)",
    uploadBtn: "Upload Certificate",
    deleteCert: "Delete Certificate",
    hostname: "HOSTNAME:",
    mdnsService: "mDNS Service:",
    mdnsAddr: "mDNS Access Address:",
    portRange: "[1-65535]",
    prefixRange: "[0-128]",
    emptyError: "Settings cannot be empty!",
    ipError: "Invalid IP address format!",
    netmaskError: "Invalid subnet mask format!",
    gatewayError: "Invalid gateway format!",
    dns1Error: "Invalid primary DNS format!",
    dns2Error: "Invalid secondary DNS format!",
    macError: "Invalid MAC address format!",
    ipv6Error: "Invalid IPv6 address format!",
    ipv6PrefixError: "Invalid IPv6 prefix length (1-128)!",
    ipv6GatewayError: "Invalid IPv6 gateway format!",
    httpPort1Error: "HTTP port 1 must be an integer between 1-65535!",
    httpPort2Error: "HTTP port 2 must be an integer between 1-65535!",
    rtspPort1Error: "RTSP port 1 must be an integer between 1-65535!",
    rtspPort2Error: "RTSP port 2 must be an integer between 1-65535!",
    httpsPort1Error: "HTTPS port 1 must be an integer between 1-65535!",
    httpsPort2Error: "HTTPS port 2 must be an integer between 1-65535!",
    onvifPortError: "ONVIF port must be an integer between 1-65535!",
    sadpPortError: "SADP port must be an integer between 1-65535!",
    httpBothDisableError: "HTTP port 1 and port 2 cannot both be disabled!",
    httpsBothDisableError: "When HTTPS is enabled, port 1 and port 2 cannot both be disabled!",
    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: "NTP server cannot be empty!",
    ntpFormatError: "Invalid NTP server address!",
    hostnameEmptyError: "HOSTNAME cannot be empty!",
    hostnameFormatError: "Invalid HOSTNAME!\n\n1. HOSTNAME must not exceed 63 characters!\n2. Only letters (a-z), numbers (0-9), hyphens (-) and underscores (_) allowed!\n3. '-' and '_' cannot appear consecutively, alone, or at the beginning/end!",
    deleteCertConfirm: "Are you sure you want to delete the uploaded HTTPS certificate?",
    selectFile: "Please select a file to upload!",
    uploadSuccess: "Upload successful!",
    uploadFailed: "Upload failed!",
    fileSizeError: "Image file size exceeds limit!",
    fileResError: "Image resolution exceeds limit!",
    spaceError: "Upgrade file too large, insufficient storage space!",
    deleteSuccess: "Deleted successfully!",
    deleteFailed: "Delete failed!",
    successReboot: "Settings saved, please reboot the device!",
    failed: "Settings failed!"
  },

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

    // Encoding settings
    encode: {
      codecType: "Codec Type:",
      frameRate: "Frame Rate:",
      sameAsInput: "Same as input frame rate",
      auto: "Auto",
      customFrameRate: "Custom frame rate",
      customFrameRateLabel: "Custom Frame Rate:",
      gopInterval: "GOP Interval (frames):",
      bitrate: "Bitrate (kbit):",
      qualityRange: "Quality Range:",
      qualityStrict: "Strict (High)",
      qualityTight: "Tight (Near-High~High)",
      qualityNormal: "Normal (Medium~High)",
      qualityLoose: "Loose (Near-Low~High)",
      qualityWide: "Wide (Low~High)",
      mjpegQuality: "MJPEG Quality:",
      outputResolution: "Output Resolution:",
      h264Profile: "H.264 Profile:",
      bitrateControl: "Bitrate Control:",
      // Tips
      tipCodec: "H.265 provides better video quality than H.264. Use H.265 if your decoder supports it.",
      tipVbr: "In VBR mode, bitrate is regulated by \"Quality Range\"; Quality Range clamps QP values;<br>Selecting \"Near-High~High\" or \"High\" results in very high actual bitrate, making the set bitrate meaningless;<br>Only when Quality Range is \"Near-Low~High\" does the bitrate have reference value;",
      tipCbr: "\"Strong CBR\" is used for CATV systems to ensure stable TS bitrate. With \"Strong CBR\" at 1080P, bitrate should not be lower than 5000kbit/s, 8000kbit/s recommended.",
      tipGop: "Assuming input video frame rate is n, common values are 60, 50, 30, 25;<br>GOP interval is typically set to n * 2, common values are 120, 100, 60, 50;<br>When frame rate is set to Auto, if n > 30, encoding frame rate is n / 2, otherwise it equals n"
    },

    // TS/Multicast settings
    ts: {
      tsUri: "TS Stream URL:",
      multicastIp: "Multicast IP:",
      multicastPort: "Multicast Port:",
      sapName: "SAP Name:",
      tsVideoPid: "TS Video PID:",
      tsAudioPid: "TS Audio PID:",
      tsTransportStreamId: "TS Transport Stream ID:",
      tsOriginalNetworkId: "TS Original Network ID:",
      tsPmtStartPid: "TS PMT Start PID:",
      tsStartPid: "TS Start PID:",
      tsTablesVersion: "TS Tables Version:",
      tsServiceId: "TS Service ID:",
      tsServiceName: "TS Service Name:",
      tsProviderName: "TS Provider Name:",
      tsPcrPeriod: "TS PCR Period (ms):",
      conformSystemB: "Conform to System B (DVB):",
      tsNullPacket: "TS Null Packets:",
      noInsert: "No insert",
      insert12: "Insert (1.2x)",
      insert13: "Insert (1.3x)",
      insert15: "Insert (1.5x)",
      insert20: "Insert (2x)",
      insert25: "Insert (2.5x)",
      tsTdt: "TS TDT:",
      // Tips
      tipMulticast: "Multicast address can also accept broadcast or unicast addresses, the system will auto-detect.",
      tipVlc: "If VLC cannot play multicast, check if your computer has multiple network adapters, try switching to another adapter.",
      tipSap: "SAP name can be viewed on supported devices, such as VLC's playlist -> Local Network.",
      tipAdvanced: "TS advanced settings generally don't need adjustment.",
      tipIptv: "When connecting to IPTV systems, TS null packets should be adjusted to 1.3x, the device will auto-insert null packets to ensure stable bitrate;<br>This setting only applies to \"Strong CBR\" mode."
    },

    // RTSP settings
    rtsp: {
      rtspUri: "RTSP Stream URL:",
      enableMulticast: "Enable (Multicast)",
      enableTcpOnly: "Enable (TCP Only)",
      multicastIp: "RTSP Multicast IP:",
      multicastPort: "RTSP Multicast Port:",
      // Tips
      tipEnable: "If Enable is selected, the actual transport (UDP or TCP) is determined by the client. For example, in VLC you can check \"RTP over RTSP(TCP)\" to use TCP.",
      tipTcpOnly: "Selecting Enable (TCP Only) forces the device to use TCP.",
      tipUdp: "UDP may occasionally drop packets due to network issues. If all clients support it, TCP is recommended.",
      tipMulticast: "Selecting Enable (Multicast) will use 4 consecutive ports starting from the \"RTSP Multicast Port\"."
    },

    // RTMP settings
    rtmp: {
      rtmpUri: "RTMP Stream URL:",
      publishUri0: "RTMP(S)/RTSP Publish URL 0:",
      publishUri1: "RTMP(S)/RTSP Publish URL 1:",
      publishUri2: "RTMP(S)/RTSP Publish URL 2:",
      mode: "RTMP Stream Mode:",
      modeStandard: "Standard (Enhanced RTMP)",
      modeLegacy: "Legacy (CodecID 12)",
      // Tips
      tipPublish: "Publish URLs 0-2 are for pushing streams to other LAN or public RTMP/RTSP servers, supporting H.265/H.264.",
      tipBuiltin: "This device has a built-in RTMP server supporting H.264/H.265 pull playback;<br>If RTMP Stream URL is set to \"/live/0\", PotPlayer can play via http://device-IP/live/0.",
      tipMode: "RTMP Stream Mode only applies to H.265 and also affects the FLV stream;"
    },

    // SRT settings
    srt: {
      listenerUri: "SRT Listener URL:",
      callerUri: "SRT Caller URL:",
      // Tips
      tipListener: "SRT Listener mode listens on a local port for players to pull the stream.<br>For example, set srt://0.0.0.0:9000;<br>VLC can then play \"srt://device-IP:9000\".<br>Adding streamid example:<br>srt://0.0.0.0:9000?streamid=channel100<br>Adding password example (minimum 10 characters):<br>srt://0.0.0.0:9000?passphrase=0123456789<br>Adding both streamid and password:<br>srt://0.0.0.0:9000?streamid=channel100&passphrase=0123456789",
      tipCaller: "SRT Caller mode pushes the stream to another server, e.g.:<br>srt://live.example.com:9000?streamid=channel100&latency=120&maxbw=8000000",
      tipParams: "Supported SRT parameters (see SRT protocol for details):<br>streamid - stream identifier for multiplexing<br>passphrase - encryption password, SRT requires 10-79 characters<br>pbkeylen - key length: 16 (AES-128), 24 (AES-192), 32 (AES-256)<br>latency - latency in ms (20-8000ms)<br>maxbw - max bandwidth in bytes/sec<br>rcvbuf - receive buffer size<br>sndbuf - send buffer size<br>ipttl - IP TTL value<br>conntimeo - connection timeout in ms"
    },

    // WebRTC settings
    webrtc: {
      previewTitle: "Web preview",
      previewNote: "(low-latency preview on Status page)",
      whipTitle: "WHIP publish",
      whipNote: "(push to a server, for many viewers)",
      p2pTitle: "P2P remote",
      p2pNote: "(NAT traversal, for a few remote viewers)",
      optional: "optional",
      preview: "Web preview",
      whipServer: "Push URL",
      whipToken: "Bearer token",
      p2pServer: "Signaling server URL",
      p2pUuid: "Device UUID",
      p2pToken: "P2P Auth Token:",
      p2pAuthToken: "Auth token",
      regenerate: "Regenerate",
      // Tips
      tipPreview: "WebRTC preview in mainstream browsers supports H.264 video and Opus/G.711 audio encoding.<br>Setting audio to Opus provides better results. If not set to Opus, defaults to G.711 8K.",
      tipWhip: "WHIP streaming connects to standard WHIP servers. Copy the address from your server.<br>Bearer token can be empty.",
      tipP2p: "After enabling P2P server, the viewing URL is shown on the status page.<br>P2P auth token can be empty.",
      tipP2pNote: "P2P may not connect in complex intranet environments."
    },

    // TRTC settings
    trtc: {
      roomId: "TRTC Room ID:",
      userId: "TRTC Username:",
      roomKey: "TRTC Room Key:",
      userSig: "TRTC UserSig:",
      sdkAppId: "TRTC SDKAppID:",
      roomIdType: "TRTC Room ID Type:",
      roomIdNumber: "Number",
      roomIdString: "String",
      // Short enum labels for template use
      number: "Number",
      string: "String",
      // Tips
      tipTrtc: "Push streams to Tencent TRTC server. Copy the address from the server.<br>Tencent TRTC currently only supports H.264."
    },

    alirtc: {
      roomId: "AliRTC Room ID:",
      userId: "AliRTC User ID:",
      userName: "AliRTC User Name:",
      region: "AliRTC Region:",
      token: "AliRTC Token:",
      tipAliRtc: "Push streams to Alibaba Cloud RTC, supporting H.265/H.264.<br>You can enter the token provided by the service directly, or click AliRTC Token to generate a token with AppID/AppKey on the separate page.<br>If the token is empty, the device will try to generate one automatically at startup using the AppID/AppKey saved on the separate page.<br>If the room ID, user ID, or user name changes, you may need to regenerate the token."
    },


    alirtcTokenPage: {
      title: "AliRTC Token",
      roomId: "AliRTC Room ID:",
      userId: "AliRTC User ID:",
      userName: "AliRTC User Name:",
      appId: "AliRTC AppID:",
      appKey: "AliRTC AppKey:",
      token: "AliRTC Token:",
      generate: "Generate And Save Token",
      appFieldsRequired: "AliRTC AppID and AppKey are required.",
      identityRequired: "AliRTC room ID, user ID, and user name are required in the current stream output settings.",
      generateSuccess: "AliRTC token generated and saved.",
      generateFailed: "AliRTC token generation failed.",
      unavailable: "AliRTC is unavailable on this device."
    },

    // HLS settings
    hls: {
      hlsTsUri: "HLS TS Stream URL:",
      hlsMp4Uri: "HLS MP4 Stream URL:",
      hlsPushUri: "HLS PUSH URL:",
      hlsPushUrl: "HLS PUSH URL:",
      // Tips
      tipHls: "When HLS TS/MP4 is enabled, the device buffers data in memory based on segment time and count in advanced settings.<br>Setting both segment time and count to 3 reduces memory usage.",
      tipPush: "HLS publish URL is for pushing to servers like YouTube."
    },

    // MP4/FLV/Other settings
    other: {
      mp4Uri: "MP4 Stream URL:",
      flvUri: "FLV Stream URL:",
      icecastUri: "ICECAST PUSH URL:",
      icecastPushUrl: "ICECAST PUSH URL:",
      shoutcastUri: "Shoutcast PUSH URL:",
      shoutcastPushUrl: "Shoutcast PUSH URL:",
      // Tips
      tipMp4: "When MP4 stream is enabled, it can be played directly in the browser.<br>FLV stream supports H.265/H.264 on this device, but VLC and other players currently only support H.264.<br>ICECAST/Shoutcast only supports MP3, for pushing to audio servers.",
      tipShoutcast: "Shoutcast supports v1 and v2;<br>Examples:<br>http://password@shoutcast_server:8000<br>http://password@shoutcast_server:8000?sid=100<br>http://password@shoutcast_server:8000?icy-name=Stream&icy-genre=Pop<br>Format:<br>http://password@server-IP:listen-port[?params...]; username can be omitted (default \"source\").<br>Use the server's \"listen port\", the device will auto-connect to source port (listen port + 1).<br>Supported parameters:<br>sid: Shoutcast v2 stream ID (default 1)<br>icy-name: stream name (optional)<br>icy-genre: genre (optional)<br>icy-url: website URL (optional)<br>icy-pub: public 0/1 (optional)"
    },

    // Common
    common: {
      save: "Save",
      disabled: "Disabled",
      enabled: "Enabled"
    },

    // Error and success messages
    messages: {
      success: "Settings saved!",
      failed: "Settings failed!",
      emptyError: "Settings cannot be empty!",
      trtcH264Only: "When TRTC is enabled, only H.264 encoding is supported. Changed automatically.",
      alirtcIdentityRequired: "When AliRTC is enabled, room ID, user ID, and user name are required.",
      mp3Required: "Please set audio encoding to MP3!",
      // Encoding validation
      frameRateError: "Frame rate must be an integer between 5-60!",
      gopError: "GOP interval must be an integer between 5-300!",
      mjpegQualityError: "MJPEG quality must be an integer between 10-99!",
      hlsBitrateWarning: "Bitrate not in 32~8000 range, HLS TS/MP4/PUSH streams disabled.",
      trtcCodecWarning: "Codec is not H.264, TRTC disabled.",
      hlsBitrateError: "Bitrate not in 32~8000 range, cannot enable HLS TS/MP4/PUSH streams",
      // SRT validation
      srtListenerPortError: "SRT Listener port must be an integer between 1-65535!",
      srtListenerFormatError: "Invalid SRT Listener URL format!",
      srtCallerFormatError: "Invalid SRT Caller URL format!",
      srtPasswordLengthError: "SRT password length must be between 10-32!",
      srtLatencyError: "SRT Latency must be an integer between 1-10000!",
      srtBandwidthError: "SRT Bandwidth must be an integer between 0-102400!",
      // RTMP validation
      rtmpFormatError: "RTMP(S)/RTSP publish URL must start with rtmp://, rtmps://, or rtsp://",
      // HLS validation
      hlsFormatError: "Invalid HLS publish URL format!",
      // RTSP validation
      rtspMulticastIpError: "Invalid RTSP multicast IP format!",
      rtspMulticastPortError: "RTSP multicast port must be an integer between 1-65535!",
      // TS validation
      multicastIpError: "Invalid multicast IP format!",
      multicastPortError: "Multicast port must be an integer between 1-65535!",
      tsTransportIdError: "TS Transport Stream ID must be an integer between 1-65535!",
      tsNetworkIdError: "TS Original Network ID must be an integer between 1-65535!",
      tsPmtPidError: "TS PMT Start PID must be an integer between 32-8186!",
      tsStartPidError: "TS Start PID must be an integer between 32-3840!",
      tsPidConflict: "TS Start PID and TS PMT Start PID must be different!",
      tsVersionError: "TS Tables Version must be an integer between 0-31!",
      tsServiceIdError: "TS Service ID must be an integer between 1-65535!",
      tsVideoPidError: "TS Video PID must be an integer between 16-8190!",
      tsAudioPidError: "TS Audio PID must be an integer between 16-8190!",
      tsPcrPeriodError: "TS PCR period must be an integer between 0-100 (0=automatic)!",
      tsVideoPidConflict: "TS Video PID and TS Audio PID must be different!",
      tsAudioPmtConflict: "TS Audio PID and TS PMT Start PID must be different!",
      tsVideoPmtConflict: "TS Video PID and TS PMT Start PID must be different!",
      // Other validation
      icecastFormatError: "Invalid Icecast publish URL format!",
      shoutcastFormatError: "Invalid Shoutcast publish URL format!"
    }
  }
};
