UNPKG

iobroker.roborock

Version:
247 lines (221 loc) 8.04 kB
// Define types for the dataset structure interface Dataset { meta: { languages: string[]; generated: string; }; fault_codes: { [code: string]: { internal?: string; [lang: string]: { title: string; summary?: string; } | string | undefined; }; }; translations: { [lang: string]: { [key: string]: string; }; }; general_translations?: { [lang: string]: { [key: string]: string; }; }; attribute_mappings?: Record<string, string>; status_map?: Record<string, string>; } export class RoborockLocales { private dataset: Dataset; private attributeMap: Record<string, string> = {}; constructor(dataset: Dataset) { this.dataset = dataset; // Merge attribute mappings from dataset if available if (this.dataset.attribute_mappings) { this.attributeMap = { ...this.attributeMap, ...this.dataset.attribute_mappings }; } } private isDatasetValid(): boolean { return !!this.dataset; } /** * Get translated text for a generic key. * @param key The translation key (e.g., "setting_consumable_mop") * @param language The language code (e.g., "en", "de") */ public getText(key: string, language: string = "en"): string { if (!this.isDatasetValid()) return key; // Normalize ioBroker language codes to dataset keys let normalizedLang = language.toLowerCase(); if (normalizedLang === "zh-cn") normalizedLang = "zh"; if (normalizedLang === "zh-tw") normalizedLang = "zh-hant"; // Try translations first // Look up using a case-insensitive check to handle zh-Hant vs zh-hant const datasetLangKey = Object.keys(this.dataset.translations || {}).find( (k) => k.toLowerCase() === normalizedLang.toLowerCase() ); const langData = datasetLangKey ? this.dataset.translations?.[datasetLangKey] : null; if (langData && langData[key]) { return langData[key]; } // Try general_translations const genData = this.dataset.general_translations?.[language]; if (genData && genData[key]) { return genData[key]; } // Fallback to English translations const enData = this.dataset.translations?.["en"]; if (enData && enData[key]) { return enData[key]; } // Fallback to English general_translations const enGenData = this.dataset.general_translations?.["en"]; if (enGenData && enGenData[key]) { return enGenData[key]; } return key; // Return key if not found } /** * Get all available translations for a key. */ public getTranslations(key: string): Record<string, string> { const translations: Record<string, string> = {}; if (!this.isDatasetValid()) return translations; // Collect from regular translations if (this.dataset.translations) { for (const lang in this.dataset.translations) { const langDict = this.dataset.translations[lang]; if (langDict && langDict[key]) { translations[lang] = langDict[key]; } } } // Collect from general translations if missing in specific language if (this.dataset.general_translations) { for (const lang in this.dataset.general_translations) { const langDict = this.dataset.general_translations[lang]; if (langDict && langDict[key] && !translations[lang]) { translations[lang] = langDict[key]; } } } return translations; } /** * Get translated error text. * @param errorCode The error code * @param language The language code */ public getErrorText(errorCode: string | number, language: string = "en"): string { let normalizedLang = language.toLowerCase(); if (normalizedLang === "zh-cn") normalizedLang = "zh"; if (normalizedLang === "zh-tw") normalizedLang = "zh-hant"; const codeStr = errorCode.toString(); const fault = this.dataset.fault_codes?.[codeStr]; if (fault) { const getTitle = (entry: any) => (typeof entry === "object" && entry !== null) ? entry.title : entry; const langTitle = getTitle(fault[normalizedLang]); if (langTitle && typeof langTitle === "string") return langTitle; const enTitle = getTitle(fault["en"]); if (enTitle && typeof enTitle === "string") return enTitle; } return `Error ${errorCode}`; } /** * Get the translation key for a given device attribute. * Returns undefined if no mapping is found. */ public getAttributeKey(attribute: string): string | undefined { if (!this.isDatasetValid()) return undefined; if (this.dataset.attribute_mappings) { return this.dataset.attribute_mappings[attribute]; } return undefined; } /** * Get the translation key for a status code. */ public getStatusKey(statusCode: string | number): string | undefined { if (this.dataset.status_map) { return this.dataset.status_map[statusCode.toString()]; } return undefined; } public getErrorCodes(): number[] { if (!this.dataset.fault_codes) return []; return Object.keys(this.dataset.fault_codes).map(k => parseInt(k)).filter(k => !isNaN(k) && k !== 0); } /** * Get the mapped value for Cloth State (Mop Mount). * Mirrors logic: if not 0, show warning. * @param value The cloth_state value * @param language The language code */ public getClothStateText(value: number, language: string = "en"): string { if (value === 0) { return this.getText("setting_consumable_mop", language) + ": " + this.getText("common_on", language); } else if (value === 1) { // Removed / Not Installed return this.getText("setting_consumable_change_tips7", language); } else { // 2 or other = Dirty / abnormal? Default to generic warning return this.getText("setting_consumable_change_tips7", language) + ` (${value})`; } } public getWaterBoxModeText(value: number, language: string = "en"): string { switch (value) { case 200: return this.getText("home_clean_water_close", language); case 201: return this.getText("home_clean_water_low", language); case 202: return this.getText("home_clean_water_medium", language); case 203: return this.getText("home_clean_water_high", language); default: return this.getText("unknown", language) || `Water ${value}`; } } public getFanPowerText(value: number, language: string = "en"): string { switch (value) { case 101: return this.getText("home_clean_wind_silence", language); case 102: return this.getText("home_clean_wind_standard", language); case 103: return this.getText("home_clean_wind_strong", language); case 104: return this.getText("home_clean_wind_super_strong", language); case 105: return this.getText("home_clean_wind_max", language); default: return this.getText("unknown", language) || `Fan ${value}`; } } public getMopModeText(value: number, language: string = "en"): string { switch (value) { case 300: return this.getText("home_clean_route_standard", language); case 301: return this.getText("home_clean_route_carefully", language); case 302: return this.getText("home_clean_route_deep_plus", language); case 303: return this.getText("home_clean_route_custom", language); default: return this.getText("unknown", language) || `MopMode ${value}`; } } public getName(attribute: string, language: string = "en"): string | undefined { const key = this.attributeMap[attribute]; if (key) { return this.getText(key, language); } return undefined; } /** * Get all translations for an attribute name (for common.name object) */ public getNameAll(attribute: string): ioBroker.StringOrTranslated { const key = this.attributeMap[attribute]; if (key) { const trans = this.getTranslations(key); if (Object.keys(trans).length > 0) { trans["en"] = trans["en"] || key; return trans as ioBroker.StringOrTranslated; } } // If translation missing, return key (if mapped) or raw attribute name as fallback string. // This ensures we can use keys like 'water_tank' that are defined in words.js but not in the dataset. return key || attribute; } }