(() => { "use strict"; const STORAGE_KEY = "arr:locale:v1"; const COOKIE_KEY = "arr_locale"; const DEFAULT_LOCALE = "zh-CN"; const LOCALES = { "zh-CN": { label: "中文", intl: "zh-CN-u-ca-gregory-nu-latn" }, en: { label: "English", intl: "en-GB-u-ca-gregory-nu-latn" }, th: { label: "ไทย", intl: "th-TH-u-ca-gregory-nu-latn" }, }; // The first value is the current product copy. Keeping the source copy here // gives the legacy static markup a safe Chinese fallback while all new // dynamic strings use the semantic key. const CATALOG = { "common.language": ["语言", "Language", "ภาษา"], "common.skip_main": ["跳到主要内容", "Skip to main content", "ข้ามไปยังเนื้อหาหลัก"], "common.skip_login": ["跳到登录表单", "Skip to login form", "ข้ามไปยังแบบฟอร์มเข้าสู่ระบบ"], "common.cancel": ["取消", "Cancel", "ยกเลิก"], "common.close": ["关闭", "Close", "ปิด"], "common.confirm": ["确认", "Confirm", "ยืนยัน"], "common.save": ["保存", "Save", "บันทึก"], "common.delete": ["删除", "Delete", "ลบ"], "common.select": ["选择", "Select", "เลือก"], "common.view": ["查看", "View", "ดู"], "common.download": ["下载", "Download", "ดาวน์โหลด"], "common.refresh": ["刷新", "Refresh", "รีเฟรช"], "common.previous": ["上一页", "Previous", "ก่อนหน้า"], "common.next": ["下一页", "Next", "ถัดไป"], "common.status": ["状态", "Status", "สถานะ"], "common.company": ["公司", "Company", "บริษัท"], "common.room_type": ["房型", "Room type", "ประเภทห้อง"], "common.quantity": ["数量", "Quantity", "จำนวน"], "common.operation": ["操作", "Actions", "การดำเนินการ"], "common.total": ["合计", "Total", "รวม"], "common.details": ["详情", "Details", "รายละเอียด"], "common.file": ["文件", "File", "ไฟล์"], "common.submitted_at": ["提交时间", "Submitted", "เวลาส่ง"], "common.submitted_at_bangkok": ["提交时间(曼谷)", "Submitted (Bangkok)", "เวลาส่ง (กรุงเทพฯ)"], "common.generated_at": ["生成时间", "Generated", "เวลาสร้าง"], "common.none": ["暂无", "None", "ไม่มีข้อมูล"], "common.unknown": ["未知", "Unknown", "ไม่ทราบ"], "common.not_selected": ["未选择", "Not selected", "ยังไม่ได้เลือก"], "common.pending": ["待生成", "Pending", "รอสร้าง"], "common.no_result": ["无结果", "No result", "ไม่มีผลลัพธ์"], "common.not_recorded": ["未记录", "Not recorded", "ไม่ได้บันทึก"], "common.not_available": ["未完成", "Not completed", "ยังไม่เสร็จ"], "common.year_month_unselected": ["未选择", "Not selected", "ยังไม่ได้เลือก"], "common.loading": ["正在读取…", "Loading…", "กำลังโหลด…"], "common.reading": ["正在读取", "Reading", "กำลังอ่าน"], "common.retrying": ["重试中", "Retrying", "กำลังลองอีกครั้ง"], "common.choose_file": ["选择文件", "Choose file", "เลือกไฟล์"], "common.download_short": ["下载", "Download", "ดาวน์โหลด"], "common.select_month": ["月份", "Month", "เดือน"], "history.business_month": ["业务月份", "Business month", "เดือนธุรกิจ"], "history.view_month": ["查看月份", "View month", "เดือนที่ดู"], "history.generation_month": ["生成月份", "Generation month", "เดือนที่สร้าง"], "history.generation_month_title": ["选择 C/O 所属的生成月份", "Choose the generation month for C/O", "เลือกเดือนที่สร้างสำหรับ C/O"], "history.previous_month": ["上一个月", "Previous month", "เดือนก่อนหน้า"], "history.next_month": ["下一个月", "Next month", "เดือนถัดไป"], "history.current_month": ["本月", "This month", "เดือนนี้"], "common.locale_zh": ["中文", "Chinese", "ภาษาจีน"], "nav.primary": ["主要模块", "Main modules", "โมดูลหลัก"], "nav.daily": ["日报处理", "Daily processing", "ประมวลผลรายวัน"], "nav.monthly": ["月报", "Monthly report", "รายงานประจำเดือน"], "nav.bi": ["渠道BI", "Channel BI", "Channel BI"], "nav.company_detail": ["公司渠道明细", "Company channel detail", "รายละเอียดช่องทางบริษัท"], "brand.home": ["ARR Report 首页", "ARR Report home", "หน้าหลัก ARR Report"], "status.connecting_service": ["正在连接数据服务", "Connecting to data service", "กำลังเชื่อมต่อบริการข้อมูล"], "status.service_ready": ["服务正常", "Service ready", "บริการพร้อมใช้งาน"], "status.service_disconnected": ["数据服务未连接", "Data service unavailable", "บริการข้อมูลไม่พร้อมใช้งาน"], "status.connecting": ["正在连接", "Connecting", "กำลังเชื่อมต่อ"], "status.received": ["已接收", "Received", "รับแล้ว"], "status.uploaded": ["已上传", "Uploaded", "อัปโหลดแล้ว"], "status.waiting_processing": ["等待处理", "Waiting for processing", "รอประมวลผล"], "status.processing": ["处理中", "Processing", "กำลังประมวลผล"], "status.waiting_validation": ["等待验收", "Waiting for validation", "รอตรวจสอบผล"], "status.validating": ["正在验收", "Validating", "กำลังตรวจสอบผล"], "status.completed": ["已完成", "Completed", "เสร็จแล้ว"], "status.validation_failed": ["验收失败", "Validation failed", "ตรวจสอบผลไม่ผ่าน"], "status.failed": ["处理失败", "Processing failed", "ประมวลผลไม่สำเร็จ"], "status.cancelled": ["已取消", "Cancelled", "ยกเลิกแล้ว"], "status.generating": ["生成中", "Generating", "กำลังสร้าง"], "status.validated": ["已验收", "Validated", "ตรวจสอบแล้ว"], "status.current_version": ["当前版本", "Current version", "เวอร์ชันปัจจุบัน"], "status.history_version": ["历史版本", "Historical version", "เวอร์ชันประวัติ"], "status.generation_failed": ["生成失败", "Generation failed", "สร้างไม่สำเร็จ"], "auth.logout": ["退出登录", "Log out", "ออกจากระบบ"], "auth.logout_short": ["退出", "Log out", "ออก"], "auth.logout_failed": ["退出登录失败,请重试", "Could not log out. Please try again.", "ออกจากระบบไม่สำเร็จ โปรดลองอีกครั้ง"], "auth.session_expired": ["登录状态已失效", "Your session has expired.", "เซสชันหมดอายุแล้ว"], "auth.session_init_failed": ["页面会话初始化失败", "Could not initialize the page session.", "เริ่มเซสชันของหน้าไม่สำเร็จ"], "auth.username": ["username", "username", "ชื่อผู้ใช้"], "auth.password": ["password", "password", "รหัสผ่าน"], "auth.show": ["显示", "Show", "แสดง"], "auth.hide": ["隐藏", "Hide", "ซ่อน"], "auth.show_password": ["显示密码", "Show password", "แสดงรหัสผ่าน"], "auth.hide_password": ["隐藏密码", "Hide password", "ซ่อนรหัสผ่าน"], "auth.submit": ["登录 ARR Report", "Log in to ARR Report", "เข้าสู่ระบบ ARR Report"], "auth.validating": ["正在验证…", "Verifying…", "กำลังตรวจสอบ…"], "auth.unavailable": ["登录暂时不可用,请稍后重试", "Login is temporarily unavailable. Please try again later.", "การเข้าสู่ระบบไม่พร้อมใช้งานชั่วคราว โปรดลองอีกครั้งภายหลัง"], "auth.required_username": ["请输入用户名", "Enter your username.", "กรุณากรอกชื่อผู้ใช้"], "auth.required_password": ["请输入密码", "Enter your password.", "กรุณากรอกรหัสผ่าน"], "time.business": ["页面日期时间统一按泰国曼谷(UTC+7)显示。", "All page dates and times use Bangkok time (UTC+7).", "วันที่และเวลาทั้งหมดใช้เวลาที่กรุงเทพฯ (UTC+7)"], "time.business_short": ["业务时间统一按泰国曼谷(UTC+7)显示", "Business time uses Bangkok time (UTC+7)", "เวลาธุรกิจใช้เวลาที่กรุงเทพฯ (UTC+7)"], "upload.xml.title": ["上传 ARR.XML", "Upload ARR.XML", "อัปโหลด ARR.XML"], "upload.xml.drop": ["拖放 XML 文件到这里", "Drop an XML file here", "ลากไฟล์ XML มาที่นี่"], "upload.xml.choose": ["或点击选择文件,单个文件最大 25 MB", "or click to choose a file; maximum 25 MB", "หรือคลิกเพื่อเลือกไฟล์ ขนาดไม่เกิน 25 MB"], "upload.file_not_selected": ["尚未选择文件", "No file selected", "ยังไม่ได้เลือกไฟล์"], "upload.start": ["开始处理", "Start processing", "เริ่มประมวลผล"], "upload.progress": ["ARR.XML 处理进度", "ARR.XML processing progress", "ความคืบหน้าการประมวลผล ARR.XML"], "upload.waiting": ["等待开始", "Waiting to start", "รอเริ่ม"], "upload.uploading": ["正在上传 ARR.XML", "Uploading ARR.XML", "กำลังอัปโหลด ARR.XML"], "upload.processing": ["正在处理ARR.XML文件", "Processing ARR.XML", "กำลังประมวลผล ARR.XML"], "upload.processing_detail": ["正在安全上传、运行固定处理器、独立验收并提交数据库。", "Uploading securely, running the fixed processor, validating independently and committing to the database.", "กำลังอัปโหลดอย่างปลอดภัย เรียกใช้ตัวประมวลผล ตรวจสอบผล และบันทึกลงฐานข้อมูล"], "upload.after_processing": ["处理完成后将立即读取服务端全流程日志…", "The server trace will be read as soon as processing finishes…", "ระบบจะอ่านบันทึกกระบวนการจากเซิร์ฟเวอร์เมื่อเสร็จสิ้น…"], "upload.creating_task": ["正在创建任务", "Creating task", "กำลังสร้างงาน"], "upload.processing_done": ["处理完成", "Processing complete", "ประมวลผลเสร็จแล้ว"], "upload.processing_failed": ["处理失败", "Processing failed", "ประมวลผลไม่สำเร็จ"], "upload.success": ["ARR.XML 已处理并完成入库", "ARR.XML was processed and committed.", "ประมวลผลและบันทึก ARR.XML แล้ว"], "upload.failure_log": ["ARR.XML 处理失败,请查看任务日志", "ARR.XML processing failed. Check the task log.", "การประมวลผล ARR.XML ไม่สำเร็จ โปรดดูบันทึกงาน"], "upload.service_unready": ["文件接收服务尚未完成生产接线。", "The file intake service is not ready for production.", "บริการรับไฟล์ยังไม่พร้อมใช้งานจริง"], "upload.stage_processor": ["正在运行固定处理器", "Running the fixed processor", "กำลังเรียกใช้ตัวประมวลผล"], "upload.stage_validate": ["正在独立验收结果", "Independently validating the result", "กำลังตรวจสอบผลอย่างอิสระ"], "upload.stage_commit": ["正在提交数据库", "Committing to the database", "กำลังบันทึกลงฐานข้อมูล"], "metric.arrival_date": ["最近成功处理日期", "Latest successful processing date", "วันที่ประมวลผลสำเร็จล่าสุด"], "metric.duration": ["处理耗时", "Processing time", "เวลาประมวลผล"], "metric.duration_from_submit": ["从提交至完成", "From submission to completion", "ตั้งแต่ส่งจนเสร็จ"], "metric.rooms": ["保留记录的售出房数", "Sold rooms in retained records", "จำนวนห้องที่ขายในรายการที่เก็บไว้"], "daily.history": ["Daily Report", "Daily Report", "Daily Report"], "daily.refresh": ["刷新", "Refresh", "รีเฟรช"], "daily.download": ["日报", "Daily report", "รายงานรายวัน"], "daily.empty": ["本月暂无 Daily Report 记录", "No Daily Report records this month", "เดือนนี้ยังไม่มีรายการ Daily Report"], "daily.loading": ["正在读取本月记录…", "Loading this month’s records…", "กำลังโหลดรายการของเดือนนี้…"], "daily.unavailable": ["日报记录暂时无法读取", "Daily records are temporarily unavailable", "ไม่สามารถอ่านรายการรายวันได้ชั่วคราว"], "daily.no_selected_log": ["请上传文件,或从下方选择一个历史任务。", "Upload a file or select a historical task below.", "อัปโหลดไฟล์หรือเลือกงานเก่าด้านล่าง"], "daily.overview": ["日报处理概览", "Daily processing overview", "ภาพรวมการประมวลผลรายวัน"], "daily.pagination_label": ["Daily Report 分页", "Daily Report pagination", "การแบ่งหน้า Daily Report"], "daily.file": ["文件", "File", "ไฟล์"], "daily.submitted_at": ["提交时间", "Submitted", "เวลาส่ง"], "daily.output": ["日报", "Daily report", "รายงานรายวัน"], "monthly.processing": ["月报处理", "Monthly processing", "ประมวลผลรายงานประจำเดือน"], "monthly.auto_update": ["自动更新 · 4 秒", "Auto-refresh · 4 sec", "อัปเดตอัตโนมัติ · 4 วินาที"], "monthly.loading": ["正在读取月报记录…", "Loading monthly report records…", "กำลังโหลดรายการรายงานประจำเดือน…"], "monthly.empty": ["该月份暂无月报处理记录", "No monthly processing records for this month", "เดือนนี้ยังไม่มีรายการประมวลผลรายเดือน"], "monthly.updated_to": ["更新至", "Updated through", "อัปเดตถึง"], "monthly.rows": ["数据行", "Data rows", "แถวข้อมูล"], "monthly.pagination_label": ["月报记录分页", "Monthly report pagination", "การแบ่งหน้ารายงานประจำเดือน"], "monthly.unavailable": ["月报记录暂时无法读取", "Monthly records are temporarily unavailable", "ไม่สามารถอ่านรายการรายเดือนได้ชั่วคราว"], "monthly.new": ["新月报已自动加入列表", "A new monthly report was added automatically", "เพิ่มรายงานประจำเดือนใหม่ในรายการแล้ว"], "monthly.retry": ["自动更新重试中", "Auto-refresh retrying", "กำลังลองอัปเดตอัตโนมัติอีกครั้ง"], "bi.title": ["渠道BI", "Channel BI", "Channel BI"], "bi.month": ["查看月份", "Month", "เดือน"], "bi.metrics": ["本月核心指标", "This month’s key metrics", "ตัวชี้วัดหลักของเดือนนี้"], "bi.rooms": ["售出房数", "Rooms sold", "จำนวนห้องที่ขาย"], "bi.revenue": ["销售金额", "Sales amount", "ยอดขาย"], "bi.nights": ["间夜", "Room nights", "คืนห้องพัก"], "bi.companies": ["公司数", "Companies", "จำนวนบริษัท"], "bi.rooms_total": ["NO. OF ROOM 合计", "Total NO. OF ROOM", "รวม NO. OF ROOM"], "bi.revenue_total": ["销售金额合计", "Total sales amount", "ยอดขายรวม"], "bi.nights_formula": ["房数 × 入住晚数", "Rooms × nights", "ห้อง × จำนวนคืน"], "bi.channel_count": ["月报子表数量", "Monthly report worksheet count", "จำนวนชีตรายงานประจำเดือน"], "bi.sales_by_company": ["各公司本月销售情况", "Monthly sales by company", "ยอดขายรายเดือนของแต่ละบริษัท"], "bi.sales_ranking": ["公司销售金额排名", "Company sales ranking", "อันดับยอดขายบริษัท"], "bi.sales_share": ["公司销售金额占比", "Company sales share", "สัดส่วนยอดขายบริษัท"], "bi.matrix": ["渠道 × 房型售出房数", "Rooms sold by channel × room type", "จำนวนห้องที่ขายตามช่องทาง × ประเภทห้อง"], "bi.channel": ["渠道", "Channel", "ช่องทาง"], "bi.empty": ["暂无渠道与房型数据", "No channel or room-type data", "ไม่มีข้อมูลช่องทางหรือประเภทห้อง"], "bi.empty_sales": ["暂无公司销售数据", "No company sales data", "ไม่มีข้อมูลยอดขายบริษัท"], "bi.loading": ["正在读取看板数据…", "Loading dashboard data…", "กำลังโหลดข้อมูลแดชบอร์ด…"], "company.title": ["公司渠道明细", "Company channel detail", "รายละเอียดช่องทางบริษัท"], "company.fixed": ["固定生成:LianTai、QBD、DY-AI-Easy-KB、FengRun、HanaTour", "Fixed scope: LianTai, QBD, DY-AI-Easy-KB, FengRun, HanaTour", "ขอบเขตคงที่: LianTai, QBD, DY-AI-Easy-KB, FengRun, HanaTour"], "company.refresh_title": ["重新读取服务状态、Excel 来源和生成记录", "Reload service status, Excel source and job history", "โหลดสถานะบริการ แหล่ง Excel และประวัติงานใหม่"], "company.refresh_jobs": ["刷新任务", "Refresh jobs", "รีเฟรชงาน"], "company.service_unready": ["公司渠道明细服务暂未就绪", "Company channel detail service is not ready", "บริการรายละเอียดช่องทางบริษัทยังไม่พร้อม"], "company.service_unready_detail": ["请检查本机数据库和 Excel 生成服务后刷新。", "Check the local database and Excel generation service, then refresh.", "ตรวจสอบฐานข้อมูลและบริการสร้าง Excel ในเครื่อง แล้วรีเฟรช"], "company.generate": ["生成报表", "Generate reports", "สร้างรายงาน"], "company.report_month": ["报表月份", "Report month", "เดือนรายงาน"], "company.month_title": ["选择 C/O 所属报表月份,并筛选下方生成记录", "Choose the report month for C/O and filter the job history below", "เลือกเดือนรายงานของ C/O และกรองประวัติงานด้านล่าง"], "company.upload_title": ["上传 Excel 报表", "Upload Excel report", "อัปโหลดรายงาน Excel"], "company.choose_excel": ["选择或拖放 Excel 文件", "Choose or drop an Excel file", "เลือกหรือลากไฟล์ Excel"], "company.xlsx_limit": [".xlsx 格式,单个文件最大 25 MB", ".xlsx format, maximum 25 MB", "รูปแบบ .xlsx ขนาดไม่เกิน 25 MB"], "company.extract": ["提取并核对", "Extract and review", "แยกข้อมูลและตรวจสอบ"], "company.checking": ["核对中", "Checking", "กำลังตรวจสอบ"], "company.period_release_10": ["周期结束:当月 11 日 00:00(曼谷)", "Period ends: 00:00 on the 11th (Bangkok)", "รอบสิ้นสุด: 00:00 วันที่ 11 (กรุงเทพฯ)"], "company.period_release_20": ["周期结束:当月 21 日 00:00(曼谷)", "Period ends: 00:00 on the 21st (Bangkok)", "รอบสิ้นสุด: 00:00 วันที่ 21 (กรุงเทพฯ)"], "company.period_release_month_end": ["周期结束:次月 1 日 00:00(曼谷)", "Period ends: 00:00 on the first day of the next month (Bangkok)", "รอบสิ้นสุด: 00:00 วันที่ 1 ของเดือนถัดไป (กรุงเทพฯ)"], "company.generate_short": ["生成", "Generate", "สร้าง"], "company.review_title": ["Booking记录提取", "Booking record extraction", "การแยกรายการ Booking"], "company.extracted_file": ["提取文件", "Source file", "ไฟล์ต้นทาง"], "company.review_stats": ["提取统计", "Extraction summary", "สรุปการแยกข้อมูล"], "company.confirmed": ["已确认", "Confirmed", "ยืนยันแล้ว"], "company.pending_human": ["待人工", "Needs review", "รอตรวจสอบ"], "company.deleted": ["已删除", "Deleted", "ลบแล้ว"], "company.delete_selected": ["删除所选", "Delete selected", "ลบรายการที่เลือก"], "company.discard": ["放弃本次提取", "Discard this extraction", "ยกเลิกการแยกข้อมูลครั้งนี้"], "company.activate": ["确认并启用", "Confirm and activate", "ยืนยันและเปิดใช้งาน"], "company.extract_rooms": ["提取房型记录", "Extracted room records", "รายการประเภทห้องที่แยกได้"], "company.raw_identifier": ["原始标识", "Raw identifier", "ตัวระบุดิบ"], "company.empty_review": ["没有可显示的提取记录。", "No extraction records to display.", "ไม่มีรายการแยกข้อมูลให้แสดง"], "company.task_status": ["TASK STATUS", "TASK STATUS", "TASK STATUS"], "company.preparing": ["正在准备公司渠道明细任务", "Preparing company channel detail job", "กำลังเตรียมงานรายละเอียดช่องทางบริษัท"], "company.reading_status": ["正在读取任务状态。", "Reading job status.", "กำลังอ่านสถานะงาน"], "company.queued": ["已排队", "Queued", "เข้าคิวแล้ว"], "company.generating": ["生成中", "Generating", "กำลังสร้าง"], "company.all_success": ["全部成功", "All succeeded", "สำเร็จทั้งหมด"], "company.partial_success": ["部分成功", "Partially succeeded", "สำเร็จบางส่วน"], "company.incomplete": ["未完成", "Incomplete", "ยังไม่เสร็จ"], "company.waiting_generation": ["等待生成", "Waiting to generate", "รอสร้าง"], "company.success": ["成功", "Success", "สำเร็จ"], "company.success_review": ["成功 · 待复核", "Success · review needed", "สำเร็จ · ต้องตรวจสอบ"], "company.failed": ["失败", "Failed", "ล้มเหลว"], "company.not_generated": ["未生成", "Not generated", "ยังไม่สร้าง"], "company.warning_count": ["需复核", "Needs review", "ต้องตรวจสอบ"], "company.cutoff_10": ["截至 10 日", "Through the 10th", "ถึงวันที่ 10"], "company.cutoff_20": ["截至 20 日", "Through the 20th", "ถึงวันที่ 20"], "company.cutoff_month_end": ["截至月末", "Through month-end", "ถึงสิ้นเดือน"], "company.history": ["生成记录", "Generation history", "ประวัติการสร้าง"], "company.per_page": ["每页 50 条", "50 per page", "หน้าละ 50 รายการ"], "company.history_loading": ["正在读取公司渠道明细任务…", "Loading company channel detail jobs…", "กำลังโหลดงานรายละเอียดช่องทางบริษัท…"], "company.history_empty": ["该月份还没有公司渠道明细任务", "No company channel detail jobs for this month", "เดือนนี้ยังไม่มีงานรายละเอียดช่องทางบริษัท"], "company.processing_title": ["公司渠道明细处理", "Company channel detail processing", "การประมวลผลรายละเอียดช่องทางบริษัท"], "company.review_pagination": ["提取记录分页", "Extraction record pagination", "การแบ่งหน้ารายการแยกข้อมูล"], "company.history_pagination": ["生成记录分页", "Generation history pagination", "การแบ่งหน้าประวัติการสร้าง"], "company.result_caption": ["本次任务中五家公司的生成结果", "Generation results for the five companies in this job", "ผลการสร้างของห้าบริษัทในงานนี้"], "company.select_all_page": ["选择本页全部记录", "Select all records on this page", "เลือกทุกรายการในหน้านี้"], "company.generated": ["已生成", "Generated", "สร้างแล้ว"], "company.as_of": ["截止日期", "As-of date", "วันที่ข้อมูล"], "company.task_duration": ["任务耗时", "Job duration", "ระยะเวลางาน"], "company.cutoff_period": ["截止期间", "Cutoff period", "ช่วงเวลาสิ้นสุด"], "company.review_problem": ["复核 / 异常", "Review / issues", "ตรวจสอบ / ปัญหา"], "company.warning_short": ["需复核", "Needs review", "ต้องตรวจสอบ"], "company.report_default_description": ["2026年07月,01-10", "July 2026, 01-10", "กรกฎาคม 2026, 01-10"], "company.progress_waiting": ["等待生成", "Waiting to generate", "รอสร้าง"], "company.progress_failed": ["生成未完成", "Generation incomplete", "การสร้างไม่เสร็จ"], "company.progress_loading_finance": ["正在读取已校验的 finance 数据", "Loading validated finance data", "กำลังโหลดข้อมูล finance ที่ตรวจสอบแล้ว"], "company.progress_generating_excel": ["正在生成 5 家公司 Excel", "Generating Excel files for 5 companies", "กำลังสร้างไฟล์ Excel สำหรับ 5 บริษัท"], "company.progress_complete": ["生成完成", "Generation complete", "สร้างเสร็จแล้ว"], "company.progress_ended": ["生成已结束", "Generation ended", "การสร้างสิ้นสุดแล้ว"], "company.job_queued_message": ["任务已进入生成队列。", "The job entered the generation queue.", "งานเข้าสู่คิวการสร้างแล้ว"], "company.job_generating_message": ["正在按公司生成渠道明细表。", "Generating channel detail workbooks by company.", "กำลังสร้างตารางรายละเอียดช่องทางแยกตามบริษัท"], "company.job_success_message": ["5 家公司渠道明细表已生成。", "Channel detail workbooks for 5 companies were generated.", "สร้างตารางรายละเอียดช่องทางสำหรับ 5 บริษัทแล้ว"], "company.job_partial_message": ["部分公司已生成,失败公司可按错误代码复核后重跑。", "Some companies were generated. Review failed companies by error code and rerun.", "สร้างบางบริษัทแล้ว ตรวจสอบบริษัทที่ล้มเหลวตามรหัสข้อผิดพลาดแล้วลองใหม่"], "company.job_execution_failed_message": ["渠道明细生成未完成;未成功发布的公司不会提供下载。", "Channel detail generation did not complete; companies not published successfully will not be available for download.", "การสร้างรายละเอียดช่องทางไม่เสร็จ บริษัทที่เผยแพร่ไม่สำเร็จจะไม่พร้อมให้ดาวน์โหลด"], "company.discarding": ["正在放弃", "Discarding", "กำลังยกเลิก"], "company.deleting": ["正在删除", "Deleting", "กำลังลบ"], "company.confirm_delete_title": ["删除房型记录", "Delete room record", "ลบรายการประเภทห้อง"], "company.confirm_delete_description": ["确认删除所选房型记录?", "Delete the selected room record?", "ยืนยันการลบรายการประเภทห้องที่เลือกหรือไม่"], "company.confirm_discard_title": ["放弃本次提取", "Discard this extraction", "ยกเลิกการแยกข้อมูลครั้งนี้"], "company.confirm_discard_description": ["确认放弃本次提取?", "Discard this extraction?", "ยืนยันการยกเลิกการแยกข้อมูลครั้งนี้หรือไม่"], "company.confirm_discard_note": ["当前已做的人工修改和删除将被丢弃,原 Booking 数据源不会改变。", "Your edits and deletions will be discarded; the original Booking source will not change.", "การแก้ไขและการลบจะถูกทิ้ง แหล่งข้อมูล Booking เดิมจะไม่เปลี่ยนแปลง"], "company.confirm_delete_note": ["此操作只影响本次提取结果,确认启用前原数据源不会改变。", "This affects only this extraction; the original source will not change until activation.", "การดำเนินการนี้มีผลเฉพาะผลการแยกครั้งนี้ แหล่งข้อมูลเดิมจะไม่เปลี่ยนจนกว่าจะเปิดใช้งาน"], "company.confirm_delete": ["确认删除", "Confirm delete", "ยืนยันการลบ"], "company.confirm_discard": ["确认放弃", "Confirm discard", "ยืนยันการยกเลิก"], "company.confirm_generate": ["确认生成", "Confirm generation", "ยืนยันการสร้าง"], "company.generate_five": ["将一次生成五家公司的正式 Excel。", "This will generate the official Excel files for five companies.", "ระบบจะสร้างไฟล์ Excel อย่างเป็นทางการสำหรับห้าบริษัท"], "company.generate_early": ["周期尚未结束,将按当前已入库数据生成;后续新数据不会自动补入,可再次生成新版。", "The period is not complete. The current committed data will be used; later data will not be added automatically. Generate again for a new version.", "รอบยังไม่สิ้นสุด ระบบจะใช้ข้อมูลที่บันทึกแล้ว ข้อมูลใหม่จะไม่ถูกเพิ่มอัตโนมัติ สามารถสร้างเวอร์ชันใหม่ได้"], "company.no_valid_month": ["请先选择有效的报表月份", "Choose a valid report month first", "เลือกเดือนรายงานที่ถูกต้องก่อน"], "company.review_open": ["请先确认或放弃当前 Excel 提取结果", "Confirm or discard the current Excel extraction first", "ยืนยันหรือยกเลิกผลการแยก Excel ปัจจุบันก่อน"], "company.source_required": ["请先提取并启用 Excel 报表", "Extract and activate the Excel report first", "แยกและเปิดใช้งานรายงาน Excel ก่อน"], "company.service_required": ["公司渠道明细服务尚未就绪", "Company channel detail service is not ready", "บริการรายละเอียดช่องทางบริษัทยังไม่พร้อม"], "company.future_month": ["未来报表月份暂不可生成", "Future report months cannot be generated yet", "ยังไม่สามารถสร้างเดือนรายงานในอนาคตได้"], "company.select_month": ["选择月份", "Choose a month", "เลือกเดือน"], "company.period_not_finished": ["周期未结束", "Period not complete", "รอบยังไม่สิ้นสุด"], "company.period_finished": ["周期已结束", "Period complete", "รอบสิ้นสุดแล้ว"], "company.source_error": ["当前 Excel 数据源暂时无法读取", "The current Excel source is temporarily unavailable", "ไม่สามารถอ่านแหล่ง Excel ปัจจุบันได้ชั่วคราว"], "company.current_source": ["当前启用来源", "Active source", "แหล่งข้อมูลที่เปิดใช้งาน"], "company.source_active": ["已启用", "Active", "เปิดใช้งานแล้ว"], "company.source_meta": ["批次 #{batch} · {rows} 条记录 · {rooms} 间 · 启用于 {activated}", "Batch #{batch} · {rows} records · {rooms} rooms · Activated {activated}", "ชุดข้อมูล #{batch} · {rows} รายการ · {rooms} ห้อง · เปิดใช้งานเมื่อ {activated}"], "company.source_file_missing": ["未记录文件名", "File name not recorded", "ไม่ได้บันทึกชื่อไฟล์"], "company.source_already_active": ["这份 Excel 已是当前启用来源;请在下方按月份查看或生成对应报表", "This Excel is already the active source. Review or generate the corresponding report by month below.", "Excel นี้เป็นแหล่งข้อมูลที่เปิดใช้งานอยู่แล้ว ตรวจสอบหรือสร้างรายงานตามเดือนได้ด้านล่าง"], "company.job_source": ["来源 Excel(提交时)", "Source Excel (at submission)", "แหล่ง Excel (ขณะส่งงาน)"], "company.history_source": ["来源 Excel", "Source Excel", "แหล่ง Excel"], "company.job_source_missing": ["历史任务未记录来源", "Source not recorded for this historical job", "งานย้อนหลังนี้ไม่ได้บันทึกแหล่งข้อมูล"], "company.job_source_meta": ["批次 #{batch} · 启用于 {activated}", "Batch #{batch} · Activated {activated}", "ชุดข้อมูล #{batch} · เปิดใช้งานเมื่อ {activated}"], "company.draft_error": ["当前提取结果暂时无法读取", "The current extraction is temporarily unavailable", "ไม่สามารถอ่านผลการแยกปัจจุบันได้ชั่วคราว"], "company.file_xlsx": ["请选择 .xlsx 格式的 Excel 文件", "Choose an .xlsx Excel file", "เลือกไฟล์ Excel รูปแบบ .xlsx"], "company.file_empty": ["Excel 文件为空", "The Excel file is empty", "ไฟล์ Excel ว่างเปล่า"], "company.file_too_large": ["Excel 文件超过 25 MB", "The Excel file exceeds 25 MB", "ไฟล์ Excel มีขนาดเกิน 25 MB"], "company.file_extract_failed": ["Excel 文件未能完成提取", "The Excel file could not be extracted", "แยกข้อมูลจากไฟล์ Excel ไม่สำเร็จ"], "company.fill_room_type": ["请填写房型后再保存", "Enter a room type before saving", "กรอกประเภทห้องก่อนบันทึก"], "company.quantity_invalid": ["房间数量必须是 1 至 9999 的整数", "Room quantity must be an integer from 1 to 9999", "จำนวนห้องต้องเป็นจำนวนเต็มตั้งแต่ 1 ถึง 9999"], "company.review_saved": ["房型记录已保存", "Room record saved", "บันทึกรายการประเภทห้องแล้ว"], "company.review_deleted": ["房型记录已删除", "Room record deleted", "ลบรายการประเภทห้องแล้ว"], "company.review_discarded": ["本次提取已放弃,原数据源未改变", "Extraction discarded; the original source was not changed", "ยกเลิกการแยกแล้ว แหล่งข้อมูลเดิมไม่เปลี่ยนแปลง"], "company.review_activated": ["人工核对完成,Booking 数据源已启用", "Review complete; the Booking source is active", "ตรวจสอบเสร็จแล้ว เปิดใช้งานแหล่งข้อมูล Booking"], "company.review_discard_failed": ["本次提取未能放弃", "The extraction could not be discarded", "ยกเลิกการแยกข้อมูลไม่สำเร็จ"], "company.review_delete_failed": ["房型记录未能删除", "The room record could not be deleted", "ลบรายการประเภทห้องไม่สำเร็จ"], "company.review_save_failed": ["房型记录未能保存", "The room record could not be saved", "บันทึกรายการประเภทห้องไม่สำเร็จ"], "company.source_activate_failed": ["Booking 数据源未能启用", "The Booking source could not be activated", "เปิดใช้งานแหล่งข้อมูล Booking ไม่สำเร็จ"], "company.extract_done": ["提取完成,可以确认并启用", "Extraction complete. Confirm and activate.", "แยกข้อมูลเสร็จแล้ว ยืนยันและเปิดใช้งานได้"], "company.extract_pending": ["提取完成,{count} 条需要人工确认", "Extraction complete. {count} records need review.", "แยกข้อมูลเสร็จแล้ว ต้องตรวจสอบ {count} รายการ"], "company.file_name_missing": ["未记录文件名", "File name not recorded", "ไม่ได้บันทึกชื่อไฟล์"], "company.review_pending_confirm": ["待人工确认", "Pending human review", "รอยืนยันโดยเจ้าหน้าที่"], "company.review_save": ["保存", "Save", "บันทึก"], "company.review_delete": ["删除", "Delete", "ลบ"], "company.review_select": ["选择", "Select", "เลือก"], "company.review_no_record": ["暂无", "None", "ไม่มีข้อมูล"], "company.period_pending": ["待生成", "Pending", "รอสร้าง"], "company.period_waiting": ["等待生成", "Waiting to generate", "รอสร้าง"], "company.period_none": ["无结果", "No result", "ไม่มีผลลัพธ์"], "company.period_not_generated": ["未生成", "Not generated", "ยังไม่สร้าง"], "company.period_not_recorded": ["未记录", "Not recorded", "ไม่ได้บันทึก"], "company.report_prepare": ["正在准备公司渠道明细任务", "Preparing company channel detail job", "กำลังเตรียมงานรายละเอียดช่องทางบริษัท"], "company.report_waiting": ["等待生成", "Waiting to generate", "รอสร้าง"], "company.report_warning_count": ["{count} 项", "{count} items", "{count} รายการ"], "company.report_no_result": ["暂无", "None", "ไม่มีข้อมูล"], "company.this_record": ["这条记录", "this record", "รายการนี้"], "company.job_submitted": ["五家公司渠道明细任务已提交", "The five-company channel detail job was submitted", "ส่งงานรายละเอียดช่องทางของห้าบริษัทแล้ว"], "company.jobs_refreshed": ["公司渠道明细任务已刷新", "Company channel detail jobs refreshed", "รีเฟรชงานรายละเอียดช่องทางบริษัทแล้ว"], "company.job_submit_failed": ["公司渠道明细任务未能提交", "The company channel detail job could not be submitted", "ส่งงานรายละเอียดช่องทางบริษัทไม่สำเร็จ"], "task.title": ["任务日志", "Task log", "บันทึกงาน"], "task.description": ["显示当前选中的日报处理任务从上传到下游通知的处理日志。", "Shows the selected daily task from upload through downstream notification.", "แสดงบันทึกของงานรายวันที่เลือกตั้งแต่อัปโหลดจนถึงการแจ้งเตือนปลายทาง"], "task.kicker": ["DAILY JOB / LOG", "DAILY JOB / LOG", "DAILY JOB / LOG"], "task.raw_log": ["任务原始日志", "Raw task log", "บันทึกงานดิบ"], "task.refresh": ["刷新日志", "Refresh log", "รีเฟรชบันทึก"], "task.copy": ["复制全部日志", "Copy all logs", "คัดลอกบันทึกทั้งหมด"], "task.copying": ["复制中…", "Copying…", "กำลังคัดลอก…"], "task.copied": ["已复制", "Copied", "คัดลอกแล้ว"], "task.copy_failed": ["复制失败", "Copy failed", "คัดลอกไม่สำเร็จ"], "task.copy_none": ["暂无可复制的任务日志", "No task log to copy", "ไม่มีบันทึกงานให้คัดลอก"], "task.copy_denied": ["无法复制日志,请检查浏览器剪贴板权限", "Could not copy the log. Check browser clipboard permission.", "คัดลอกบันทึกไม่ได้ โปรดตรวจสอบสิทธิ์คลิปบอร์ดของเบราว์เซอร์"], "task.clipboard_denied": ["浏览器未允许访问剪贴板", "The browser did not allow clipboard access", "เบราว์เซอร์ไม่อนุญาตให้เข้าถึงคลิปบอร์ด"], "task.reading": ["正在读取任务日志", "Reading task log", "กำลังอ่านบันทึกงาน"], "task.reading_detail": ["正在聚合数据库中的处理证据…", "Aggregating processing evidence from the database…", "กำลังรวมหลักฐานการประมวลผลจากฐานข้อมูล…"], "task.unavailable": ["任务日志暂时无法读取", "The task log is temporarily unavailable", "ไม่สามารถอ่านบันทึกงานได้ชั่วคราว"], "task.no_server_log": ["服务端没有返回可用日志。", "The server returned no usable log.", "เซิร์ฟเวอร์ไม่ส่งบันทึกที่ใช้ได้กลับมา"], "task.not_selected": ["未选择任务", "No task selected", "ยังไม่ได้เลือกงาน"], "task.waiting_upload": ["等待上传 ARR.XML", "Waiting for ARR.XML upload", "รอการอัปโหลด ARR.XML"], "task.after_create": ["新任务创建后,这里会显示服务端保存的全流程日志。", "The server-side trace will appear here after a new task is created.", "บันทึกจากเซิร์ฟเวอร์จะแสดงที่นี่หลังสร้างงานใหม่"], "task.inline_prompt": ["请上传文件,或从 Daily Report 中选择一个任务。", "Upload a file or select a task from Daily Report.", "อัปโหลดไฟล์หรือเลือกงานจาก Daily Report"], "task.refresh_failed": ["日志刷新失败", "Log refresh failed", "รีเฟรชบันทึกไม่สำเร็จ"], "task.auto_refresh_failed": ["自动刷新失败", "Auto-refresh failed", "อัปเดตอัตโนมัติไม่สำเร็จ"], "task.created": ["任务已登记到 ARR 程序化处理队列。", "The task was registered in the ARR processing queue.", "ลงทะเบียนงานในคิวประมวลผล ARR แล้ว"], "task.processor_started": ["ARR 已开始处理已登记的源 XML。", "ARR started processing the registered source XML.", "ARR เริ่มประมวลผล XML ต้นทางที่ลงทะเบียนแล้ว"], "task.processor_failed": ["程序化处理失败", "Programmatic processing failed", "การประมวลผลแบบโปรแกรมไม่สำเร็จ"], "task.processor_cancelled": ["程序化处理已取消", "Programmatic processing cancelled", "ยกเลิกการประมวลผลแบบโปรแกรมแล้ว"], "task.processor_complete": ["处理尝试已闭环", "Processing attempt completed", "การประมวลผลเสร็จสิ้น"], "task.accepted": ["业务任务已完成", "Business task completed", "งานธุรกิจเสร็จสิ้น"], "task.upload_registered": ["上传已安全登记", "Upload safely registered", "ลงทะเบียนการอัปโหลดอย่างปลอดภัยแล้ว"], "task.trace_processing": ["处理已结束", "Processing ended", "การประมวลผลสิ้นสุดแล้ว"], "task.trace_failed": ["处理未能完成", "Processing could not complete", "การประมวลผลไม่เสร็จสมบูรณ์"], "task.refreshed": ["任务日志已刷新", "Task log refreshed", "รีเฟรชบันทึกงานแล้ว"], "task.no_job_id": ["任务编号暂不可用,请刷新 Daily Report。", "The task ID is not available yet. Refresh Daily Report.", "รหัสงานยังไม่พร้อม โปรดรีเฟรช Daily Report"], "task.failed_refresh_hint": ["请刷新 Daily Report,确认是否已登记失败任务。", "Refresh Daily Report to confirm whether a failed task was recorded.", "รีเฟรช Daily Report เพื่อตรวจสอบว่าบันทึกงานที่ล้มเหลวแล้วหรือไม่"], "task.error_status": ["处理失败", "Processing failed", "ประมวลผลไม่สำเร็จ"], "task.live_failed": ["日志刷新失败", "Log refresh failed", "รีเฟรชบันทึกไม่สำเร็จ"], "task.live_auto_failed": ["自动刷新失败", "Auto-refresh failed", "อัปเดตอัตโนมัติไม่สำเร็จ"], "task.live_reading": ["正在读取", "Reading", "กำลังอ่าน"], "task.live_unselected": ["未选择任务", "No task selected", "ยังไม่ได้เลือกงาน"], "task.trace_failed_status": ["FAILED", "FAILED", "FAILED"], "task.trace_running_status": ["RUNNING / auto refresh {seconds}s", "RUNNING / auto refresh {seconds}s", "RUNNING / อัปเดตทุก {seconds}s"], "task.trace_succeeded_status": ["SUCCEEDED", "SUCCEEDED", "SUCCEEDED"], "task.trace_unknown_status": ["UNKNOWN", "UNKNOWN", "UNKNOWN"], "task.no_events": ["0 events", "0 events", "0 เหตุการณ์"], "task.events": ["{count} events", "{count} events", "{count} เหตุการณ์"], "task.raw_log_count": ["0 lines", "0 lines", "0 บรรทัด"], "task.raw_log_aria": ["任务原始日志", "Raw task log", "บันทึกงานดิบ"], "task.browser_clipboard": ["浏览器未允许访问剪贴板", "The browser did not allow clipboard access", "เบราว์เซอร์ไม่อนุญาตให้เข้าถึงคลิปบอร์ด"], "task.none_to_copy": ["暂无可复制的任务日志", "No task log to copy", "ไม่มีบันทึกงานให้คัดลอก"], "task.copying_lines": ["已复制全部任务日志({count} 行)", "Copied all task logs ({count} lines)", "คัดลอกบันทึกงานทั้งหมดแล้ว ({count} บรรทัด)"], "task.copy_button": ["复制全部日志", "Copy all logs", "คัดลอกบันทึกทั้งหมด"], "task.copying_button": ["复制中…", "Copying…", "กำลังคัดลอก…"], "task.copied_button": ["已复制", "Copied", "คัดลอกแล้ว"], "task.copy_failed_button": ["复制失败", "Copy failed", "คัดลอกไม่สำเร็จ"], "task.close_button": ["关闭", "Close", "ปิด"], "error.generic": ["请求未完成", "The request could not be completed", "ดำเนินการตามคำขอไม่สำเร็จ"], "error.unrecognized_response": ["服务返回了无法识别的结果", "The service returned an unrecognized response", "บริการส่งผลลัพธ์ที่ไม่รู้จักกลับมา"], "error.database_unavailable": ["数据库连接失败", "Database connection failed", "เชื่อมต่อฐานข้อมูลไม่สำเร็จ"], "error.database_read_unavailable": ["数据库读取服务暂不可用", "Database read service is temporarily unavailable", "บริการอ่านฐานข้อมูลไม่พร้อมใช้งานชั่วคราว"], "error.query_invalid": ["查询参数无效", "Invalid query parameters", "พารามิเตอร์การค้นหาไม่ถูกต้อง"], "error.auth_required": ["请先登录", "Please log in first", "กรุณาเข้าสู่ระบบก่อน"], "error.login_failed": ["用户名或密码不正确", "Incorrect username or password", "ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง"], "error.login_rate_limited": ["登录尝试过于频繁,请稍后再试", "Too many login attempts. Try again later.", "พยายามเข้าสู่ระบบบ่อยเกินไป โปรดลองอีกครั้งภายหลัง"], "error.request_invalid": ["请求内容不是有效 JSON", "The request is not valid JSON", "คำขอไม่ใช่ JSON ที่ถูกต้อง"], "error.request_too_large": ["请求内容过大", "The request is too large", "คำขอมีขนาดใหญ่เกินไป"], "error.upload_empty": ["XML 文件为空", "The XML file is empty", "ไฟล์ XML ว่างเปล่า"], "error.upload_too_large": ["XML 文件超过 25 MB", "The XML file exceeds 25 MB", "ไฟล์ XML มีขนาดเกิน 25 MB"], "error.upload_invalid": ["文件内容不是 XML", "The file content is not XML", "เนื้อหาไฟล์ไม่ใช่ XML"], "error.upload_filename": ["请选择 XML 文件", "Choose an XML file", "เลือกไฟล์ XML"], "error.job_id": ["任务编号无效", "Invalid task ID", "รหัสงานไม่ถูกต้อง"], "error.route_not_found": ["页面或接口不存在", "The page or endpoint does not exist", "ไม่พบหน้าหรือปลายทาง"], "error.static_not_found": ["页面资源不存在", "The page resource does not exist", "ไม่พบทรัพยากรของหน้า"], "error.session_invalid": ["页面会话已失效", "The page session is no longer valid", "เซสชันของหน้าไม่ถูกต้องแล้ว"], "error.download_not_found": ["文件不存在或尚未生成", "The file does not exist or has not been generated", "ไม่พบไฟล์หรือยังไม่ได้สร้าง"], "error.download_invalid": ["文件身份无效", "Invalid file identity", "ข้อมูลระบุไฟล์ไม่ถูกต้อง"], "error.download_unavailable": ["文件读取服务暂不可用", "The file read service is temporarily unavailable", "บริการอ่านไฟล์ไม่พร้อมใช้งานชั่วคราว"], "error.download_integrity": ["文件完整性校验失败", "File integrity check failed", "ตรวจสอบความสมบูรณ์ของไฟล์ไม่ผ่าน"], "error.company_source_required": ["请先上传并校验 Excel 报表", "Upload and validate the Excel report first", "อัปโหลดและตรวจสอบรายงาน Excel ก่อน"], "error.company_review_open": ["请先完成或放弃当前 Excel 提取草稿", "Complete or discard the current Excel draft first", "ดำเนินการหรือยกเลิกร่าง Excel ปัจจุบันก่อน"], "error.company_future": ["未来报表月份暂不可生成", "Future report months cannot be generated yet", "ยังไม่สามารถสร้างเดือนรายงานในอนาคตได้"], "error.company_running": ["同一月份和期间已有生成任务", "A job already exists for this month and period", "มีงานสำหรับเดือนและช่วงเวลานี้อยู่แล้ว"], "error.company_unavailable": ["公司渠道明细生成服务暂不可用", "Company channel detail generation is temporarily unavailable", "บริการสร้างรายละเอียดช่องทางบริษัทไม่พร้อมใช้งานชั่วคราว"], "error.company_download": ["该公司的正式表格尚不可下载", "The official workbook for this company is not ready to download", "ไฟล์อย่างเป็นทางการของบริษัทนี้ยังไม่พร้อมดาวน์โหลด"], "error.booking_unavailable": ["Excel 数据源服务暂未就绪", "The Excel source service is not ready", "บริการแหล่ง Excel ยังไม่พร้อม"], "error.booking_extract_failed": ["Excel 文件未能完成提取", "The Excel file could not be extracted", "แยกข้อมูลจากไฟล์ Excel ไม่สำเร็จ"], "error.processing_failed": ["文件已安全接收,但程序化处理未能完成", "The file was received safely, but processing did not complete", "รับไฟล์อย่างปลอดภัยแล้ว แต่การประมวลผลไม่เสร็จ"], "error.invalid_request": ["请求字段无效", "Invalid request fields", "ฟิลด์คำขอไม่ถูกต้อง"], "error.invalid_period": ["期间无效", "Invalid period", "ช่วงเวลาไม่ถูกต้อง"], "error.invalid_company": ["公司名称无效", "Invalid company name", "ชื่อบริษัทไม่ถูกต้อง"], "error.not_found": ["任务或数据不存在", "The task or data was not found", "ไม่พบงานหรือข้อมูล"], "error.service_unavailable": ["服务暂时不可用", "The service is temporarily unavailable", "บริการไม่พร้อมใช้งานชั่วคราว"], "error.internal": ["服务暂时无法完成请求", "The service could not complete the request", "บริการไม่สามารถดำเนินการตามคำขอได้"], "error.month_invalid": ["报表月份无效", "Invalid report month", "เดือนรายงานไม่ถูกต้อง"], "error.monthly_busy": ["该服务正在生成月报", "The monthly report service is already running", "บริการรายงานประจำเดือนกำลังทำงาน"], "error.monthly_failed": ["月报生成未完成", "Monthly report generation did not complete", "การสร้างรายงานประจำเดือนไม่เสร็จ"], "error.monthly_not_found": ["找不到该月份的正式月报。", "The published monthly report for this month was not found.", "ไม่พบรายงานประจำเดือนที่เผยแพร่ของเดือนนี้"], "error.channel_invalid": ["渠道名称无效", "Invalid channel name", "ชื่อช่องทางไม่ถูกต้อง"], "error.login_request_invalid": ["登录请求格式或字段无效", "The login request is invalid", "คำขอเข้าสู่ระบบไม่ถูกต้อง"], "error.content_length_required": ["请求长度缺失", "Request length is missing", "ไม่มีความยาวคำขอ"], "error.booking_filename": ["请选择 .xlsx 格式的 Excel 文件", "Choose an .xlsx Excel file", "เลือกไฟล์ Excel รูปแบบ .xlsx"], "error.review_request_invalid": ["人工确认请求无效", "The review request is invalid", "คำขอตรวจสอบไม่ถูกต้อง"], "error.review_item_invalid": ["待确认记录编号无效", "Invalid review item ID", "รหัสรายการตรวจสอบไม่ถูกต้อง"], "error.company_request_invalid": ["渠道明细请求字段无效", "Invalid company detail request fields", "ฟิลด์คำขอรายละเอียดบริษัทไม่ถูกต้อง"], "error.company_source_already_active": ["这份 Excel 已经启用,无需重复提取", "This Excel is already active; no duplicate extraction is needed", "Excel นี้เปิดใช้งานอยู่แล้ว ไม่จำเป็นต้องแยกข้อมูลซ้ำ"], "error.company_period_invalid": ["期间必须是 01-10、11-20 或 21-month-end", "Period must be 01-10, 11-20 or 21-month-end", "ช่วงเวลาต้องเป็น 01-10, 11-20 หรือ 21-month-end"], "error.company_job_not_found": ["任务不存在", "The job does not exist", "ไม่พบงาน"], "error.download_too_large": ["文件超过下载限制", "The file exceeds the download limit", "ไฟล์มีขนาดเกินขีดจำกัดการดาวน์โหลด"], "problem.multi_price": ["同房型存在不同静态价格,需人工复核", "The same room type has different static prices; review required", "ประเภทห้องเดียวกันมีราคาคงที่ต่างกัน ต้องตรวจสอบ"], "problem.source_missing": ["数据源版本缺失", "Source version is missing", "ไม่มีเวอร์ชันแหล่งข้อมูล"], "problem.group_missing": ["Group Code 缺失", "Group Code is missing", "ไม่มี Group Code"], "problem.group_not_found": ["Group Code 未找到", "Group Code not found", "ไม่พบ Group Code"], "problem.booking_parse": ["预订解析异常", "Booking parsing error", "เกิดข้อผิดพลาดในการแยก Booking"], "problem.room_items_missing": ["房型明细缺失", "Room details are missing", "ไม่มีรายละเอียดประเภทห้อง"], "problem.stay_date": ["住宿日期异常", "Invalid stay date", "วันที่เข้าพักไม่ถูกต้อง"], "problem.nights_conflict": ["间夜数据冲突", "Room-night data conflict", "ข้อมูลคืนห้องพักขัดแย้งกัน"], "problem.total_price": ["静态价格异常", "Invalid static price", "ราคาคงที่ไม่ถูกต้อง"], "problem.output_validation": ["Excel 输出校验失败", "Excel output validation failed", "ตรวจสอบผลลัพธ์ Excel ไม่ผ่าน"], "problem.publish_failed": ["正式表格发布失败", "Official workbook publication failed", "เผยแพร่ไฟล์อย่างเป็นทางการไม่สำเร็จ"], "problem.internal": ["处理服务异常", "Processing service error", "บริการประมวลผลขัดข้อง"], "problem.execution": ["任务执行未完成", "Job execution did not complete", "การทำงานยังไม่เสร็จ"], "problem.interrupted": ["服务重启中断任务", "The service restart interrupted the job", "การรีสตาร์ตบริการขัดจังหวะงาน"], "problem.review_result": ["需复核处理结果", "Review the processing result", "โปรดตรวจสอบผลการประมวลผล"], "units.second": ["秒", "sec", "วินาที"], "units.seconds": ["秒", "sec", "วินาที"], "units.minute": ["分", "min", "นาที"], "units.minutes": ["分", "min", "นาที"], "units.rows": ["条", "records", "รายการ"], "units.items": ["项", "items", "รายการ"], "pagination.zero": ["共 0 条", "0 records", "0 รายการ"], "pagination.summary": ["共 {total} 条 · 本页 {start} 至 {end}", "{total} records · Showing {start}–{end}", "{total} รายการ · แสดง {start}–{end}"], "pagination.page": ["第 {page} / {pages} 页", "Page {page} of {pages}", "หน้า {page} จาก {pages}"], "history.pagination": ["{month} · {summary}", "{month} · {summary}", "{month} · {summary}"], "history.daily_empty": ["{month} · 暂无 Daily Report 记录", "{month} · No Daily Report records", "{month} · ไม่มีรายการ Daily Report"], "history.monthly_empty": ["{month} · 暂无月报处理记录", "{month} · No monthly processing records", "{month} · ไม่มีรายการประมวลผลรายเดือน"], "history.company_empty": ["{month} · 暂无公司渠道明细任务", "{month} · No company channel detail jobs", "{month} · ไม่มีงานรายละเอียดช่องทางบริษัท"], "history.view_recent": ["查看 {month}", "View {month}", "ดู {month}"], "progress.auto_update": ["自动更新 · {seconds} 秒", "Auto-refresh · {seconds} sec", "อัปเดตอัตโนมัติ · {seconds} วินาที"], "period.release": ["周期结束:{date} 00:00(曼谷)", "Period ends: {date} 00:00 (Bangkok)", "รอบสิ้นสุด: {date} 00:00 (กรุงเทพฯ)"], "period.release_hint": ["周期尚未结束;可按当前已入库数据生成,周期结束时间为曼谷 {date} 00:00", "The period is not complete; current committed data can be used. The Bangkok completion time is {date} 00:00.", "รอบยังไม่สิ้นสุด ใช้ข้อมูลที่บันทึกแล้วสร้างได้ เวลาสิ้นสุดที่กรุงเทพฯ คือ {date} 00:00"], "company.month_end": ["21-月末", "21-month-end", "21-สิ้นเดือน"], "company.range_month_end": ["21-{day}", "21-{day}", "21-{day}"], "company.range_co": ["C/O:{range}", "C/O:{range}", "C/O:{range}"], "company.month_label": ["{year}年{month}月", "{monthName} {year}", "{monthName} {year}"], "company.at_period": ["{month},{period}", "{month}, {period}", "{month}, {period}"], "company.selected_count": ["已选 {count} 条", "{count} selected", "เลือก {count} รายการ"], "company.deleted_count": ["已删除 {count} 条房型记录", "Deleted {count} room records", "ลบรายการประเภทห้อง {count} รายการแล้ว"], "company.delete_count": ["删除 {count} 条", "Delete {count}", "ลบ {count} รายการ"], "company.confirm_single_delete": ["确认删除 {tourCode} 的这条房型记录?", "Delete this room record for {tourCode}?", "ลบรายการประเภทห้องของ {tourCode} หรือไม่"], "company.confirm_multi_delete": ["确认删除已选择的 {count} 条房型记录?", "Delete the {count} selected room records?", "ลบรายการประเภทห้องที่เลือก {count} รายการหรือไม่"], "company.selected_file": ["{name} · {size} KB", "{name} · {size} KB", "{name} · {size} KB"], "task.selected_job": ["任务 {jobId}", "Task {jobId}", "งาน {jobId}"], "task.view_job": ["查看任务 {jobId} 的全流程日志", "View the full trace for task {jobId}", "ดูบันทึกทั้งหมดของงาน {jobId}"], "task.copied_lines": ["已复制全部任务日志({count} 行)", "Copied all task logs ({count} lines)", "คัดลอกบันทึกงานทั้งหมดแล้ว ({count} บรรทัด)"], "bi.data_range": ["数据范围:{start} – {end}", "Data coverage: {start} – {end}", "ช่วงข้อมูล: {start} – {end}"], "company.warning_items": ["{count} 项", "{count} items", "{count} รายการ"], "company.period_rows": ["✓ {count} 条", "✓ {count} records", "✓ {count} รายการ"], "company.period_end_display": ["周期结束:{date} 00:00(曼谷)", "Period ends: {date} 00:00 (Bangkok)", "รอบสิ้นสุด: {date} 00:00 (กรุงเทพฯ)"], "trace.events": ["0 events", "0 events", "0 เหตุการณ์"], "trace.events_count": ["{count} events", "{count} events", "{count} เหตุการณ์"], "trace.failed": ["ERROR", "ERROR", "ERROR"], "trace.loading": ["LOADING", "LOADING", "LOADING"], "trace.idle": ["IDLE", "IDLE", "IDLE"], "trace.failed_status": ["FAILED / {stage} / {code}", "FAILED / {stage} / {code}", "FAILED / {stage} / {code}"], "trace.running_status": ["RUNNING / auto refresh {seconds}s", "RUNNING / auto refresh {seconds}s", "RUNNING / อัปเดตทุก {seconds}s"], "trace.succeeded_status": ["SUCCEEDED", "SUCCEEDED", "SUCCEEDED"], "trace.unknown_status": ["{status}", "{status}", "{status}"], "h5.snapshot": ["基于已发布月报快照", "Based on the published monthly snapshot", "อ้างอิงสแนปช็อตรายเดือนที่เผยแพร่แล้ว"], "h5.nights_formula": ["房数 × 晚数", "Rooms × nights", "ห้อง × จำนวนคืน"], "h5.monthly_sheet": ["月报子表", "Monthly worksheets", "ชีตรายงานประจำเดือน"], "h5.loading": ["正在读取数据…", "Loading data…", "กำลังโหลดข้อมูล…"], "h5.login_title": ["ARR Report 登录", "ARR Report login", "เข้าสู่ระบบ ARR Report"], "login.title": ["登录 · ARR Report", "Log in · ARR Report", "เข้าสู่ระบบ · ARR Report"], "h5.title": ["渠道BI · ARR Report", "Channel BI · ARR Report", "Channel BI · ARR Report"], }; const ERROR_KEYS = { LOGIN_FAILED: "error.login_failed", LOGIN_RATE_LIMITED: "error.login_rate_limited", AUTH_REQUIRED: "error.auth_required", SESSION_INVALID: "error.session_invalid", REQUEST_JSON_INVALID: "error.request_invalid", REQUEST_TOO_LARGE: "error.request_too_large", UPLOAD_FILENAME_INVALID: "error.upload_filename", UPLOAD_EMPTY: "error.upload_empty", UPLOAD_TOO_LARGE: "error.upload_too_large", UPLOAD_CONTENT_INVALID: "error.upload_invalid", JOB_ID_INVALID: "error.job_id", ROUTE_NOT_FOUND: "error.route_not_found", STATIC_NOT_FOUND: "error.static_not_found", QUERY_INVALID: "error.query_invalid", DATABASE_UNAVAILABLE: "error.database_unavailable", DATABASE_DRIVER_UNAVAILABLE: "error.database_read_unavailable", DATABASE_CONFIG_MISSING: "error.database_read_unavailable", DATABASE_TARGET_INVALID: "error.database_read_unavailable", DATABASE_QUERY_FAILED: "error.database_read_unavailable", DOWNLOAD_NOT_FOUND: "error.download_not_found", DOWNLOAD_REQUEST_INVALID: "error.download_invalid", DOWNLOAD_REFERENCE_INVALID: "error.download_invalid", DOWNLOAD_UNAVAILABLE: "error.download_unavailable", DOWNLOAD_IDENTITY_MISMATCH: "error.download_integrity", BOOKING_EXCEL_SERVICE_UNAVAILABLE: "error.booking_unavailable", BOOKING_EXCEL_PROCESSING_FAILED: "error.booking_extract_failed", BOOKING_EXCEL_REVIEW_OPEN: "error.company_review_open", BOOKING_EXCEL_SOURCE_REQUIRED: "error.company_source_required", BOOKING_EXCEL_SOURCE_ALREADY_ACTIVATED: "error.company_source_already_active", COMPANY_REPORT_MONTH_IN_FUTURE: "error.company_future", COMPANY_REPORT_ALREADY_RUNNING: "error.company_running", COMPANY_REPORT_GENERATOR_UNAVAILABLE: "error.company_unavailable", COMPANY_REPORT_DOWNLOAD_NOT_FOUND: "error.company_download", PROGRAMMATIC_PROCESSING_FAILED: "error.processing_failed", MONTH_INVALID: "error.month_invalid", MONTH_KEY_INVALID: "error.month_invalid", CHANNEL_INVALID: "error.channel_invalid", LOGIN_REQUEST_INVALID: "error.login_request_invalid", CONTENT_LENGTH_REQUIRED: "error.content_length_required", INTERNAL_ERROR: "error.internal", PROCESSING_GATEWAY_UNAVAILABLE: "error.service_unavailable", MONTHLY_GENERATOR_UNAVAILABLE: "error.service_unavailable", MONTHLY_REQUEST_INVALID: "error.invalid_request", MONTHLY_ALREADY_RUNNING: "error.monthly_busy", MONTHLY_GENERATION_FAILED: "error.monthly_failed", MONTHLY_NOT_FOUND: "error.monthly_not_found", BOOKING_EXCEL_FILENAME_INVALID: "error.booking_filename", BOOKING_EXCEL_REVIEW_REQUEST_INVALID: "error.review_request_invalid", BOOKING_EXCEL_REVIEW_ITEM_INVALID: "error.review_item_invalid", COMPANY_REPORT_REQUEST_INVALID: "error.company_request_invalid", COMPANY_REPORT_PERIOD_INVALID: "error.company_period_invalid", COMPANY_REPORT_COMPANY_INVALID: "error.invalid_company", COMPANY_REPORT_JOB_NOT_FOUND: "error.company_job_not_found", COMPANY_REPORT_DOWNLOAD_INVALID: "error.download_invalid", DOWNLOAD_TOO_LARGE: "error.download_too_large", }; const sourceToKey = new Map(); Object.entries(CATALOG).forEach(([key, values]) => { if (!sourceToKey.has(values[0])) sourceToKey.set(values[0], key); }); let locale = DEFAULT_LOCALE; let translating = false; const sourceTextValues = new WeakMap(); const sourceAttributeValues = new WeakMap(); function validLocale(value) { return Object.prototype.hasOwnProperty.call(LOCALES, value) ? value : null; } function readCookie(name) { const match = document.cookie.match(new RegExp(`(?:^|; )${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}=([^;]*)`)); return match ? decodeURIComponent(match[1]) : ""; } function writeLocaleCookie(value) { document.cookie = `${COOKIE_KEY}=${encodeURIComponent(value)}; Path=/; Max-Age=31536000; SameSite=Strict`; } function resolveLocale() { let candidate = null; try { candidate = validLocale(window.localStorage.getItem(STORAGE_KEY)); } catch (_) { /* private mode */ } return candidate || validLocale(readCookie(COOKIE_KEY)) || DEFAULT_LOCALE; } function currentMeta() { return LOCALES[locale] || LOCALES[DEFAULT_LOCALE]; } function interpolate(value, params = {}) { return String(value).replace(/\{([A-Za-z0-9_]+)\}/g, (_, name) => String(params[name] ?? "")); } function t(key, params = {}) { const entry = CATALOG[key]; if (!entry) return interpolate(key, params); const index = locale === "en" ? 1 : locale === "th" ? 2 : 0; return interpolate(entry[index] || entry[0], params); } function keyForSource(value) { const normalized = String(value ?? "").trim(); return sourceToKey.get(normalized) || null; } function patternText(value) { const source = String(value ?? ""); const trimmed = source.trim(); const exact = keyForSource(trimmed); if (exact) return t(exact); let match = /^共\s*([\d,]+)\s*条\s*·\s*本页\s*([\d,]+)\s*至\s*([\d,]+)$/.exec(trimmed); if (match) return t("pagination.summary", { total: match[1], start: match[2], end: match[3] }); match = /^第\s*([\d,]+)\s*\/\s*([\d,]+)\s*页$/.exec(trimmed); if (match) return t("pagination.page", { page: match[1], pages: match[2] }); match = /^已选\s*([\d,]+)\s*条$/.exec(trimmed); if (match) return t("company.selected_count", { count: match[1] }); match = /^已删除\s*([\d,]+)\s*条房型记录$/.exec(trimmed); if (match) return t("company.deleted_count", { count: match[1] }); match = /^删除\s*([\d,]+)\s*条$/.exec(trimmed); if (match) return t("company.delete_count", { count: match[1] }); match = /^提取完成,\s*([\d,]+)\s*条需要人工确认$/.exec(trimmed); if (match) return t("company.extract_pending", { count: match[1] }); match = /^✓\s*([\d,]+)\s*条$/.exec(trimmed); if (match) return t("company.period_rows", { count: match[1] }); match = /^([\d,]+)\s*项$/.exec(trimmed); if (match) return t("company.warning_items", { count: match[1] }); match = /^自动更新\s*·\s*([\d,]+)\s*秒$/.exec(trimmed); if (match) return t("progress.auto_update", { seconds: match[1] }); match = /^周期结束:(.+?)\s*00:00(曼谷)$/.exec(trimmed); if (match) return t("company.period_end_display", { date: match[1] }); match = /^周期尚未结束;可按当前已入库数据生成,周期结束时间为曼谷\s*(.+?)\s*00:00$/.exec(trimmed); if (match) return t("period.release_hint", { date: match[1] }); match = /^(\d{4})年(\d{2})月,(.+)$/.exec(trimmed); if (match) return t("company.at_period", { month: `${match[1]}年${match[2]}月`, period: match[3] }); match = /^(\d{4})年(\d{2})月$/.exec(trimmed); if (match) return t("company.month_label", { year: match[1], month: match[2], monthName: `${match[1]}年${match[2]}月` }); match = /^任务\s+(.+)$/.exec(trimmed); if (match) return t("task.selected_job", { jobId: match[1] }); match = /^查看任务\s+(.+?)\s+的全流程日志$/.exec(trimmed); if (match) return t("task.view_job", { jobId: match[1] }); match = /^([\d,]+)\s*秒$/.exec(trimmed); if (match) return `${match[1]} ${t("units.seconds")}`; match = /^([\d,]+)\s*分\s*([\d,]+)\s*秒$/.exec(trimmed); if (match) return `${match[1]} ${t("units.minutes")} ${match[2]} ${t("units.seconds")}`; return source; } function translateValue(value) { if (typeof value !== "string") return value; if (value.includes("\n")) { return value.split("\n").map((line) => patternText(line)).join("\n"); } const leading = value.match(/^\s*/)?.[0] || ""; const trailing = value.match(/\s*$/)?.[0] || ""; return `${leading}${patternText(value)}${trailing}`; } function translateAttribute(value) { const translated = translateValue(value); if (translated !== value) return translated; let match = /^ARR Report 首页$/.exec(value); if (match) return t("brand.home"); match = /^查看任务\s+(.+?)\s+的全流程日志$/.exec(value); if (match) return t("task.view_job", { jobId: match[1] }); match = /^选择\s+(.+)$/.exec(value); if (match) return `${t("common.select")} ${match[1]}`; match = /^(.+?)\s+房型$/.exec(value); if (match) return `${match[1]} ${t("common.room_type")}`; match = /^(.+?)\s+数量$/.exec(value); if (match) return `${match[1]} ${t("common.quantity")}`; match = /^(.+?)\s*·\s*退出登录$/.exec(value); if (match) return `${match[1]} · ${t("auth.logout")}`; return value; } function translateDom(root = document) { if (translating || !root) return; translating = true; try { const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT); const nodes = []; let node; while ((node = walker.nextNode())) { const parent = node.parentElement; if (!parent || ["SCRIPT", "STYLE"].includes(parent.tagName)) continue; nodes.push(node); } nodes.forEach((textNode) => { const source = sourceTextValues.has(textNode) ? sourceTextValues.get(textNode) : textNode.nodeValue; sourceTextValues.set(textNode, source); const value = translateValue(source); if (value !== textNode.nodeValue) textNode.nodeValue = value; }); root.querySelectorAll?.("[aria-label], [title], [placeholder], [aria-valuetext]").forEach((element) => { ["aria-label", "title", "placeholder", "aria-valuetext"].forEach((attribute) => { if (!element.hasAttribute(attribute)) return; const values = sourceAttributeValues.get(element) || new Map(); const current = element.getAttribute(attribute); const source = values.has(attribute) ? values.get(attribute) : current; values.set(attribute, source); sourceAttributeValues.set(element, values); const next = translateAttribute(source); if (next !== current) element.setAttribute(attribute, next); }); }); root.querySelectorAll?.("[data-arr-locale-selector]").forEach((select) => { select.value = locale; select.setAttribute("aria-label", t("common.language")); }); } finally { translating = false; } } function formatInteger(value) { return new Intl.NumberFormat(currentMeta().intl, { maximumFractionDigits: 0 }).format(Number(value || 0)); } function formatMoney(value, compact = false) { const amount = Number(value || 0); const formatter = new Intl.NumberFormat(currentMeta().intl, compact ? { notation: "compact", maximumFractionDigits: 2 } : { maximumFractionDigits: 0 }); return `¥${formatter.format(amount)}`; } function formatDate(value, withTime = false) { if (!value) return "—"; const date = new Date(value); if (Number.isNaN(date.getTime())) return translateValue(String(value)); return new Intl.DateTimeFormat(currentMeta().intl, withTime ? { timeZone: "Asia/Bangkok", calendar: "gregory", year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", hourCycle: "h23" } : { timeZone: "Asia/Bangkok", calendar: "gregory", year: "numeric", month: "2-digit", day: "2-digit" } ).format(date); } function formatMonth(value) { const match = /^(\d{4})-(\d{2})$/.exec(value || ""); if (!match) return t("common.year_month_unselected"); const date = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, 1)); return new Intl.DateTimeFormat(currentMeta().intl, { timeZone: "UTC", calendar: "gregory", year: "numeric", month: "long" }).format(date); } function formatDurationSeconds(value) { const seconds = Number(value); if (!Number.isFinite(seconds)) return t("common.none"); if (seconds < 60) return `${Math.max(1, Math.round(seconds))} ${t("units.seconds")}`; return `${Math.floor(seconds / 60)} ${t("units.minutes")} ${Math.round(seconds % 60)} ${t("units.seconds")}`; } function errorMessage(code, fallback = "") { const normalizedCode = String(code || ""); const key = ERROR_KEYS[normalizedCode] || ( normalizedCode.endsWith("_NOT_FOUND") ? "error.not_found" : normalizedCode.includes("UNAVAILABLE") || normalizedCode.endsWith("_TIMEOUT") ? "error.service_unavailable" : normalizedCode.endsWith("_INVALID") || normalizedCode.includes("REQUEST") ? "error.invalid_request" : normalizedCode.endsWith("_FAILED") || normalizedCode.endsWith("_ERROR") ? "error.generic" : null ); if (key) return t(key); const translated = fallback ? translateValue(fallback) : ""; const containsCjk = /[\u4e00-\u9fff]/.test(translated); const containsThai = /[\u0e00-\u0e7f]/.test(translated); if (translated && locale === DEFAULT_LOCALE) return translated; if (translated && locale === "en" && !containsCjk && !containsThai) return translated; if (translated && locale === "th" && !containsCjk && containsThai) return translated; return t("error.generic"); } function setLocale(next) { const resolved = validLocale(next) || DEFAULT_LOCALE; locale = resolved; try { window.localStorage.setItem(STORAGE_KEY, resolved); } catch (_) { /* private mode */ } writeLocaleCookie(resolved); document.documentElement.lang = resolved; translateDom(); document.dispatchEvent(new CustomEvent("arr:locale-change", { detail: { locale: resolved } })); } function bindSelectors() { document.querySelectorAll("[data-arr-locale-selector]").forEach((select) => { select.value = locale; select.addEventListener("change", (event) => setLocale(event.currentTarget.value)); }); } function init() { locale = resolveLocale(); document.documentElement.lang = locale; bindSelectors(); translateDom(); const observer = new MutationObserver((mutations) => { if (locale === DEFAULT_LOCALE || translating) return; mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeType === Node.ELEMENT_NODE) translateDom(node); else if (node.nodeType === Node.TEXT_NODE) { sourceTextValues.set(node, node.nodeValue); node.nodeValue = translateValue(node.nodeValue); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); } window.ARRI18n = { CATALOG, LOCALES, get locale() { return locale; }, t, text: translateValue, translateDom, errorMessage, formatInteger, formatMoney, formatDate, formatMonth, formatDurationSeconds, setLocale, }; if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", init, { once: true }); else init(); })();