'ROMAN Custom Center', 'page.title' => 'ROMAN Custom Center', 'tab.alert' => 'Alert', 'tab.opt' => 'Optimization', 'tab.maint' => 'Maintenance', 'tab.l2' => 'L2 Topology', 'sec.robot' => 'WeCom group robot', 'sec.strategy' => 'Alert strategy (pick one, then Apply)', 'sec.threshold' => 'Manual threshold (overrides the strategy)', 'sec.tuning' => 'Server tuning generator', 'sec.template' => 'Template import', 'sec.map' => 'Map marker', 'sec.triggers' => 'Per-trigger alerting switch', 'sec.class_sev' => 'Bulk severity by class', 'lbl.mediatype' => 'Alert media type', 'lbl.alerting_on' => 'Alerting enabled', 'lbl.severity' => 'Severities that will notify', 'lbl.key' => 'Robot key (global macro {$WECOM_KEY})', 'lbl.strategy_hint' => 'Every strategy pins the "must alert" classes to the highest severity (Disaster) so they always fire, and sets a threshold for the rest. Apply is safe and repeatable.', 'lbl.threshold_hint' => 'The strategy sets this automatically. Change it here only for a one-off adjustment.', 'lbl.tuning_hint' => 'This only GENERATES the settings and command — nothing is changed. Copy them onto the Zabbix host and recreate the server container yourself.', 'btn.save' => 'Save', 'btn.test' => 'Send test', 'btn.import' => 'Import template', 'btn.preview' => 'Preview', 'btn.apply' => 'Apply', 'btn.generate' => 'Generate', 'btn.search' => 'Search', 'sev.1' => 'Not classified', 'sev.2' => 'Information', 'sev.3' => 'Warning', 'sev.4' => 'Average', 'sev.5' => 'High', 'sev.6' => 'Disaster', 'cls.device_down' => 'Device down / unreachable', 'cls.hw_fault' => 'Hardware fault (fan/power/temperature)', 'cls.restarted' => 'Device restarted', 'cls.core_link' => 'Core/uplink link down', 'cls.interface_down' => 'Access interface down', 'cls.perf' => 'Performance (bandwidth/error/CPU)', 'cls.other' => 'Other (unchanged)', 'cls.col.class' => 'Class', 'cls.col.target' => 'Severity', 'cls.col.count' => 'Triggers', 'cls.col.changes' => 'Will change', 'cls.total' => 'Total', 'preset.current' => '(current)', 'preset.col.name' => 'Strategy', 'preset.col.desc' => 'Description', 'preset.col.action' => 'Actions', 'preset.steady' => 'Steady operations', 'preset.steady.desc' => 'Must-alert always fires; rest only High+. Balanced for daily production.', 'preset.core' => 'Core essentials only', 'preset.core.desc' => 'Only must-alert classes fire (Disaster). Everything else muted — max noise reduction.', 'preset.observe' => 'Full observation', 'preset.observe.desc' => 'Notify from Warning up. For onboarding / troubleshooting periods.', 'preset.night' => 'Night quiet', 'preset.night.desc' => 'Disaster only. For night shifts / on-call quiet hours.', 'preset.balanced' => 'Core strict / access loose', 'preset.balanced.desc' => 'Must-alert + Average up. Slightly broader than steady.', 'preview.title' => 'Preview — dry run for "{1}" (nothing written)', 'preview.hint' => 'These are the hosted triggers that would change. Apply to actually write them.', 'tpl.choose' => 'Bundled template', 'tpl.none' => 'No bundled template found', 'map.choose_host' => '-- select host --', 'map.host' => 'Marker host', 'map.lat' => 'Latitude', 'map.lon' => 'Longitude', 'map.hint' => 'The map uses one representative point (the Zabbix server). Note: the Geomap widget needs the browser to reach the internet for base-map tiles.', 'tuning.choose' => 'Hardware profile', 'tuning.small' => 'Small (< 200 hosts)', 'tuning.medium' => 'Medium (~ 500 hosts)', 'tuning.large' => 'Large (1000+ hosts)', 'tuning.env' => 'Settings (paste into .env / compose environment):', 'tuning.cmd' => 'Then apply:', 'lbl.trig_search' => 'Search triggers by description (e.g. CPU, disk)', 'lbl.trig_list' => 'Triggers (checked = alerting enabled)', 'lbl.trig_hint' => 'There are {1} triggers. Type a keyword above to search (max 200 shown).', 'lbl.trig_edit_hint' => 'Adjust severity or toggle alerting per row, then Save. Changes apply immediately and the list refreshes.', 'lbl.class_sev_hint' => 'Pick a class of triggers and a target severity. Apply sets every trigger in that class — template, prototypes and already-discovered triggers — then refreshes the list.', 'lbl.class_pick' => 'Trigger class', 'lbl.set_severity' => 'Set severity to', 'msg.saved' => 'Alert settings saved.', 'msg.robot_saved' => 'Robot key saved.', 'msg.tested' => 'Test message sent successfully (errcode 0).', 'msg.test_failed' => 'Test failed (HTTP {1}): {2}', 'msg.imported' => 'Template imported. Templates: {1}', 'msg.map_saved' => 'Map coordinates saved.', 'msg.no_mediatype' => 'No webhook media type found.', 'msg.no_url' => 'Robot key is empty (set {$WECOM_KEY}).', 'msg.no_template' => 'Please choose a template.', 'msg.no_host' => 'Please choose a host.', 'msg.no_template_host' => 'Huawei walk template not found on this server.', 'msg.no_server_host' => 'Host "Zabbix server" not found.', 'msg.bad_scheme' => 'Unknown strategy.', 'msg.unknown_op' => 'Unknown operation.', 'msg.no_triggers' => 'No trigger selected.', 'msg.triggers_saved' => 'Trigger alerting updated: {1} trigger(s).', 'msg.no_trig_search' => 'No triggers matched your search.', 'msg.bad_class_sev' => 'Choose a class and a severity (0-5).', 'msg.class_sev_saved' => 'Class severity updated: template triggers {1}, discovered triggers {2}. List refreshed.', 'msg.strategy_applied' => 'Strategy "{1}" applied — template triggers: {2}, prototypes: {3}, discovered triggers: {4}.', 'hero.sub' => 'WeCom group alerts, one-click alert strategy, server tuning, template migration and per-trigger control — all in one place.', 'lbl.template_hint' => 'Bundled templates ship with the module. Importing an existing template updates it in place; importing a new one creates it. Use the switch card below to move devices from an old template to the new one.', 'sec.switch' => 'Template switch (migrate devices)', 'lbl.switch_hint' => 'Pick the OLD template and the NEW template. Preview lists the affected devices; confirm replaces the template link on every one of them. This is the "import, then switch?" step.', 'switch.pick' => '-- select template --', 'switch.src' => 'From template (old)', 'switch.dst' => 'To template (new)', 'switch.none' => 'No device currently uses "{1}". Nothing to switch.', 'switch.result' => '{1} device(s) on "{2}" will be moved to "{3}".', 'btn.confirm' => 'Confirm switch', 'msg.need_both' => 'Please choose both source and target template.', 'msg.same_tpl' => 'Source and target template must differ.', 'msg.switch_applied' => 'Switched {1} device(s) to the new template.', 'sec.init' => 'Environment initialisation', 'lbl.init_hint' => 'On a brand-new Zabbix click this once — it creates the WeCom webhook media type, the robot user with its media, the trigger action and the {$WECOM_KEY} macro. Existing objects are reused (safe to re-run as a self-check).', 'lbl.init_key' => 'Group-robot key (Webhook key)', 'btn.init' => 'Initialise / self-check', 'init.title' => 'First-time setup', 'init.sub' => 'This Zabbix has no WeCom media type yet. Paste your group-robot key and initialise — the media type, robot user, trigger action and macro will all be created automatically, then alerts start flowing to the group.', 'msg.init_done' => 'Initialisation complete: {1}.', 'msg.init_mediatype_new' => 'media type created', 'msg.init_mediatype_ok' => 'media type reused', 'msg.init_user_new' => 'robot user created', 'msg.init_user_ok' => 'robot user reused', 'msg.init_action_new' => 'trigger action created', 'msg.init_action_ok' => 'trigger action exists', 'msg.init_key_set' => 'key saved', 'menu.l2' => 'L2 Topology', 'sec.l2_collect' => 'L2 collection', 'sec.l2_display' => 'L2 display', 'sec.l2_colors' => 'Link speed colours', 'sec.l2_latency' => 'Latency thresholds', 'sec.l2_group' => 'Grouping rules', 'sec.l2_networks' => 'Physical networks', 'sec.l2_cores' => 'Core switches', 'lbl.l2_cores_hint' => 'Define the root switch (left-most column). One row per core switch: network | match | name/IP pattern. Multiple cores in one network are supported; order does not matter.', 'lbl.core_net' => 'Network', 'lbl.core_any' => 'All networks', 'lbl.core_pattern' => 'Name or IP pattern', 'btn.add_core' => 'Add core switch', 'lbl.l2_templates' => 'Collect hosts using these template(s)', 'lbl.l2_templates_hint' => 'Only hosts linked to the selected templates are collected. Recommended/default: Huawei VRP by SNMP (walk).', 'lbl.l2_networks' => 'Physical networks (one per line: KEY | label | name/IP keywords | colour)', 'lbl.l2_networks_hint' => 'A switch belongs to the first network whose keyword appears in its name or IP. Example: SURVE | SURVE monitoring | SURVE,10.169. | #2E75B6.', 'lbl.l2_refresh' => 'Display auto-refresh (seconds)', 'lbl.l2_full' => 'Full collection interval (minutes)', 'lbl.l2_alarm' => 'Alarm-only refresh (minutes)', 'lbl.l2_root' => 'Outermost frame label', 'lbl.l2_other' => 'Fallback group label', 'lbl.color_100' => '100M', 'lbl.color_1000' => '1G', 'lbl.color_10000' => '10G', 'lbl.color_20000' => '20G+', 'lbl.color_unknown' => 'Unknown', 'lbl.color_down' => 'Down', 'lbl.lat_warn' => 'Orange above (ms)', 'lbl.lat_bad' => 'Red above (ms)', 'lbl.rule_match' => 'Match', 'lbl.rule_pattern' => 'Pattern', 'lbl.rule_label' => 'Frame label', 'lbl.rule_big' => 'Big', 'lbl.rule_hint' => 'First matching rule wins; unmatched devices go to the fallback group. For regex rules the label may use $1..$9 back-references.', 'btn.add_rule' => 'Add rule', 'msg.l2_saved' => 'L2 topology settings saved.', 'l2.title' => 'L2 Physical Topology', 'l2.search_ph' => 'Search IP / MAC / name…', 'l2.show_term' => 'Show terminals', 'l2.only_off' => 'Only offline switches', 'l2.auto_refresh' => 'Auto refresh', 'l2.min' => 'min', 'l2.refresh_now' => 'Refresh now', 'l2.fit' => 'Fit to window', 'l2.alarms' => 'Alarms', 'l2.offline' => 'Offline switches', 'l2.time_live' => 'Live', 'l2.time_btn' => 'Go', 'l2.time_label' => 'Snapshot time', 'l2.no_data' => 'No snapshot yet — the collector has not run.', 'l2.offline_empty' => 'No offline switches.', 'l2.alarm_empty' => 'No active alarms.', 'l2.updated' => 'Updated', 'l2.pause' => 'Pause auto-refresh', 'l2.resume' => 'Resume auto-refresh', 'l2.legend_speed' => 'Link speed', 'l2.legend_tier' => 'Tier', 'l2.legend_lat' => 'Latency', 'l2.core' => 'Core', 'l2.main' => 'Main switch', 'l2.dist' => 'Distribution', 'l2.access' => 'Access', 'l2.lat_norm' => 'Normal', 'l2.term_on' => 'Online', 'l2.term_off' => 'Offline', 'l2.term_title' => 'Terminal', 'l2.term_mac' => 'MAC address', 'l2.term_rate' => 'Link rate', 'l2.term_switch' => 'Switch', 'l2.term_port' => 'Port', 'l2.term_ip' => 'IP address', 'l2.zoom_in' => 'Zoom in', 'l2.zoom_out' => 'Zoom out', 'l2.snapshot' => 'Snapshot', 'l2.showing' => 'Showing', 'l2.live_tag' => 'LIVE', 'menu.title' => 'ROMAN Custom Center', 'l2.unit_sw' => 'switches', 'l2.tile_hint' => 'Click to open this workshop', 'l2.not_in_topo' => 'not in topology', 'l2.click_hint' => 'Click a switch to highlight its links', 'l2.net_surve' => 'SURVE surveillance', 'l2.net_office' => 'OFFICE office', 'l2.net_other' => 'Other network', 'l2.floor_na' => 'Other', 'l2.terminals' => 'Terminals', 'l2.offline_short' => 'offline SW', 'l2.last_online' => 'last online', 'l2.history' => 'History', 'l2.history_live' => 'Live / latest', 'l2.history_live_hint' => 'Newest snapshot, auto refresh', 'l2.history_empty' => 'No history snapshots yet.', ];