@zeesoft/i18n-verify 2.2.1 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/i18n.mjs +1 -1
  2. package/package.json +1 -1
package/dist/i18n.mjs CHANGED
@@ -1 +1 @@
1
- import e,{statSync as t,existsSync as n,readFileSync as a,readdirSync as r,writeFileSync as i,appendFileSync as s,mkdirSync as o}from"fs";import l,{join as c,dirname as d,extname as u}from"path";import g from"globalize";import p from"cldr-data";import{en as h,uk as m,nl as f,ru as y,zh as v,ja as w,pt as b,fr as D,es as L,de as T}from"chrono-node";import{DateTime as I}from"luxon";import{detectTextLangEx as S}from"@isdk/detect-text-language";import{Table as E}from"console-table-printer";import C from"chrome-remote-interface";import N from"jimp";class z{constructor(e){this.$driver=e}checkIfNullOrEmpty(e){return![null,"",void 0].includes(e)}getElement(){throw new Error("implementation is missing")}getElements(){throw new Error("implementation is missing")}getText(){throw new Error("implementation is missing")}getTitle(){throw new Error("implementation is missing")}getPlaceholderText(){throw new Error("implementation is missing")}getAltText(){throw new Error("implementation is missing")}getWidth(){throw new Error("implementation is missing")}getHeight(){throw new Error("implementation is missing")}getTagName(){throw new Error("implementation is missing")}getValue(){throw new Error("implementation is missing")}getLocation(){throw new Error("implementation is missing")}getElementDimension(){throw new Error("implementation is missing")}getElementID(){throw new Error("implementation is missing")}isElementDisplayed(){throw new Error("implementation is missing")}isElementPresent(){throw new Error("implementation is missing")}getElementString(){throw new Error("implementation is missing")}getElementStrings(){throw new Error("implementation is missing")}captureScreenshot(){throw new Error("implementation is missing")}getElementsCount(){throw new Error("implementation is missing")}switchIframe(){throw new Error("implementation is missing")}switchToParentframe(){throw new Error("implementation is missing")}pause(){throw new Error("implementation is missing")}onScreenStringHighlight(){throw new Error("implementation is missing")}checkIfIframeIsPresent(){throw new Error("implementation is missing")}checkIfIframeBodyIsEmpty(){throw new Error("implementation is missing")}printOnConsole(e){console.log(e)}}const x={NIGHT_WATCH:"nightwatch",WEB_DRIVER_IO:"webio",CYPRESS:"cypress",SELENIUMJS:"seleniumJS"},M="rgb(0, 154, 61)",P="rgb(255, 0, 0)",_="rgb(255, 255, 0)",O="rgb(0, 0, 255)",A="",R="",j="",k="STRING_LOCALIZED",U="STRING_PARTIALLY_LOCALIZED",F="NUMBER_LOCALIZED",G="CURRENCY_LOCALIZED",V="PERCENTAGE_LOCALIZED",Q="DATE_LOCALIZED",q="TIME_LOCALIZED",B="DATE_TIME_LOCALIZED",Y="STRING_NOT_LOCALIZED",H="NUMBER_NOT_LOCALIZED",Z="CURRENCY_NOT_LOCALIZED",W="PERCENTAGE_NOT_LOCALIZED",J="DATE_NOT_LOCALIZED",X="TIME_NOT_LOCALIZED",K="DATE_TIME_NOT_LOCALIZED",ee="TRUNCATION_ISSUE",te="OVERLAPPING_ISSUE",ne="ENCODING_ISSUE",ae="DNT",re="IGNORE",ie="UNTRANSLATED",se="AUTO_IGNORE",oe="USER_INPUT",le="REVIEWED",ce={[k]:0,[Y]:0,[U]:0,[F]:0,[H]:0,[Q]:0,[J]:0,[B]:0,[K]:0,[q]:0,[X]:0,[G]:0,[Z]:0,[V]:0,[W]:0,[ee]:0,[te]:0,[ne]:0,[ae]:0,[re]:0,[ie]:0,[se]:0,[oe]:0,[le]:0},de={[k]:[M,A],[U]:[_,j],[F]:[M,A],[Q]:[M,A],[q]:[M,A],[B]:[M,A],[G]:[M,A],[V]:[M,A],[Y]:[P,R],[J]:[P,R],[K]:[P,R],[X]:[P,R],[H]:[P,R],[Z]:[P,R],[W]:[P,R],[ee]:[P,R],[te]:[P,R],[ne]:[P,R],[ae]:[M,A],[re]:[M,A],[ie]:[M,A],[se]:[M,A],[oe]:[M,A],[le]:[M,A]},ue={[k]:"string is localized",[U]:"string is partially localized",[F]:"number is localized",[Q]:"date is localized",[B]:"dateTime is localized",[q]:"time is localized",[G]:"currency is localized",[V]:"percentage is localized",[Y]:"string is not localized",[J]:"date is not localized",[K]:"dateTime is not localized",[X]:"time is not localized",[H]:"number is not localized",[Z]:"currency is not localized",[W]:"percentage is not localized",[ee]:"truncation issue detected",[te]:"overlapping issue detected",[ne]:"encoding issue detected",[ae]:"do not translate",[re]:"ignored this issue",[ie]:"string is untranslated",[se]:"automatically ignored issue",[oe]:"user input field",[le]:"string has been reviewed"},ge={EMAIL:/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}\b/gi,URL:/^(https?:\/\/)?(www\.)?[a-zA-Z0-9-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?$/},pe=[".txt",".json"],he="//*[string-length(normalize-space(text())) > 0 and not(ancestor-or-self::*/@style[contains(.,'display:none')]) or @placeholder] | //input[@type='checkbox']/parent::*[text() and not(ancestor-or-self::*/@style[contains(.,'display:none')])]",me=!0,fe=["☐","�","퟿","â€","î","ÃÂ","í","ü","é","é","æ•°","据","ラã"],ye=".i18n-verify.rc",ve="html",we="ascii_table",be="metrics.cache",De=e=>Te(e)&&t(e).isDirectory(),Le=e=>Te(e)&&t(e).isFile(),Te=e=>n(e),Ie=(e,t=!0)=>{Te(e)&&De(e)||(t&&it.debug(`Folder doesn't exists, creating ${e}`),(e=>{!Te(e)&&o(e,{recursive:!0})})(e))},Se=e=>Le(e)?a(e,{encoding:"utf-8"}):"",Ee=e=>De(e)?r(e):[],Ce=(...e)=>c(...e),Ne=(e,t,n="utf-8")=>i(e,t,{encoding:n});class ze{#e;#t;constructor({appName:e,reportTime:t}){this.#e=e,this.#t=t}getAppName(){return this.#e}getReportTime(){return this.#t}}class xe{#n;$generatedContent;$type;constructor(e){this.$type=e}generate(e){this.#n=e,this.$generatedContent=this.buildContent()}export(e,t="report"){this.write(e,t,this.$generatedContent),it.info(`Exported consolidated I18n Verification ${this.$type} report in ${e}`)}write(e,t,n){throw new Error("should be implemented by child report classes")}buildContent(){throw new Error("should be implemented by child report classes")}getMetaInfo(){return{defaultLocale:mt.getDefaultLocale(),appName:this.#n.getAppName(),reportTime:this.#n.getReportTime(),sanityCapture:mt.getOptions()?.sanityCapture}}}class Me extends xe{constructor(){super(ve)}buildContent(){const e=this.getMetaInfo(),t=`var DataStore;\n // global functions\n function openImageViewer(imageSrc) {\n var imageView = document.getElementById('imageView');\n imageView.src = \`\${window.getProductUrl()}/\${imageSrc}\`;\n document.getElementById('imageViewer').style.display = 'block';\n }\n\n function closeImageViewer() {\n delete document.getElementById('imageView').src;\n document.getElementById('imageViewer').style.display = 'none';\n }\n\n //to dynamically show/hide header based upon query param: ?standalone=<true|false>\n window.getProductUrl = () => {\n if (window.productUrl) {\n return window.productUrl;\n } else {\n window.productUrl = \`\${window.location.protocol}//\${\n window.location.host\n }\${window.location.pathname.match(/^.+[^\\/report\\.html]/g)?.[0]}\`;\n return window.productUrl;\n }\n };\n const params = new URLSearchParams(location.href.match(/(\\?.*$)/g)?.[0]);\n if (params.size) {\n window.reducedZoom = params.get('standalone') === 'false';\n if(window.reducedZoom) {\n const overview = document.getElementById('overview');\n if(overview) {\n overview.classList.add('--reduced-zoom');\n }\n }\n }\n ${(e=>`// DataStore\n (() => {\n // prepare appData and set DataStore\n var appData = {\n appName: '${e.appName}',\n defaultLocale: '${e.defaultLocale}',\n sanityRun: ${e.sanityCapture},\n timeStamp: '${e.reportTime}',\n metaData: {\n stats: {},\n statsByLocale: {}\n },\n stringsData: {},\n locales: Object.keys(rawData)\n };\n\n for (const entry of Object.entries(rawData)) {\n const locale = entry[0];\n const stats = entry[1].metaData.stats;\n const stringsData = entry[1].stringsData;\n\n if (Object.keys(appData.metaData.stats).length) {\n for (const prop in stats) {\n appData.metaData.stats[prop] += stats[prop];\n }\n } else {\n appData.metaData.stats = {...stats};\n }\n\n appData.metaData.statsByLocale[locale] = stats;\n appData.stringsData[locale] = stringsData;\n }\n\n function SimpleDataStore() {\n this._getData = () => appData;\n\n this.ranSuccessfully = () => this.getLocales().length > 0;\n\n this.getTimestamp = () => this._getData().timeStamp;\n\n this.getAppName = () => this._getData().appName;\n\n this.isDefaultLocale = (locale) =>\n locale === this._getData().defaultLocale;\n\n this.getLocalesData = () => this._getData().stringsData || {};\n\n this.getLocales = () => this._getData().locales || [];\n\n this.getStatByLocale = (locale) =>\n this._getData().metaData.statsByLocale[locale] || {};\n\n this.getOverallStats = () => this._getData().metaData.stats || {};\n\n this.getDataByLocale = (locale) =>\n this._getData().stringsData[locale] || {};\n\n this.isSanityRun = () => this._getData().sanityRun;\n }\n\n DataStore = new SimpleDataStore();\n })();`)(e)}\n (() => {\n // for sidebar menu\n const loadContent = (section, highlightMenu = false) => {\n if (highlightMenu) {\n document\n .querySelector('li[data-page="overview"]')\n ?.classList.add('selected');\n }\n\n const contents = document.querySelectorAll('.content');\n const wrapper = document.querySelector('.content-wrapper');\n\n contents.forEach((content) => {\n content.id !== section\n ? content.classList.remove('active')\n : content.classList.add('active');\n\n section === 'overview' &&\n window.persistOverviewCharts &&\n window.persistOverviewCharts();\n\n section === 'log' ? wrapper.classList.add('--hide-overflow') : wrapper.classList.remove('--hide-overflow');\n window.currentPage = section;\n });\n };\n\n document.addEventListener('DOMContentLoaded', function () {\n const createMenuItems = (() => {\n const ul = document.querySelector('.sidebar .submenu');\n const createListItems = (locale) => {\n const li = document.createElement('li');\n li.classList.add('sub-menu-item');\n li.dataset.locale = locale;\n\n const a = document.createElement('a');\n a.href = '#';\n a.textContent = locale;\n\n li.appendChild(a);\n return li;\n };\n\n for (const locale of DataStore.getLocales()) {\n ul.appendChild(createListItems(locale));\n }\n })();\n\n const menuItems = document.querySelectorAll('.menu-item'),\n submenuItems = document.querySelectorAll('.sub-menu-item');\n\n menuItems.forEach((item) => {\n item.addEventListener('click', function (event) {\n const selectedMenuItem = document.querySelector(\n '.menu-item.selected'\n ),\n selectedSubmenu = document.querySelector('.submenu.active'),\n page = item.dataset.page;\n\n if (selectedMenuItem) {\n selectedMenuItem.classList.remove('selected');\n }\n\n if (selectedSubmenu) {\n selectedSubmenu.classList.remove('active');\n }\n\n if (item.classList.contains('has-submenu')) {\n event.preventDefault();\n item.classList.add('selected');\n const submenu = item.querySelector('.submenu');\n submenu.classList.add('active');\n } else {\n item.classList.add('selected');\n }\n\n if (selectedSubmenu) {\n selectedSubmenu\n .querySelectorAll('.sub-menu-item')\n .forEach((submenuItem) => {\n submenuItem.textContent !== item.textContent &&\n submenuItem.classList.remove('selected');\n });\n }\n\n loadContent(page);\n });\n\n loadContent('overview', true);\n });\n\n submenuItems.forEach((sItem) => {\n sItem.addEventListener('click', function (event) {\n const selectedSubMenuItem = document.querySelector(\n '.sub-menu-item.selected'\n );\n event.preventDefault();\n event.stopPropagation();\n\n if (selectedSubMenuItem) {\n selectedSubMenuItem.classList.remove('selected');\n window.previousSelectedLocale =\n selectedSubMenuItem.dataset.locale;\n }\n\n sItem.classList.add('selected');\n loadContent('locale');\n });\n });\n\n // update footer info\n const footer = document.querySelector('.sidebar .footer');\n footer.textContent = \`\${new Date().getFullYear()} @ Zeesoft. All rights reserved.\`;\n\n // update project info\n document.querySelector(\n 'header .logo'\n ).innerHTML = \`zQA Report | \${DataStore.getAppName()} [\${DataStore.isSanityRun() ? 'Quick Sanity' : 'I18n Verification'}]<span class="project-info"><span class="time">Report generated at: \${DataStore.getTimestamp()}</span></span>\`;\n });\n })();\n //overview content\n (() => {\n if (!DataStore.ranSuccessfully()) {\n document.getElementById('overview').innerHtml =\n 'Unable to prepare zQA automation report for the project.';\n return;\n }\n\n document.addEventListener('DOMContentLoaded', function () {\n let overviewChart,\n stringChart,\n dateTimeChart,\n numberChart,\n ignoredChart;\n\n window.persistOverviewCharts = () => {\n const reset = (chart) => {\n chart.resetSeries(true, true);\n };\n\n reset(overviewChart);\n reset(stringChart);\n reset(dateTimeChart);\n reset(numberChart);\n reset(ignoredChart);\n };\n\n renderOverallChart();\n renderStringChart();\n renderIgnoredChart();\n renderNumberChart();\n renderDatetimeChart();\n\n function renderOverallChart() {\n const overallStats = DataStore.getOverallStats();\n const reviewed = overallStats.reviewed;\n const locales = DataStore.getLocales().length;\n const type = {\n I18NED: 'Internationalized',\n NOT_I18NED: 'Not Internationalized',\n SKIPPED: 'Skipped'\n },\n valueMap = {\n [type.I18NED]:\n overallStats.localizedStrings +\n overallStats.partialStrings + // TODO: need to confirm\n overallStats.untranslatedStrings +\n overallStats.localizedDateTime +\n overallStats.localizedDate +\n overallStats.localizedTime +\n overallStats.localizedNumber +\n overallStats.localizedCurrency +\n overallStats.localizedPercentage,\n [type.NOT_I18NED]:\n overallStats.notLocalizedStrings +\n overallStats.notLocalizedDateTime +\n overallStats.notLocalizedDate +\n overallStats.notLocalizedTime +\n overallStats.notLocalizedNumber +\n overallStats.notLocalizedCurrency +\n overallStats.notLocalizedPercentage,\n [type.SKIPPED]:\n overallStats.dnt +\n overallStats.ignored +\n overallStats.autoIgnored +\n overallStats.userInput\n },\n percentageCalc = (value) => {\n const val = ((value / reviewed) * 100).toFixed(0);\n return isNaN(val) || !isFinite(val) ? 0 : val;\n };\n\n var options = {\n series: [\n {\n name: '',\n data: [\n percentageCalc(valueMap[type.I18NED]),\n percentageCalc(valueMap[type.NOT_I18NED]),\n percentageCalc(valueMap[type.SKIPPED])\n ]\n }\n ],\n chart: {\n type: 'bar',\n height: 200,\n toolbar: {\n show: false\n },\n animations: {\n enabled: true,\n easing: 'easeinout',\n speed: 800,\n animateGradually: {\n enabled: true,\n delay: 150\n },\n dynamicAnimation: {\n enabled: true,\n speed: 350\n }\n }\n },\n plotOptions: {\n bar: {\n horizontal: true,\n borderRadius: 3,\n dataLabels: {\n position: 'right'\n }\n }\n },\n title: {\n text: \`Total Reviewed strings in \${locales} locales: \${reviewed}\`,\n align: 'center',\n floating: true,\n style: {\n fontSize: '14px',\n fontWeight: 'bold'\n }\n },\n dataLabels: {\n enabled: true,\n style: {\n colors: ['#080404b0']\n },\n formatter: (val) => {\n return \`\${val}%\`;\n }\n },\n xaxis: {\n categories: [type.I18NED, type.NOT_I18NED, type.SKIPPED],\n min: 0,\n max: 100,\n labels: {\n formatter: (v) => \`\${v}%\`\n }\n },\n yaxis: {\n labels: {\n style: {\n fontSize: '13px'\n }\n }\n },\n colors: [\n (v) => {\n switch (v.dataPointIndex) {\n case 0:\n return '#31E994'; //green\n case 1:\n return '#ff8173'; //red\n case 2:\n return '#f5eb5f'; //yellow\n }\n }\n ],\n tooltip: {\n theme: 'dark',\n x: {\n formatter: (v) => \`Total Number of \${v} instances:\`\n },\n y: {\n formatter: function (v, { dataPointIndex }) {\n let count = 0;\n switch (dataPointIndex) {\n case 0:\n count = valueMap[type.I18NED];\n break;\n case 1:\n count = valueMap[type.NOT_I18NED];\n break;\n case 2:\n count = valueMap[type.SKIPPED];\n break;\n }\n return \`\${v}% (\${count} strings)\`;\n }\n }\n }\n };\n\n (overviewChart = new ApexCharts(\n document.querySelector('.overall-quality .graph'),\n options\n )).render();\n }\n\n function renderStringChart() {\n const overallStats = DataStore.getOverallStats();\n const type = {\n LOCALIZED: 'Localized',\n PARTIAL: 'Partially Localized',\n NOT_LOCALIZED: 'Not Localized',\n UNTRANSLATED: 'Untranslated',\n ENCODING: 'Encoding Issue',\n IGNORED: 'Ignored'\n },\n valueMap = {\n [type.LOCALIZED]: overallStats.localizedStrings,\n [type.PARTIAL]: overallStats.partialStrings,\n [type.NOT_LOCALIZED]: overallStats.notLocalizedStrings,\n [type.UNTRANSLATED]: overallStats.untranslatedStrings,\n [type.ENCODING]: overallStats.encoding,\n [type.IGNORED]:\n overallStats.dnt +\n overallStats.ignored +\n overallStats.autoIgnored +\n overallStats.userInput\n },\n total = Object.values(valueMap).reduce(\n (acc, curr) => acc + curr,\n 0\n ),\n data = [\n valueMap[type.LOCALIZED],\n valueMap[type.PARTIAL],\n valueMap[type.NOT_LOCALIZED],\n valueMap[type.IGNORED],\n valueMap[type.ENCODING],\n valueMap[type.UNTRANSLATED]\n ],\n options = {\n series:\n data.reduce((acc, curr) => acc + curr, 0) === 0 ? [] : data,\n chart: {\n width: 415,\n type: 'pie',\n animations: {\n enabled: true,\n easing: 'easeinout',\n speed: 800,\n animateGradually: {\n enabled: true,\n delay: 150\n },\n dynamicAnimation: {\n enabled: true,\n speed: 350\n }\n }\n },\n noData: {\n text: 'No metrics available',\n align: 'left',\n verticalAlign: 'middle',\n offsetX: 0,\n offsetY: -50,\n style: {\n fontSize: '14px'\n }\n },\n labels: [\n type.LOCALIZED,\n type.PARTIAL,\n type.NOT_LOCALIZED,\n type.IGNORED,\n type.ENCODING,\n type.UNTRANSLATED\n ],\n tooltip: {\n theme: 'dark',\n y: {\n formatter: function (v, { config, dataPointIndex }) {\n let count = 0,\n value = Number(\n (v /\n config.series.reduce((acc, curr) => acc + curr, 0)) *\n 100\n ).toFixed(0);\n value = isNaN(value) || !isFinite(value) ? 0 : value;\n\n switch (dataPointIndex) {\n case 0:\n count = valueMap[type.LOCALIZED];\n break;\n case 1:\n count = valueMap[type.PARTIAL];\n break;\n case 2:\n count = valueMap[type.NOT_LOCALIZED];\n break;\n case 3:\n count = valueMap[type.IGNORED];\n break;\n case 4:\n count = valueMap[type.ENCODING];\n break;\n case 5:\n count = valueMap[type.UNTRANSLATED];\n break;\n }\n\n return \`\${value}% (\${count} strings)\`;\n },\n title: {\n formatter: function (a) {\n return \`Total Number of \${a} strings:\`;\n }\n }\n }\n },\n colors: [\n ({ seriesIndex, w }) => {\n const currType = w.config.labels[seriesIndex];\n\n switch (currType) {\n case type.LOCALIZED:\n return '#31E994';\n case type.NOT_LOCALIZED:\n return '#E44242';\n case type.PARTIAL:\n return '#DADF40';\n case type.UNTRANSLATED:\n return '#F44E9E';\n case type.IGNORED:\n return '#AFA6AB';\n case type.ENCODING:\n return '#3AD1F3';\n\n default:\n return '';\n }\n }\n ],\n legend: {\n offsetX: -50,\n width: 170,\n formatter: (seriesName, a, b, c) => {\n let value = ((valueMap[seriesName] / total) * 100).toFixed(0);\n value = isNaN(value) || !isFinite(value) ? 0 : value;\n return \`\${seriesName} (\${value}%)\`;\n }\n },\n dataLabels: {\n formatter: (v) => \`\${Number(v).toFixed(0)}%\`,\n dropShadow: { enabled: false },\n style: {\n colors: ['#080404b0']\n }\n }\n };\n\n (stringChart = new ApexCharts(\n document.querySelector('.string-quality .graph'),\n options\n )).render();\n }\n\n function renderIgnoredChart() {\n const overallStats = DataStore.getOverallStats();\n const type = {\n DNT: 'DNT',\n IGNORED: 'Ignored',\n USER_INPUTS: 'User Inputs'\n },\n valueMap = {\n [type.DNT]: overallStats.dnt,\n [type.IGNORED]: overallStats.ignored + overallStats.autoIgnored,\n [type.USER_INPUTS]: overallStats.userInput\n },\n total = Object.values(valueMap).reduce(\n (acc, curr) => acc + curr,\n 0\n ),\n data = [\n valueMap[type.DNT],\n valueMap[type.IGNORED],\n valueMap[type.USER_INPUTS]\n ],\n options = {\n series:\n data.reduce((acc, curr) => acc + curr, 0) === 0 ? [] : data,\n chart: {\n width: 360,\n type: 'pie',\n animations: {\n enabled: true,\n easing: 'easeinout',\n speed: 800,\n animateGradually: {\n enabled: true,\n delay: 150\n },\n dynamicAnimation: {\n enabled: true,\n speed: 350\n }\n }\n },\n labels: [type.DNT, type.IGNORED, type.USER_INPUTS],\n tooltip: {\n theme: 'dark',\n y: {\n formatter: function (v, { config, dataPointIndex }) {\n let count = 0,\n value = Number(\n (v /\n config.series.reduce((acc, curr) => acc + curr, 0)) *\n 100\n ).toFixed(0);\n value = isNaN(value) || !isFinite(value) ? 0 : value;\n\n switch (dataPointIndex) {\n case 0:\n count = valueMap[type.DNT];\n break;\n case 1:\n count = valueMap[type.IGNORED];\n break;\n case 2:\n count = valueMap[type.USER_INPUTS];\n break;\n }\n\n return \`\${value}% (\${count} strings)\`;\n },\n title: {\n formatter: function (a) {\n return \`Total Number of \${a} strings:\`;\n }\n }\n }\n },\n colors: [\n ({ seriesIndex, w }) => {\n const currType = w.config.labels[seriesIndex];\n\n switch (currType) {\n case type.DNT:\n return '#31E994';\n case type.IGNORED:\n return '#3AD1F3';\n case type.USER_INPUTS:\n return '#DADF40';\n\n default:\n return '';\n }\n }\n ],\n noData: {\n text: 'No metrics available',\n align: 'center',\n verticalAlign: 'middle',\n offsetX: -70,\n offsetY: -25,\n style: {\n fontSize: '14px'\n }\n },\n legend: {\n offsetX: -40,\n formatter: (seriesName) => {\n let value = ((valueMap[seriesName] / total) * 100).toFixed(0);\n value = isNaN(value) || !isFinite(value) ? 0 : value;\n return \`\${seriesName} (\${value}%)\`;\n }\n },\n dataLabels: {\n formatter: (v) => \`\${Number(v).toFixed(0)}%\`,\n style: {\n colors: ['#080404b0']\n },\n dropShadow: { enabled: false }\n }\n };\n\n (ignoredChart = new ApexCharts(\n document.querySelector('.skipped-items .graph'),\n options\n )).render();\n }\n\n function renderNumberChart() {\n const overallStats = DataStore.getOverallStats();\n const types = ['Number', 'Currency', 'Percentage'],\n data = {\n number_i18n: overallStats.localizedNumber,\n currency_i18n: overallStats.localizedCurrency,\n percentage_i18n: overallStats.localizedPercentage,\n number_not_i18n: overallStats.notLocalizedNumber,\n currency_not_i18n: overallStats.notLocalizedCurrency,\n percentage_not_i18n: overallStats.notLocalizedPercentage\n },\n total = Object.values(data).reduce((acc, curr) => acc + curr, 0),\n percentageCalc = (v, t) => {\n const val = ((v / t) * 100).toFixed(0);\n return isNaN(val) || !isFinite(val) ? 0 : val;\n },\n i18nPercentage = percentageCalc(\n data.number_i18n + data.percentage_i18n + data.currency_i18n,\n total\n ),\n nonI18nPercentage = percentageCalc(\n data.number_not_i18n +\n data.percentage_not_i18n +\n data.currency_not_i18n,\n total\n ),\n numberTotal = data.number_i18n + data.number_not_i18n,\n currencyTotal = data.currency_i18n + data.currency_not_i18n,\n percentageTotal = data.percentage_i18n + data.percentage_not_i18n,\n numberI18n = percentageCalc(data.number_i18n, numberTotal),\n currencyI18n = percentageCalc(data.currency_i18n, currencyTotal),\n percentageI18n = percentageCalc(\n data.percentage_i18n,\n currencyTotal\n ),\n numberNotI18n = percentageCalc(data.number_not_i18n, numberTotal),\n currencyNotI18n = percentageCalc(\n data.currency_not_i18n,\n currencyTotal\n ),\n percentageNotI18n = percentageCalc(\n data.percentage_not_i18n,\n currencyTotal\n ),\n options = {\n series: [\n {\n name: 'Internationalized',\n data: [numberI18n, currencyI18n, percentageI18n]\n },\n {\n name: 'Not Internationalized',\n data: [numberNotI18n, currencyNotI18n, percentageNotI18n]\n }\n ],\n chart: {\n type: 'bar',\n height: 220,\n width: 500,\n toolbar: {\n show: false\n },\n animations: {\n enabled: true,\n easing: 'easeinout',\n speed: 800,\n animateGradually: {\n enabled: true,\n delay: 150\n },\n dynamicAnimation: {\n enabled: true,\n speed: 350\n }\n }\n },\n dataLabels: {\n enabled: true,\n dropShadow: { enabled: false },\n style: {\n colors: ['#080404b0']\n },\n formatter: (val) => {\n return \`\${val}%\`;\n }\n },\n stroke: {\n show: true,\n width: 1,\n colors: ['#fff']\n },\n tooltip: {\n theme: 'dark',\n shared: true,\n intersect: false,\n x: {\n formatter: (type) => \`\${type} instances:\`\n },\n y: {\n formatter: (v, { seriesIndex, dataPointIndex }) => {\n const getI18nCount = (type) => {\n switch (type) {\n case 'number':\n return data.number_i18n;\n case 'currency':\n return data.currency_i18n;\n case 'percentage':\n return data.percentage_i18n;\n }\n },\n getNonI18nCount = (type) => {\n switch (type) {\n case 'number':\n return data.number_not_i18n;\n case 'currency':\n return data.currency_not_i18n;\n case 'percentage':\n return data.percentage_not_i18n;\n }\n },\n getCount = (type) => {\n return seriesIndex === 0\n ? getI18nCount(type)\n : getNonI18nCount(type);\n };\n\n switch (dataPointIndex) {\n case 0:\n return getCount('number');\n case 1:\n return getCount('currency');\n case 2:\n return getCount('percentage');\n }\n }\n }\n },\n xaxis: {\n categories: types\n },\n yaxis: {\n min: 0,\n max: 100,\n labels: {\n formatter: (v) => \`\${v}%\`\n }\n },\n colors: ['#31E994', '#ff8173'],\n legend: {\n offsetX: -13,\n position: 'right',\n formatter: (seriesName) => {\n if (seriesName === 'Internationalized') {\n return \`\${seriesName} (\${i18nPercentage}%)\`;\n }\n return \`\${seriesName} (\${nonI18nPercentage}%)\`;\n }\n },\n plotOptions: {\n bar: {\n borderRadius: 3,\n columnWidth: '85%'\n }\n }\n };\n\n (numberChart = new ApexCharts(\n document.querySelector('.number-quality .graph'),\n options\n )).render();\n }\n\n function renderDatetimeChart() {\n const overallStats = DataStore.getOverallStats();\n const types = ['Date', 'Time', 'DateTime'],\n data = {\n date_i18n: overallStats.localizedDate,\n time_i18n: overallStats.localizedTime,\n date_time_i18n: overallStats.localizedDateTime,\n date_not_i18n: overallStats.notLocalizedDate,\n time_not_i18n: overallStats.notLocalizedTime,\n date_time_not_i18n: overallStats.notLocalizedDateTime\n },\n total = Object.values(data).reduce((acc, curr) => acc + curr, 0),\n percentageCalc = (v, t) => {\n const val = ((v / t) * 100).toFixed(0);\n return isNaN(val) || !isFinite(val) ? 0 : val;\n },\n i18nPercentage = percentageCalc(\n data.date_i18n + data.time_i18n + data.date_time_i18n,\n total\n ),\n nonI18nPercentage = percentageCalc(\n data.date_not_i18n + data.time_not_i18n + data.date_time_not_i18n,\n total\n ),\n dateTotal = data.date_i18n + data.date_not_i18n,\n timeTotal = data.time_i18n + data.time_not_i18n,\n dateTimeTotal = data.date_time_i18n + data.date_time_not_i18n,\n dateI18n = percentageCalc(data.date_i18n, dateTotal),\n timeI18n = percentageCalc(data.time_i18n, timeTotal),\n dateTimeI18n = percentageCalc(data.date_time_i18n, dateTimeTotal),\n dateNotI18n = percentageCalc(data.date_not_i18n, dateTotal),\n timeNotI18n = percentageCalc(data.time_not_i18n, timeTotal),\n dateTimeNotI18n = percentageCalc(\n data.date_time_not_i18n,\n dateTimeTotal\n ),\n options = {\n series: [\n {\n name: 'Internationalized',\n data: [dateI18n, timeI18n, dateTimeI18n]\n },\n {\n name: 'Not Internationalized',\n data: [dateNotI18n, timeNotI18n, dateTimeNotI18n]\n }\n ],\n chart: {\n type: 'bar',\n height: 220,\n width: 500,\n toolbar: {\n show: false\n },\n animations: {\n enabled: true,\n easing: 'easeinout',\n speed: 800,\n animateGradually: {\n enabled: true,\n delay: 150\n },\n dynamicAnimation: {\n enabled: true,\n speed: 350\n }\n }\n },\n dataLabels: {\n enabled: true,\n dropShadow: { enabled: false },\n style: {\n colors: ['#080404b0']\n },\n formatter: (val) => {\n return \`\${val}%\`;\n }\n },\n stroke: {\n show: true,\n width: 1,\n colors: ['#fff']\n },\n tooltip: {\n theme: 'dark',\n shared: true,\n intersect: false,\n x: {\n formatter: (type) => \`\${type} instances:\`\n },\n y: {\n formatter: (v, { seriesIndex, dataPointIndex }) => {\n const getI18nCount = (type) => {\n switch (type) {\n case 'date':\n return data.date_i18n;\n case 'time':\n return data.time_i18n;\n case 'date_time':\n return data.date_time_i18n;\n }\n },\n getNonI18nCount = (type) => {\n switch (type) {\n case 'date':\n return data.date_not_i18n;\n case 'time':\n return data.time_not_i18n;\n case 'date_time':\n return data.date_time_not_i18n;\n }\n },\n getCount = (type) => {\n return seriesIndex === 0\n ? getI18nCount(type)\n : getNonI18nCount(type);\n };\n\n switch (dataPointIndex) {\n case 0:\n return getCount('date');\n case 1:\n return getCount('time');\n case 2:\n return getCount('date_time');\n }\n }\n }\n },\n xaxis: {\n categories: types\n },\n yaxis: {\n min: 0,\n max: 100,\n labels: {\n formatter: (v) => \`\${v}%\`\n }\n },\n colors: ['#31E994', '#ff8173'],\n legend: {\n offsetX: 4,\n position: 'right',\n formatter: (seriesName) => {\n if (seriesName === 'Internationalized') {\n return \`\${seriesName} (\${i18nPercentage}%)\`;\n }\n return \`\${seriesName} (\${nonI18nPercentage}%)\`;\n }\n },\n plotOptions: {\n bar: {\n borderRadius: 3,\n columnWidth: '85%'\n }\n }\n };\n\n (dateTimeChart = new ApexCharts(\n document.querySelector('.datetime-quality .graph'),\n options\n )).render();\n }\n });\n })();\n // insights content\n (() => {\n if (!DataStore.ranSuccessfully()) {\n document.getElementById('overview').innerHTML =\n 'Unable to prepare zQA automation report for the project.';\n return;\n }\n\n document.addEventListener('DOMContentLoaded', function () {\n renderCards();\n\n // helper methods to generate cards and its sections\n function createStatSection(locale, data) {\n const isDefaultLocale = DataStore.isDefaultLocale(locale);\n const holder = document.createElement('div');\n const table = document.createElement('table');\n const tbody = document.createElement('tbody');\n const name = document.createElement('div');\n const tableData = {\n 'Internationlized Strings':\n data.localizedStrings +\n data.untranslatedStrings +\n data.partialStrings,\n 'Not Internationlized Strings': data.notLocalizedStrings,\n 'Internationlized Numbers': data.localizedNumber,\n 'Not Internationlized Numbers': data.notLocalizedNumber,\n 'Internationlized Currency': data.localizedCurrency,\n 'Not Internationlized Currency': data.notLocalizedCurrency,\n 'Internationlized Percentage': data.localizedPercentage,\n 'Not Internationlized Percentage': data.notLocalizedPercentage,\n 'Internationlized Date': data.localizedDate,\n 'Not Internationlized Date': data.notLocalizedDate,\n 'Internationlized Time': data.localizedTime,\n 'Not Internationlized Time': data.notLocalizedTime,\n 'Internationlized DateTime': data.localizedDate,\n 'Not Internationlized DateTime': data.notLocalizedDateTime,\n 'Encoding Issue Strings': data.encoding,\n 'DNT Strings': data.dnt,\n 'Ignored Strings': data.ignored,\n 'Untranslated Strings': data.untranslatedStrings,\n 'Auto Ignored Strings': data.autoIgnored,\n 'User Input Strings': data.userInput,\n 'Total Reviewed': data.reviewed\n };\n const addRow = (name, value) => {\n const row = document.createElement('tr');\n\n const col1 = document.createElement('td');\n col1.classList.add('name');\n col1.textContent = name;\n\n const col2 = document.createElement('td');\n col2.classList.add('value');\n col2.textContent = value;\n\n row.appendChild(col1);\n row.appendChild(col2);\n return row;\n };\n\n for (const rowData of Object.entries(tableData)) {\n if (!isDefaultLocale || rowData[0] !== 'Untranslated Strings') {\n tbody.appendChild(addRow(rowData[0], rowData[1]));\n }\n }\n\n holder.classList.add('stat');\n name.classList.add('name');\n name.textContent = 'Summary';\n holder.append(name);\n\n table.appendChild(tbody);\n holder.appendChild(table);\n return holder;\n }\n\n function createStatusBarSection(locale, data) {\n const holder = document.createElement('div');\n holder.classList.add('status-bar');\n\n const generateBarEl = (name, total, current) => {\n const getColorClass = (value) => {\n if (value <= 25) {\n return 'red';\n } else if (value <= 50) {\n return 'yellow';\n } else if (value <= 75) {\n return 'blue';\n } else if (value <= 100) {\n return 'green';\n }\n };\n current = (current / total) * 100;\n current = isNaN(current) || !isFinite(current) ? 0 : current;\n const holder = document.createElement('div');\n holder.classList.add('bar-container');\n\n const nameHolder = document.createElement('div');\n nameHolder.classList.add('name');\n nameHolder.textContent = name;\n\n const barHolder = document.createElement('div');\n barHolder.classList.add('bar-holder');\n\n const bar = document.createElement('div');\n bar.classList.add('bar');\n bar.classList.add(\`--\${getColorClass(current)}\`);\n bar.style.width = \`\${current}%\`;\n bar.textContent = \`\${current.toFixed(0)}%\`;\n\n barHolder.appendChild(bar);\n holder.appendChild(nameHolder);\n holder.appendChild(barHolder);\n\n return holder;\n };\n\n const isDefaultLocale = DataStore.isDefaultLocale(locale),\n totalI18nCount = isDefaultLocale\n ? 100\n : data.localizedStrings +\n data.untranslatedStrings +\n data.partialStrings +\n data.notLocalizedStrings,\n i18nStrings = isDefaultLocale\n ? 100\n : data.localizedStrings +\n data.untranslatedStrings +\n data.partialStrings,\n totalLocCount = isDefaultLocale\n ? 100\n : totalI18nCount -\n data.untranslatedStrings -\n data.notLocalizedStrings,\n totalNumberCount = isDefaultLocale\n ? 100\n : data.localizedNumber +\n data.localizedCurrency +\n data.localizedPercentage +\n data.notLocalizedPercentage +\n data.notLocalizedCurrency +\n data.notLocalizedNumber,\n i18nNumbers = isDefaultLocale\n ? 100\n : totalNumberCount -\n data.notLocalizedPercentage -\n data.notLocalizedCurrency -\n data.notLocalizedNumber,\n totalI18nDateTimeCount = isDefaultLocale\n ? 100\n : data.localizedDate +\n data.localizedDateTime +\n data.localizedTime +\n data.notLocalizedDate +\n data.notLocalizedDateTime +\n data.notLocalizedTime,\n i18nDateTime = isDefaultLocale\n ? 100\n : totalI18nDateTimeCount -\n data.notLocalizedDate -\n data.notLocalizedDateTime -\n data.notLocalizedTime;\n\n holder.appendChild(\n generateBarEl('String I18n level', totalI18nCount, i18nStrings)\n );\n\n holder.appendChild(\n generateBarEl('String L10n level', totalI18nCount, totalLocCount)\n );\n\n holder.appendChild(\n generateBarEl('Number I18n level', totalNumberCount, i18nNumbers)\n );\n\n holder.appendChild(\n generateBarEl(\n 'DateTime I18n level',\n totalI18nDateTimeCount,\n i18nDateTime\n )\n );\n return holder;\n }\n\n function generateCardContents(locale, data) {\n const cardContent = document.createElement('div');\n cardContent.classList.add('card-content');\n\n cardContent.appendChild(createStatusBarSection(locale, data));\n cardContent.appendChild(createStatSection(locale, data));\n return cardContent;\n }\n\n function createCardEl(locale, data) {\n const card = document.createElement('div');\n const title = document.createElement('div');\n card.classList.add('card');\n card.dataset.locale = locale;\n\n if(window.reducedZoom) {\n card.classList.add('--reduced-zoom');\n }\n\n title.classList.add('title');\n title.textContent = \`\${locale} details\`;\n\n // fire menu selection event on clicking the card\n card.addEventListener('click', () => {\n const previousSelectedSubMenu = document.querySelector(\n '.sub-menu-item.selected'\n );\n if (previousSelectedSubMenu) {\n window.previousSelectedLocale =\n previousSelectedSubMenu.dataset.locale;\n }\n\n document\n .querySelector(\`.sub-menu-item[data-locale="\${locale}"]\`)\n .click();\n });\n\n card.appendChild(title);\n card.appendChild(generateCardContents(locale, data));\n return card;\n }\n\n function renderCards() {\n // read from global variable appData;\n const localeInfo = DataStore.getLocalesData();\n\n if (Object.keys(localeInfo).length) {\n const cardHolder = document.querySelector(\n '#insights .cards .holder'\n );\n for (const locale in localeInfo) {\n const cardEl = createCardEl(\n locale,\n DataStore.getStatByLocale(locale)\n );\n cardHolder.appendChild(cardEl);\n }\n }\n }\n });\n })();\n // locale grid\n (() => {\n if (!DataStore.ranSuccessfully()) {\n return;\n }\n\n document.addEventListener('DOMContentLoaded', function () {\n let table;\n document.querySelectorAll('.sub-menu-item').forEach((menu) => {\n menu.addEventListener('click', (e) => {\n render(e.currentTarget.dataset.locale);\n });\n });\n\n const updateTitle = (locale) => {\n document.querySelector(\n '#locale .title'\n ).textContent = \`\${locale} I18n Coverage Details\`;\n };\n\n const buildGrid = (locale) => {\n const data = DataStore.getDataByLocale(locale) || {};\n $.fn.dataTable.ext.errMode = 'none';\n const dataSet = [];\n Object.entries(data).map((entry) =>\n entry[1].forEach(\n (v) =>\n (v.type !== 'REVIEWED' || DataStore.isSanityRun()) &&\n dataSet.push([entry[0], v.type, v.description, v.imagePath])\n )\n );\n table = new DataTable('#locale .coverage-info table', {\n columns: [\n { title: 'String' },\n { title: 'Type' },\n { title: 'Page' },\n { title: 'Screenshot' }\n ],\n columnDefs: [\n {\n width: '44%',\n targets: 0\n },\n {\n width: '18%',\n targets: 1\n },\n {\n width: '18%',\n targets: 2\n },\n {\n width: '18%',\n targets: 3,\n orderable: false,\n searchable: false,\n data: null,\n render: function (data) {\n return \`<a href="#" class="view-screenshot-btn" onclick="openImageViewer('\${data[3]}')"><img title="View screenshot for '\${data[2]}'" class="view-screenshot-image"></img></a>\`;\n },\n className: 'dt-head-center dt-body-center'\n }\n ],\n data: dataSet,\n initComplete: function () {\n this.api()\n .columns()\n .every(function () {\n const column = this;\n\n if (column[0][0] === 3) {\n return;\n }\n\n const select = $(\n '<select class="filter dt-input"><option value="">Filter By</option></select>'\n )\n .appendTo($(column.header()).before())\n .on('change', function () {\n const val = $.fn.dataTable.util.escapeRegex(\n $(this).val()\n );\n\n column\n .search(val ? '^' + val + '$' : '', true, false)\n .draw();\n })\n .on('click', function (e) {\n e.stopPropagation();\n e.stopImmediatePropagation();\n });\n\n column\n .data()\n .unique()\n .sort()\n .each(function (d, j) {\n select.append(\n '<option value="' + d + '">' + d + '</option>'\n );\n });\n });\n },\n sScrollY:\n document\n .querySelector('#locale .coverage-info')\n .getBoundingClientRect().height - 142,\n pageLength: 25,\n lengthMenu: [10, 25, 50, 100]\n });\n };\n\n const render = (locale) => {\n if (table) {\n table.destroy();\n }\n updateTitle(locale);\n buildGrid(locale);\n };\n });\n })();\n\n // log content\n (() => {\n document.addEventListener('DOMContentLoaded', function () {\n const pre = document.querySelector('#log .log-content pre');\n pre.textContent = 'Loading...';\n document\n .querySelector('li[data-page="log"]')\n ?.addEventListener('click', (e) => {\n pre.textContent = window.logData || 'No log data found!';\n });\n });\n })();`,n=[],a=Ce(rt.getReportPath(),"logs","log"),r=!0===mt.getOptions()?.sanityCapture;let i="";if(Ee(rt.getReportPath()).forEach((t=>(t!==e.defaultLocale||r)&&Le(Ce(rt.getReportPath(),t,be))&&n.push(Ce(t,be).replace(/\\/g,"/")))),Le(a)){const t=[e.appName,...mt.getL10nReportsPath().split(/[\\/]+/g)];t.push(rt.getReportTimeStamp()),i=Se(a).replace(new RegExp(rt.getReportPath().replace(/\\/g,"\\\\"),"g"),Ce(...t)).replace(/\\/g,"\\\\").replace(/`/g,"\\`")}return function({appName:e,reportTime:t,script:n,style:a,body:r,dataFilePaths:i=[],logData:s}){return`<!DOCTYPE html>\n<html lang="en">\n <head>\n <meta charset="UTF-8" />\n <meta name="charset" content="charset='UTF-8'" />\n <meta name="viewport" content="width=device-width, initial-scale=1.0" />\n <meta name="company" content="Zeesoft" />\n <meta name="author" content="Jitendra Maheshwari" />\n <meta name="email" content="jm@zeesoft.com" />\n <meta\n name="description"\n content="I18n verification report"\n />\n <title>${e} - I18n Verification Report | ${t}</title>\n \x3c!-- 3rd party dependencies --\x3e\n <link\n rel="stylesheet"\n href="https://cdn.datatables.net/2.0.3/css/dataTables.dataTables.min.css"\n />\n ${i.map((e=>`<script\n src="${e}"\n type="text/javascript">\n <\/script>`)).join("")}\n ${s?`<script type="text/javascript" async/>window.logData = \`${s}\`;<\/script>`:""}\n <script\n src="https://code.jquery.com/jquery-3.7.1.slim.min.js"\n integrity="sha256-kmHvs0B+OpCW5GVHUNjv9rOmY0IvSIRcf7zGUDTDQM8="\n crossorigin="anonymous"\n defer\n ><\/script>\n <script src="https://cdn.jsdelivr.net/npm/apexcharts" defer><\/script>\n <script\n src="https://cdn.datatables.net/2.0.3/js/dataTables.min.js"\n defer\n ><\/script>\n <style>\n ${a}\n </style>\n </head>\n <body>\n ${r}\n </body>\n <script type="text/javascript" defer>\n ${n}\n <\/script>\n</html>\n`}({appName:e.appName,reportTime:e.reportTime,body:'<header><div class="logo">zQA Report</div></header>\n <main>\n <div class="sidebar">\n <ul class="menu" id="menu">\n <li class="menu-item" data-page="overview">\n <a href="#">Overview</a>\n </li>\n <li class="menu-item" data-page="log">\n <a href="#">View Log</a>\n </li>\n <li class="menu-item has-submenu" data-page="insights">\n <a href="#" data-page="insights">Insights</a>\n <ul class="submenu"></ul>\n </li>\n </ul>\n <div class="footer"></div>\n </div>\n <div class="content-wrapper">\n <div id="overview" class="content">\n <div class="overall-quality card">\n <span class="title">Overall I18n Coverage</span>\n <div class="section">\n <div class="block">\n <article>\n <p class="desc">\n zI18n-Verify report provides a comprehensive information\n about the I18n and L10n quailty of your application.\n </p>\n <ul class="items">\n <li>\n <h4>Reviewed:</h4>\n <p class="detail">\n Total strings which are captured and processed by\n zI18n-Verify.\n </p>\n </li>\n <li>\n <h4>Internationlized:</h4>\n <p class="detail">\n Different types of value like string, number, date-time\n which are properly Internationalized.\n </p>\n </li>\n <li>\n <h4>Not Internationalized:</h4>\n <p class="detail">\n Values which are not Internationalized. Also includes\n Partially Localized strings and Encoding Issues.\n </p>\n </li>\n <li>\n <h4>Skipped:</h4>\n <p class="detail">\n Values which are skipped from processing because they\n are listed in DNT / Ignored lists or contains Auto\n Ignored pattern / User input pattern.\n </p>\n </li>\n </ul>\n </article>\n </div>\n <div class="block">\n <div class="graph"></div>\n </div>\n </div>\n </div>\n <div class="string-quality card">\n <span class="title">String Coverage</span>\n <div class="graph"></div>\n </div>\n <div class="skipped-items card">\n <span class="title">Skipped Items</span>\n <div class="graph"></div>\n </div>\n <div class="number-quality card">\n <span class="title">Number Coverage</span>\n <div class="graph"></div>\n </div>\n <div class="datetime-quality card">\n <span class="title">DateTime Coverage</span>\n <div class="graph"></div>\n </div>\n </div>\n <div id="log" class="content">\n <span class="title">Runtime log</span>\n <div class="log-content"><pre></pre></div>\n </div>\n <div id="insights" class="content">\n <div class="cards">\n <span class="title">Locale Quality</span>\n <div class="holder"></div>\n </div>\n </div>\n <div id="locale" class="content">\n <span class="title">Locale Quality</span>\n <div class="coverage-info">\n <table class="row-border hover order-column stripe"></table>\n </div>\n <div id="imageViewer" class="image-viewer">\n <span class="close-button" onclick="closeImageViewer()"\n >&times;</span\n >\n <div class="image-container">\n <img id="imageView" src="" alt="Image" />\n </div>\n </div>\n </div>\n </div>\n </main>',script:t,style:"html {\n width: 100vw;\n height: 100vh;\n }\n\n * {\n user-select: none;\n }\n\n body {\n width: 100%;\n height: 100%;\n margin: 0;\n display: flex;\n flex-direction: column;\n font-family: Arial, sans-serif;\n font-family: 'Helvetica Neue', Arial, sans-serif;\n -webkit-font-smoothing: antialiased; /* Webkit-based browsers */\n -moz-osx-font-smoothing: grayscale; /* Firefox on OS X */\n font-smooth: always; /* Non-standard, some browsers */\n }\n\n header {\n background-color: #333;\n height: 8%;\n }\n\n main {\n display: flex;\n direction: column;\n width: 100%;\n height: 92%\n }\n\n .sidebar {\n width: 16%;\n height: 100%;\n background-color: #333;\n color: #fff;\n padding: 20px;\n box-sizing: border-box;\n float: left;\n }\n\n .logo {\n letter-spacing: 0.1rem;\n color: #14cf96;\n font-weight: bold;\n padding-top: 1.4%;\n padding-left: 2.1%;\n font-size: 1.6rem;\n }\n\n .menu {\n list-style-type: none;\n padding: 0;\n margin: 0;\n }\n\n .menu-item {\n margin-bottom: 10px;\n }\n\n .menu-item a {\n color: #fff;\n text-decoration: none;\n display: block;\n padding: 10px;\n border-radius: 5px;\n font-size: 1.05rem;\n }\n\n .menu-item a:hover {\n background-color: #555;\n }\n\n .submenu {\n display: none;\n list-style-type: none;\n padding-left: 20px;\n }\n\n .menu-item.has-submenu > a::after {\n content: '⯆';\n float: right;\n margin-left: 5px;\n }\n\n .menu-item.has-submenu.selected > a::after {\n content: '⯅';\n float: right;\n margin-left: 5px;\n }\n\n .menu-item.selected > a {\n background-color: #555;\n }\n\n .submenu .sub-menu-item {\n margin: 3px auto;\n }\n\n .submenu .sub-menu-item a:hover {\n background-color: #777;\n }\n\n .submenu .sub-menu-item.selected a {\n background-color: #555 !important;\n }\n\n .submenu.active {\n display: block !important;\n }\n\n .view-screenshot-image {\n width: 100px;\n height: 30px;\n content: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBVcGxvYWRlZCB0bzogU1ZHIFJlcG8sIHd3dy5zdmdyZXBvLmNvbSwgR2VuZXJhdG9yOiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4NCjxzdmcgZmlsbD0iIzAwMDAwMCIgaGVpZ2h0PSI4MDBweCIgd2lkdGg9IjgwMHB4IiB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIA0KCSB2aWV3Qm94PSIwIDAgNDkwIDQ5MCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8cGF0aCBkPSJNMjQ1LjIwNCwxMDEuMjY3QzY3LjE3MSwxMDEuMjY3LDAsMjQ1LDAsMjQ1czY2Ljc2MywxNDMuNzMzLDI0NC43OTYsMTQzLjczM0M0MjIuODI5LDM4OC43MzMsNDkwLDI0NSw0OTAsMjQ1DQoJCVM0MjMuMjM4LDEwMS4yNjcsMjQ1LjIwNCwxMDEuMjY3eiBNMjQ0Ljc5NiwzNzMuNDIxYy0xNDYuMzkzLDAtMjEyLjM2Ny0xMDEuMDUzLTIyNy41MDYtMTI4LjMzMw0KCQljMTUuMjQ5LTI2Ljc5Niw4Mi43MzMtMTI4LjUwOCwyMjcuOTE0LTEyOC41MDhjMTQ2LjUxNCwwLDIxMi40NzUsMTAxLjIyLDIyNy41NDMsMTI4LjQNCgkJQzQ1Ny41NzgsMjcyLjIwMywzOTEuMzEzLDM3My40MjEsMjQ0Ljc5NiwzNzMuNDIxeiIvPg0KCTxwYXRoIGQ9Ik0yNDUuMDAzLDE0Ni4xMjRjLTU0LjUyMSwwLTk4Ljg4MSw0NC4zNTItOTguODgxLDk4Ljg3M2MwLDU0LjUyMSw0NC4zNiw5OC44ODEsOTguODgxLDk4Ljg4MXM5OC44NzMtNDQuMzYsOTguODczLTk4Ljg4MQ0KCQlDMzQzLjg3NiwxOTAuNDc3LDI5OS41MjQsMTQ2LjEyNCwyNDUuMDAzLDE0Ni4xMjR6IE0yNDUuMDAzLDMyOC41NjZjLTQ2LjA4LDAtODMuNTY4LTM3LjQ4OS04My41NjgtODMuNTY4DQoJCWMwLTQ2LjA3MiwzNy40ODktODMuNTYxLDgzLjU2OC04My41NjFjNDYuMDcyLDAsODMuNTYxLDM3LjQ4OSw4My41NjEsODMuNTYxQzMyOC41NjQsMjkxLjA3NywyOTEuMDc1LDMyOC41NjYsMjQ1LjAwMywzMjguNTY2eiIvPg0KCTxwYXRoIGQ9Ik0yNDUuMDAzLDE3NS41ODNjLTM4LjI4MSwwLTY5LjQyMiwzMS4xNDEtNjkuNDIyLDY5LjQxNWMwLDM4LjI3NCwzMS4xNDEsNjkuNDE1LDY5LjQyMiw2OS40MTUNCgkJYzM4LjI3NCwwLDY5LjQxNS0zMS4xNDEsNjkuNDE1LTY5LjQxNUMzMTQuNDE3LDIwNi43MjQsMjgzLjI3NywxNzUuNTgzLDI0NS4wMDMsMTc1LjU4M3ogTTI0NS4wMDMsMjk5LjENCgkJYy0yOS44MzMsMC01NC4xMS0yNC4yNy01NC4xMS01NC4xMDJjMC0yOS44MzIsMjQuMjc3LTU0LjEwMiw1NC4xMS01NC4xMDJzNTQuMTAyLDI0LjI3LDU0LjEwMiw1NC4xMDINCgkJQzI5OS4xMDUsMjc0LjgzLDI3NC44MzUsMjk5LjEsMjQ1LjAwMywyOTkuMXoiLz4NCgk8cGF0aCBkPSJNMjQ1LjAwMywyMDYuNjc5Yy0yMS4xMywwLTM4LjMyNiwxNy4xODktMzguMzI2LDM4LjMxOWMwLDIxLjEyOSwxNy4xOTcsMzguMzI2LDM4LjMyNiwzOC4zMjZzMzguMzE5LTE3LjE5NywzOC4zMTktMzguMzI2DQoJCUMyODMuMzIxLDIyMy44NjgsMjY2LjEzMiwyMDYuNjc5LDI0NS4wMDMsMjA2LjY3OXogTTI0NS4wMDMsMjY4LjAxMWMtMTIuNjg4LDAtMjMuMDE0LTEwLjMyNi0yMy4wMTQtMjMuMDE0DQoJCWMwLTEyLjY4OCwxMC4zMjUtMjMuMDA2LDIzLjAxNC0yMy4wMDZjMTIuNjg4LDAsMjMuMDA2LDEwLjMxOCwyMy4wMDYsMjMuMDA2QzI2OC4wMDksMjU3LjY4NiwyNTcuNjkxLDI2OC4wMTEsMjQ1LjAwMywyNjguMDExeiIvPg0KPC9nPg0KPC9zdmc+);\n }\n\n .content-wrapper {\n padding: 1rem;\n float: left;\n width: 84%;\n background-color: #f4f4f4;\n overflow: hidden;\n overflow-y: auto;\n }\n\n .content {\n display: none;\n }\n\n .content .title {\n font-size: 1rem;\n color: #080404e2;\n font-weight: 600;\n }\n\n .content .title::after {\n content: ':';\n }\n\n .content.active {\n display: flex !important;\n flex-direction: column;\n gap: 0.9rem;\n flex-wrap: wrap;\n transition: all 2s ease-in-out;\n }\n\n .sidebar .footer {\n bottom: 1.5%;\n position: absolute;\n font-size: 0.8rem;\n color: #14cf96;\n font-family: system-ui;\n }\n\n #overview {\n flex-direction: row;\n justify-content: space-between;\n }\n\n #overview .card {\n display: flex;\n flex-direction: column;\n width: 25rem;\n height: 12.5rem;\n border: 1px solid #ddd;\n box-shadow: 0 22px 35px -16px rgba(0, 0, 0, 0.3);\n border-radius: 5px;\n background: white;\n padding: 1rem;\n }\n\n #overview .overall-quality {\n height: 20rem;\n flex-basis: 100%;\n line-height: 14px;\n }\n\n #overview .overall-quality .section {\n display: flex;\n flex-direction: row;\n }\n\n #overview .overall-quality .section .block {\n width: 50%;\n }\n\n #overview .overall-quality .section .block article {\n padding: 5px;\n }\n\n #overview .overall-quality .section .block article p.desc {\n font-size: 0.9em;\n }\n\n #overview .overall-quality .section .block article .items li {\n font-size: 0.87em;\n }\n\n #overview .overall-quality .section .block article .items li .detail {\n margin-top: -10px;\n }\n\n #overview .overall-quality .section .block .graph {\n margin-top: 1.5em;\n }\n\n #overview .string-quality,\n #overview .number-quality,\n #overview .datetime-quality,\n #overview .skipped-items {\n flex-basis: 45%;\n }\n\n #overview .string-quality .graph,\n #overview .number-quality .graph,\n #overview .datetime-quality .graph,\n #overview .skipped-items .graph {\n align-self: center;\n }\n\n #overview .string-quality .graph {\n margin-left: 4rem;\n }\n\n #overview .number-quality.card,\n #overview .datetime-quality.card {\n height: 13rem;\n }\n\n #overview .number-quality .graph,\n #overview .datetime-quality .graph {\n margin-top: -0.9rem;\n margin-left: 4.5rem;\n }\n\n #insights .cards {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n }\n\n #insights .cards .holder {\n display: flex;\n flex-direction: row;\n gap: 1.5rem;\n flex-wrap: wrap;\n }\n\n #insights .cards .card {\n display: flex;\n flex-direction: column;\n width: 20rem;\n min-height: 10rem;\n border: 1px solid #ddd;\n box-shadow: 0 22px 35px -16px rgba(0, 0, 0, 0.3);\n border-radius: 5px;\n background: white;\n }\n\n #insights .cards .card:hover {\n transform: scale(1.015);\n box-shadow: 0 22px 35px -16px #07ff7d33;\n cursor: pointer;\n transition: all 0.1s ease-in-out;\n }\n\n #insights .cards .card .title {\n height: 2.5rem;\n font-size: 1rem;\n padding-top: 1rem;\n font-weight: 500;\n width: calc(100% - 1rem);\n background: #0c5ad9d6;\n border-top-left-radius: 5px;\n border-top-right-radius: 5px;\n padding-left: 1rem;\n color: white;\n }\n\n #insights .cards .card .title::after {\n content: '';\n }\n\n #insights .cards .card .card-content {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n padding: 1rem;\n }\n\n #insights .cards .card .status-bar {\n display: flex;\n flex-direction: column;\n gap: 0.8rem;\n }\n\n #insights .cards .card .status-bar .bar-container .name {\n font-size: 0.78rem;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n #insights .cards .card .status-bar .bar-container .name::after {\n content: ':';\n }\n\n #insights .cards .card .status-bar .bar-container .bar-holder {\n width: 100%;\n height: 10px;\n border: 1px solid #00000038;\n border-radius: 2px;\n }\n\n #insights .cards .card .status-bar .bar-container .bar-holder .bar {\n height: 100%;\n font-size: 0.63rem;\n text-align: right;\n color: rgb(0, 0, 0);\n }\n\n .bar.--green {\n background-color: #1dedaf;\n }\n\n .bar.--red {\n background-color: #fe3e3e;\n }\n\n .bar.--yellow {\n background-color: #faef1f;\n }\n\n .bar.--blue {\n background-color: #77c2ff;\n }\n\n #insights .cards .card .stat {\n display: flex;\n flex-direction: column;\n gap: 0.3rem;\n border: 0.5px solid #00000012;\n border-radius: 6px;\n }\n\n #insights .cards .card .stat table td {\n font-size: 0.78rem;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n #insights .cards .card .stat table td.name {\n width: 70%;\n }\n\n #insights .cards .card .stat table td.value::before {\n content: ': ';\n }\n\n #locale {\n background: white;\n padding: 12px;\n border-radius: 5px;\n padding-top: 20px;\n }\n\n #locale .title {\n content: ':';\n }\n\n #locale .coverage-info {\n margin-top: 1rem;\n width: 100%;\n height: 80vh;\n padding-right: 1rem;\n padding-left: 0.1rem;\n }\n\n #locale table thead th select.filter {\n margin-left: 1rem;\n max-width: 8rem;\n text-overflow: ellipsis;\n }\n\n #locale .image-viewer {\n display: none;\n position: fixed;\n z-index: 9999;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.8);\n text-align: center;\n }\n\n #locale .image-container {\n position: relative;\n top: 50%;\n transform: translateY(-50%);\n display: inline-block;\n }\n\n #locale .image-viewer img {\n max-width: 90%;\n max-height: 90%;\n }\n\n #locale .close-button {\n position: absolute;\n top: 0.5rem;\n right: 1rem;\n color: #ffffffbf;\n font-size: 3.1rem;\n cursor: pointer;\n }\n\n #locale .close-button:hover {\n color: white;\n }\n\n #locale table tbody td {\n font-size: 0.9em;\n }\n\n #locale table td .view-screenshot-btn {\n color: blue;\n }\n\n .project-info {\n font-size: 1rem;\n color: #90a3a9;\n }\n\n .project-info .time {\n float: right;\n position: relative;\n top: 1rem;\n margin-right: 0.5%;\n }\n\n @media (max-width: 768px) {\n .sidebar {\n width: 16rem;\n padding: 10px;\n }\n }\n\n .--hidden {\n display: none;\n visibility: hidden;\n }\n\n #log .log-content {\n width: 98%;\n height: 82vh;\n background: white;\n border-radius: 3px;\n overflow: hidden;\n padding: 1em;\n }\n\n #log .log-content pre {\n height: 100%;\n white-space: pre-line;\n word-break: break-all;\n padding: 0;\n margin: 0;\n width: 100%;\n overflow: hidden;\n overflow-y: auto;\n }\n\n .--reduced-zoom {\n zoom: 0.9123;\n }\n \n .--hide-overflow {\n overflow: hidden;\n }",dataFilePaths:n,logData:i})}write(e,t,n){Ne(Ce(e,`${t}.html`),n,"utf-8")}}const Pe=(e=!0)=>e?"(?:\\s|\\t|(?:&nbsp;))":/(?:\s|\t|(?:&nbsp;))/g;class _e{#a={};#r;constructor(e){this.#r=e,this.#i(),this.buildConfig(),this.#s()}#i(){this.addToConfig("supportedLocales",mt.getOptions()?.supportedLocales,[]),this.addToConfig("defaultLocale",mt.getDefaultLocale()),this.addToConfig("defaultLanguage",mt.getDefaultLocale()?.split(/[-_ ]/g)[0]),this.addToConfig("language",mt.getLocale()?.split(/[-_ ]/g)[0]),this.addToConfig("locale",mt.getLocale()),this.addToConfig("qaLocale",mt.getQALocale())}buildConfig(){throw new Error(`{{${this.#r}}} buildConfig should be implemented by child class`)}#s(){g.load(p.entireSupplemental()),g.load(p.entireMainFor(this.#o(this.#a.defaultLocale),this.#o(this.#a.locale)))}#o(e){if(this.isQaLocale())return"en";e=e.replace(/[-_ ]/g,"-");const t=p.availableLocales;let n;if(t.find((t=>t===e)))n=e;else{const a=e.split("-")[0];n=t.find((e=>e===a))?a:e}return n}validate(e){throw new Error(`{{${this.#r}}} validate should be implemented by child class`)}isInternationalized(e){throw new Error(`{{${this.#r}}} isInternationalized should be implemented by child class`)}setConfig(e){this.#a=e}addToConfig(e,t,n){this.#a[e]=t??n}getConfig(){return this.#a}isSupportedLocale(){return this.#a.supportedLocales.includes(this.currentLocale())}isQaLocale(){return this.currentLocale()===this.#a?.qaLocale}isDefaultLocale(){return this.currentLocale()===this.defaultLocale()}defaultLocale(){return this.#a?.defaultLocale}defaultLanguage(){return this.#a?.defaultLanguage}currentLocale(){return this.#a?.locale}currentLanguage(){return this.#a.language}getGlobalize(e){return g(this.#o(e))}}class Oe extends _e{constructor(){super("currency")}validate(e){return this.#l(e)||this.isInternationalized(e)}isInternationalized(e){return this.#c(this.currentLocale(),e)}buildConfig(){}#c(e,t){const n=this.#d(e),a=this.#u(e,n);if(!this.#g(n,a,t))return!1;const r=this.#p(n,a,t);return!isNaN(this.getGlobalize(e).numberParser()(r))}#g(e,t,n){return new RegExp(`^(?:-)?(?:${e}|\\${t})(?:${Pe()})?(?:-)?[0-9,. ]+$`,"gi").test(n)||new RegExp(`^(?:[- ]?)[0-9,. ]+(?:${Pe()})?(?:${e}|\\${t})$`,"gi").test(n)}#p(e,t,n){return n.replace(new RegExp(`^(?:-)(?:${Pe()})?`,"gi"),"").replace(new RegExp(`^(?:${Pe()})?(?:${e}|\\${t})`,"gi"),"").replace(new RegExp(`^(?:-)(?:${Pe()})?`,"gi"),"").replace(new RegExp(`(?:${Pe()})?(?:${e}|\\${t})$`,"gi"),"").trim()}#h(e){return(this.getGlobalize(e).cldr.supplemental(["likelySubtags",e])||e).split(/[-_ ]/).pop()}#d(e){const t=this.#h(e),n=this.getGlobalize(e).cldr.supplemental("currencyData").region[t];if(n){const e=n.find((e=>{const t=Object.values(e)[0];return!t._tender&&(!t._to||new Date(t._to)>=new Date)}));return e?Object.keys(e)[0]:"USD"}return"USD"}#u(e,t){const n=this.getGlobalize(e).cldr.main(`numbers/currencies/${t}`);return n?.symbol||"$"}#l(e){return this.#c(this.defaultLocale(),e)}}const $e=(e,t)=>{t=String(t);const n=(e=>{let[t="en",n="us"]=e.split(/[-_ ]/g);switch(n=String(n).toLowerCase(),t){case"en":return"gb"===n?h.GB:h;case"de":return T;case"es":return L;case"fr":return D;case"pt":return b;case"ja":return w;case"zh":return["hans","cn","sg","hans-cn"].includes(n)?v.hans:["hant","tw","hk","mo","hant-tw"].includes(n)?v.hant:v;case"ru":return y;case"nl":return f;case"uk":return m;default:return h}})(e).parse(String(t).trim());return n.forEach((e=>{t=t.replace(e.text,"")})),0===t.replace(/[^\p{L}\p{N}]+/gu,"").trim().length},Ae=e=>{try{return e=e.replace("_","-"),Intl.DateTimeFormat.supportedLocalesOf(e)[0]}catch(t){return Logger.warn(`${e} is unsupported by Intl`),!1}},Re=(e,t,n)=>{if(!1!==(e=Ae(e))){if(I.fromFormat(n,t,{locale:Ae(e)}).isValid)return!0}return!1};class je extends _e{constructor(){super("date")}validate(e){return this.#m(e)||this.isInternationalized(e)}isInternationalized(e){return this.#f(this.isQaLocale()?this.defaultLocale():this.currentLocale(),e)}buildConfig(){}#f(e,t){return this.#y(e,t)||this.#v(e,t)||this.#w(e,t)}#m(e){return this.#f(this.defaultLocale(),e)}#y(e,t){const n=["short","medium","long","full"];for(let a of n){if(this.getGlobalize(e).dateParser({date:a})(t))return!0}return!1}#v(e,t){const n=[DateTime.DATE_SHORT,DateTime.DATE_MED,DateTime.DATE_FULL,DateTime.DATE_HUGE,DateTime.DATE_MED_WITH_WEEKDAY,"D","DD","DDD","DDDD"];for(let a of n){if(Re(e,a,t))return!0}return!1}#w(e,t){return $e(this.isQaLocale()?this.defaultLocale():e,t)}}class ke extends _e{constructor(){super("dateTime")}validate(e){return this.#b(e)||this.isInternationalized(e)}isInternationalized(e){return this.#D(this.isQaLocale()?this.defaultLocale():this.currentLocale(),e)}buildConfig(){}#D(e,t){return this.#y(e,t)||this.#v(e,t)||this.#w(e,t)}#b(e){return this.#D(this.defaultLocale(),e)}#y(e,t){const n=["short","medium","long","full"];for(let a of n){if(this.getGlobalize(e).dateParser({datetime:a})(t))return!0}return!1}#v(e,t){const n=[DateTime.DATETIME_SHORT,DateTime.DATETIME_SHORT_WITH_SECONDS,DateTime.DATETIME_MED,DateTime.DATETIME_MED_WITH_SECONDS,DateTime.DATETIME_MED_WITH_WEEKDAY,DateTime.DATETIME_FULL,DateTime.DATETIME_FULL_WITH_SECONDS,DateTime.DATETIME_HUGE,DateTime.DATETIME_HUGE_WITH_SECONDS,"f","F","ff","FF"];for(let a of n){if(Re(e,a,t))return!0}return!1}#w(e,t){return $e(this.isQaLocale()?this.defaultLocale():e,t)}}class Ue extends _e{constructor(){super("number")}validate(e){return this.#L(e)||this.isInternationalized(e)}isInternationalized(e){return this.#T(this.currentLocale(),e)}buildConfig(){}#T(e,t){const n=this.getGlobalize(e).numberParser();return!isNaN(n(t))}#L(e){return this.#T(this.defaultLocale(),e)}}class Fe extends _e{constructor(){super("percentage")}validate(e){return this.#I(e)||this.isInternationalized(e)}isInternationalized(e){return this.#S(this.currentLocale(),e)}buildConfig(){}#S(e,t){if(!this.#E(e,t))return!1;const n=this.#C(t);return!isNaN(this.getGlobalize(e).numberParser()(n))}#C(e=""){return e.replace(new RegExp(`(^(?:${Pe()})*|(?:${Pe()})*$)`,"g"),"").replace(/^-/,"").replace(/٪|%/g,"").trim()}#E(e,t){const n="[0-9,. ]+";let a;return a=["fa-IR","fa-ir"].includes(e)||e.startsWith("ar")?new RegExp(`(?:-)?(?:${Pe()})?(?:٪|%)(?:${Pe()})?${n}`,"g"):new RegExp(`(?:-)?(?:${Pe()})?${n}(?:${Pe()})?(?:٪|%)`,"g"),a.test(t)}#I(e){return this.#S(this.defaultLocale(),e)}}class Ge extends _e{constructor(){super("string")}buildConfig(){const e=mt.getOptions();this.addToConfig("mockChars",e?.qaMock),this.addToConfig("resource",mt.getResourceBundle(),{}),this.addToConfig("garbledChars",mt.getGarbledChars()?.filter((e=>String(e).trim())).filter(Boolean),[])}isInternationalized(e){const t=e.trim().replace(/\s*:\s*$/,""),n=this.getConfig()?.resource?.[this.defaultLocale()];return n?.includes(e)||n?.includes(t)}validate(e){return"string"==typeof e}isDntText(e){return this.getConfig()?.resource?.dnt?.includes(e)}isAutoIgnoredText(e){return this.isDefaultLocale()||this.isUserInputText(e)||this.isEmailText(e)||this.isUrlText(e)}isIgnoredText(e){return this.getConfig()?.resource?.ignore?.includes(e)}isUserInputText(e){return e.startsWith("zqa_")}isEmailText(e){return ge.EMAIL.test(e)}isUrlText(e){return ge.URL.test(e)}isFullQaLanguageText(e){const t=this.getConfig();return(e.slice(0,2)===t?.mockChars?.prefix||e.slice(0,2)===t?.mockChars?.prefix.toUpperCase())&&e.slice(-2)===t?.mockChars.suffix}isPartialQaLanguageText(e){const t=this.getConfig();return e.slice(0,2)===t?.mockChars.prefix||e.slice(0,2)===t?.mockChars.prefix.toUpperCase()||e.slice(-2)===t?.mockChars.suffix}hasEncodingIssue(e){return this.getConfig()?.garbledChars?.length>0&&this.getConfig().garbledChars.some((t=>e.includes(t)))}isPartiallyLocalizedText(e){return this.#N(e)===this.currentLanguage()}#N(e){const t=Object.keys(S(e)?.scores||{}).filter(Boolean)||[],n=this.currentLanguage();return t.length?t.includes(n)?n:t[0]:this.defaultLanguage()}isLocalized(e){const t=e.trim().replace(/\s*:\s*$/,""),n=this.getConfig()?.resource?.[this.currentLocale()];return n?.includes(e)||n?.includes(t)}}class Ve extends _e{constructor(){super("time")}validate(e){return this.#z(e)||this.isInternationalized(e)}isInternationalized(e){return this.#x(this.isQaLocale()?this.defaultLocale():this.currentLocale(),e)}buildConfig(){}#x(e,t){return this.#y(e,t)||this.#v(e,t)||this.#w(e,t)}#z(e){return this.#x(this.defaultLocale(),e)}#y(e,t){const n=["short","medium","long","full"];for(let a of n){if(this.getGlobalize(e).dateParser({time:a})(t))return!0}return!1}#v(e,t){const n=[DateTime.TIME_SIMPLE,DateTime.TIME_WITH_SECONDS,DateTime.TIME_WITH_SHORT_OFFSET,DateTime.TIME_WITH_LONG_OFFSET,DateTime.TIME_24_SIMPLE,DateTime.TIME_24_WITH_LONG_OFFSET,DateTime.TIME_24_WITH_SECONDS,DateTime.TIME_24_WITH_SHORT_OFFSET,"t","T","tt","TT"];for(let a of n){if(Re(e,a,t))return!0}return!1}#w(e,t){return $e(this.isQaLocale()?this.defaultLocale():e,t)}}class Qe{static#M={};static#P;static#_;static#O;static#$;static#A;static#R;static#j;static load(){Qe.#P=new Ge,Qe.#_=new Ue,Qe.#O=new je,Qe.#$=new Ve,Qe.#A=new ke,Qe.#R=new Oe,Qe.#j=new Fe}static getIssueType(e){const t=mt.getLocale();if(t){let n=ie;return Qe.#M[t]||(Qe.#M[t]={}),Qe.#M[t][e]?Qe.#M[t][e]:(this.#P.isAutoIgnoredText(e)?n=se:this.#P.isDntText(e)?n=ae:this.#P.isIgnoredText(e)?n=re:this.#P.hasEncodingIssue(e)?n=ne:this.#R.validate(e)?n=this.#R.isInternationalized(e)?G:Z:this.#j.validate(e)?n=this.#j.isInternationalized(e)?V:W:this.#_.validate(e)?n=this.#_.isInternationalized(e)?F:H:this.#O.validate(e)?n=this.#O.isInternationalized(e)?Q:J:this.#$.validate(e)?n=this.#$.isInternationalized(e)?q:X:this.#A.validate(e)?n=this.#A.isInternationalized(e)?B:K:this.#P.validate(e)?this.#P.isQaLocale()?n=this.#P.isFullQaLanguageText(e)?k:this.#P.isPartialQaLanguageText(e)?U:Y:!this.#P.isDefaultLocale()&&this.#P.isSupportedLocale()&&(n=this.#P.isLocalized(e)?k:this.#P.isPartiallyLocalizedText(e)?U:this.#P.isInternationalized(e)?ie:Y):this.#P.isDefaultLocale()&&(n=se),Qe.#M[t][e]=n,n)}return ie}}class qe{static load(){const e={};if(mt.getOptions()?.l10nResourcePath){const t=Ce(process.cwd(),mt.getOptions()?.l10nResourcePath);if(Le(t))qe.#k(t,e);else{if(!De(t))return void console.error(`${t} invalid resource path`);for(const n of Ee(t)){const a=Ce(t,n);qe.#k(a,e)}}mt.setResourceBundle(e)}}static#k(e,t){const n=mt.getLocale(),a=mt.getDefaultLocale(),r=Se(e),i=(e=>Le(e)?u(e):"")(e);if(pe.includes(i)){if(!r)return void console.error(`${e} is empty or invalid`);if(e.toLowerCase().includes("dnt"))t.dnt=r.split(/\r?\n/);else if(e.toLowerCase().includes("ignore"))t.ignore=r.split(/\r?\n/);else if(e.includes(n)){const e=r.split(/\r?\n/);t[n]=e.map(Be)}else e.includes(a)&&(t[a]=r.split(/\r?\n/))}}}function Be(e){return e.replace(/<\/?[^>]+>/gi,"")}class Ye{static#U;static#F;static init(){Ye.#F=Ce(rt.getReportPath(),mt.getLocale()),Ye.#U=Ce(Ye.#F,be),this.#G()}static exists(){return Le(Ye.#U)}static save(e){this.#G();const t=`!window.rawData && (window.rawData={'${mt.getLocale()}':{}});window.rawData['${mt.getLocale()}']=${JSON.stringify(e)};`;Ne(Ye.#U,t)}static getData(){if(!this.exists())return{};try{return JSON.parse(Se(Ye.#U).replace(new RegExp(`(\\!window.rawData && \\(window\\.rawData=\\{'${mt.getLocale()}':\\{\\}\\}\\);window\\.rawData\\['${mt.getLocale()}'\\]=)|(;$)`,"g"),""))}catch(e){return{}}}static#G(){Ie(Ye.#F)}static getCacheDirPath(){return Ye.#F}}const He=()=>{qe.load(),Qe.load(),rt.setup(),Ye.init()},Ze=()=>{let e=process.cwd(),t=0;for(;t<10;){const n=Ce(e,"package.json");if(Le(n)){const e=Se(n),t=JSON.parse(e),a={...t?.dependencies||{},...t?.devDependencies||{},...t?.peerDependencies||{}};if("@zeesoft/i18n-verify"!==t.name&&JSON.stringify(a).includes('"@zeesoft/i18n-verify"'))break}e=d(e),t++}return e},We=(e=Ze())=>Se(Ce(e,"package.json"));class Je extends xe{#V;#Q=!1;static#q="STATUS";static#B="COUNTS";constructor(){super(we),this.#Y()}#Y(){this.#V=new E({style:{headerTop:{left:"╔",mid:"╦",right:"╗",other:"═"},headerBottom:{left:"╟",mid:"╬",right:"╢",other:"═"},tableBottom:{left:"╚",mid:"╩",right:"╝",other:"═"},vertical:"║"},columns:[{name:Je.#q,alignment:"left"},{name:Je.#B,alignment:"center"}]})}buildContent(){if(ce[le]>0){this.#Q=!0;for(const e in ce)e!==le?ce.hasOwnProperty(e)&&this.#V.addRows([{STATUS:e,COUNTS:`${ce[e]}`}]):(this.#V.addRows([{STATUS:""+"═".repeat(28)+"",COUNTS:""+"═".repeat(8)+""}]),this.#V.addRows([{STATUS:"OVERALL_REVIEWED",COUNTS:`${ce[e]}`}]))}}export(){this.#Q?this.#V.printTable():it.info("There are no visbile elements with UI strings")}}class Xe{static#H(e){switch(e){case ve:return new Me;case we:return new Je;default:throw new Error("unsupported report type requested")}}static export(e,t,n){const a=Xe.#H(e),r=(new Date).toLocaleString(),i=We()?.match(/"name": "([^"]+)",/)?.[1]||"",s=new ze({appName:i,reportTime:r});a.generate(s),a.export(t,n)}}class Ke{#Z;#W;#J;#X;#K;#ee;#te;#ne;#ae;#re;#ie;#se;#oe;#le;#ce;#de;#ue;#ge;#pe;#he;#me;#fe;#ye;#ve;constructor(e={}){this.#Z=e?.localizedStrings||0,this.#W=e?.notLocalizedStrings||0,this.#J=e?.untranslatedStrings||0,this.#X=e?.partialStrings||0,this.#K=e?.localizedDateTime||0,this.#ee=e?.localizedDate||0,this.#te=e?.localizedTime||0,this.#ne=e?.notLocalizedDateTime||0,this.#ae=e?.notLocalizedDate||0,this.#re=e?.notLocalizedTime||0,this.#ie=e?.localizedNumber||0,this.#se=e?.notLocalizedNumber||0,this.#oe=e?.localizedCurrency||0,this.#le=e?.notLocalizedCurrency||0,this.#ce=e?.localizedPercentage||0,this.#de=e?.notLocalizedPercentage||0,this.#ue=e?.ignored||0,this.#ge=e?.dnt||0,this.#pe=e?.autoIgnored||0,this.#he=e?.userInput||0,this.#me=e?.encoding||0,this.#fe=e?.truncation||0,this.#ye=e?.overlapping||0,this.#ve=e?.reviewed||0}getLocalizedStrings(){return this.#Z}setLocalizedStrings(e){this.#Z=e}getUntranslatedStrings(){return this.#J}setUntranslatedStrings(e){this.#J=e}getNotLocalizedStrings(){return this.#W}setNotLocalizedStrings(e){this.#W=e}getPartialStrings(){return this.#X}setPartialStrings(e){this.#X=e}getLocalizedDateTime(){return this.#K}setLocalizedDateTime(e){this.#K=e}getLocalizedDate(){return this.#ee}setLocalizedDate(e){this.#ee=e}getLocalizedTime(){return this.#te}setLocalizedTime(e){this.#te=e}getNotLocalizedDateTime(){return this.#ne}setNotLocalizedDateTime(e){this.#ne=e}getNotLocalizedDate(){return this.#ae}setNotLocalizedDate(e){this.#ae=e}getNotLocalizedTime(){return this.#re}setNotLocalizedTime(e){this.#re=e}getLocalizedNumber(){return this.#ie}setLocalizedNumber(e){this.#ie=e}getNotLocalizeNumber(){return this.#se}setNotLocalizeNumber(e){this.#se=e}getCurrency(){return this.#oe}setCurrency(e){this.#oe=e}getNotLocalizeCurrency(){return this.#le}setNotLocalizeCurrency(e){this.#le=e}getPercentage(){return this.#ce}setPercentage(e){this.#ce=e}getNotLocalizePercentage(){return this.#de}setNotLocalizePercentage(e){this.#de=e}getIgnored(){return this.#ue}setIgnored(e){this.#ue=e}getUserInput(){return this.#he}setUserInput(e){this.#he=e}getDnt(){return this.#ge}setDnt(e){this.#ge=e}getAutoIgnored(){return this.#pe}setAutoIgnored(e){this.#pe=e}getEncoding(){return this.#me}setEncoding(e){this.#me=e}getTruncation(){return this.#fe}setTruncation(e){this.#fe=e}getOverlapping(){return this.#ye}setOverlapping(e){this.#ye=e}getReviewed(){return this.#ve}setReviewed(e){this.#ve=e}incrementByType(e){switch(e){case k:++this.#Z;break;case Y:++this.#W;break;case ie:++this.#J;break;case U:++this.#X;break;case se:++this.#pe;break;case re:++this.#ue;break;case ae:++this.#ge;break;case ne:++this.#me;break;case Q:++this.#ee;break;case q:++this.#te;break;case B:++this.#K;break;case J:++this.#ae;break;case X:++this.#re;break;case K:++this.#ne;break;case F:++this.#ie;break;case H:++this.#se;break;case G:++this.#oe;break;case Z:++this.#le;break;case V:++this.#ce;break;case W:++this.#de;break;case ee:++this.#fe;break;case te:++this.#ye;break;case le:++this.#ve;break;case oe:++this.#he}}toJSON(){return{localizedStrings:this.#Z,notLocalizedStrings:this.#W,untranslatedStrings:this.#J,partialStrings:this.#X,localizedDateTime:this.#K,localizedDate:this.#ee,localizedTime:this.#te,notLocalizedDateTime:this.#ne,notLocalizedDate:this.#ae,notLocalizedTime:this.#re,localizedNumber:this.#ie,notLocalizedNumber:this.#se,localizedCurrency:this.#oe,notLocalizedCurrency:this.#le,localizedPercentage:this.#ce,notLocalizedPercentage:this.#de,ignored:this.#ue,dnt:this.#ge,autoIgnored:this.#pe,userInput:this.#he,encoding:this.#me,truncation:this.#fe,overlapping:this.#ye,reviewed:this.#ve}}}class et{#we;constructor(e={}){this.#we=new Ke(e.stats)}getStats(){return this.#we}setStats(e){this.#we=e}toJSON(){return{stats:this.#we}}}class tt{#r;#be;#De;constructor(e){this.#r=e?.type||"",this.#be=e?.imagePath||"",this.#De=e?.description||""}getType(){return this.#r}setType(e){this.#r=e}getImagePath(){return this.#be}setImagePath(e){this.#be=e}getDescription(){return this.#De}setDescription(e){this.#De=e}toJSON(){return{type:this.#r,description:this.#De,imagePath:this.#be}}}class nt{#Le={};constructor(e){if(e)for(const t in e)e[t].forEach((e=>{this.#Le[t]||(this.#Le[t]=[]),this.#Le[t].push(new tt(e))}))}getStringData(e){return this.#Le[e]||[]}setStringData(e,t){return!this.#Le[e]&&(this.#Le[e]=[]),this.#Le[e].push(new tt(t)),!0}checkAndAdd(e,t){!this.#Le[e]&&(this.#Le[e]=[]);const n=this.getStringData(e).some((e=>e.getDescription()!==t.description||e.getImagePath()!==t.imagePath||e.getType()!==e.type));return n&&this.setStringData(e,t),n}hasStringData(e){return e in this.#Le}static createNew(e,t){return t=Array.isArray(t)?t:[t],new nt({data:{[e]:t}})}toJSON(){return this.#Le}}class at{#Te;#Ie;constructor(e={}){this.#Te=new et(e.metaData),this.#Ie=new nt(e.stringsData)}getMetaData(){return this.#Te}setMetaData(e){this.#Te=e}getStringEntry(e){return this.#Ie.getStringData(e)}static addString(e,t,n,a){const r=at.getInstance(),i=r.#Se(e,t,n,a.replace(/\\/g,"/"));return i&&r.save(),i}#Se(e,t,n,a){let r=!1;const i={type:t,description:n,imagePath:a};return r=this.#Ie.hasStringData(e)?this.#Ie.checkAndAdd(e,i):this.#Ie.setStringData(e,i),r&&this.#Te.getStats().incrementByType(t),r}toJSON(){return{metaData:this.#Te,stringsData:this.#Ie}}save(){Ye.save(this)}remove(){Ye.delete()}static getInstance(){return new at(Ye.getData())}}class rt{static#Ee;static#Ce;static setup(){rt.#Ce=rt.#A();const e=l.resolve();rt.#Ee=Ce(e,mt.getL10nReportsPath(),rt.#Ce)}static getReportTimeStamp(){return rt.#Ce}static getReportPath(){return rt.#Ee}static reviewedReports(e=null,t=null){return rt.#Ne(le,e,t)}static[k](e,t){return rt.#Ne(k,e,t)}static[Y](e,t){return rt.#Ne(Y,e,t)}static[U](e,t){return rt.#Ne(U,e,t)}static[ae](e,t){return rt.#Ne(ae,e,t)}static[re](e,t){return rt.#Ne(re,e,t)}static[se](e,t){return rt.#Ne(se,e,t)}static[ie](e,t){return rt.#Ne(ie,e,t)}static[ne](e,t){return rt.#Ne(ne,e,t)}static[B](e,t){return rt.#Ne(B,e,t)}static[K](e,t){return rt.#Ne(K,e,t)}static[Q](e,t){return rt.#Ne(Q,e,t)}static[J](e,t){return rt.#Ne(J,e,t)}static[q](e,t){return rt.#Ne(q,e,t)}static[X](e,t){return rt.#Ne(X,e,t)}static[G](e,t){return rt.#Ne(G,e,t)}static[Z](e,t){return rt.#Ne(Z,e,t)}static[V](e,t){return rt.#Ne(V,e,t)}static[W](e,t){return rt.#Ne(W,e,t)}static[F](e,t){return rt.#Ne(F,e,t)}static[H](e,t){return rt.#Ne(H,e,t)}static incrementCount(e,t,n,a){ce.hasOwnProperty(e)&&(ce[e]++,at.addString(t,e,a,n.replace(rt.#Ee,"")))}static#A(){const e=new Date;return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}-${String(e.getHours()).padStart(2,"0")}-${String(e.getMinutes()).padStart(2,"0")}`}static#Ne=(e,t,n)=>{const a=Ce(rt.#Ee,mt.getLocale(),"screenshots",String(e).toLowerCase());Ie(a,me);const r=Ce(rt.#Ee,mt.getLocale(),"strings");if(Ie(r,me),null!=t){let a="";if(Te(Ce(r,e+".txt"))){Se(Ce(r,e+".txt")).includes(n)||(a+=`\n|<<<<<<<<<<<<<------${n}------\x3e>>>>>>>>>>>>|\n`),a+=t}else a+=`\n|<<<<<<<<<<<<<------${n}------\x3e>>>>>>>>>>>>|\n`,a+=t;((e,t,n="utf-8")=>{if(e&&t)try{s(e,t+"\n",{encoding:n,flag:"a"})}catch(e){it.error(e)}})(Ce(r,e+".txt"),a)}return a};static#ze(e){Xe.export(e,rt.#Ee)}static generateHtml(){rt.#ze(ve)}static generateAsciiTable(){rt.#ze(we)}}class it{static#xe=!1;static#Me;static#Pe=[];static info(e){it.#_e("info",e)}static warn(e){it.#_e("warn",e)}static error(e,t){it.#_e("errr",e,t)}static debug(e){it.#_e("dbug",e)}static#_e(e,t,n=""){const a={INFO:"",WARN:"",ERRR:"",DBUG:""};let r=a[e=e.toUpperCase()]||a.DEFAULT;n=n?` reason: ${n.toString()}`:"";let i=`[${(new Date).toLocaleString()}] [${r}${e}] [${mt.getLocale()}] - ${t}${n}`;switch(e){case"INFO":console.info(i);break;case"WARN":console.warn(i);break;case"ERRR":console.error(i);break;case"DBUG":console.debug(i);break;default:console.log(i)}i=i.replace(/\x1b\[\d+m/g,""),it.#Oe(`${i}\n`)}static#Oe=t=>{if(it.#xe)it.#Pe.push(t),it.#Me=setInterval((()=>{it.#xe||(clearInterval(it.#Me),t=it.#Pe.join("\n"),it.#Pe=[],t&&it.#Oe(t))}),10);else{it.#xe=!0;const n=Ce(rt.getReportPath(),"logs"),a=Ce(n,"log");Ie(n,me),e.appendFileSync(a,t),it.#xe=!1}}}class st extends z{constructor(e){super(e)}getElement(e){return this.$driver.element.find({selector:e,locateStrategy:e.startsWith("/")?"xpath":"css selector"})}async getElements(e){return await this.$driver.element.findAll({selector:e,locateStrategy:e.startsWith("/")?"xpath":"css selector"})}async getText(e){return await e.getText()}async getTitle(e){return await e.getAttribute("title")}async getPlaceholderText(e){return await e.getAttribute("placeholder")}async getAltText(e){return await e.getAttribute("alt")}async getTagName(e){return await e.getTagName()}async getValue(e){return await e.getAttribute("value")}async getElementID(e){return await e.getAttribute("id")}async getElementDimension(e){const t=await e.getRect();if(![null,"",void 0].includes(t))return[t.x,t.y,t.height,t.width]}async isElementDisplayed(e){return await this.$driver.isVisible(e)}async isElementPresent(e){return await this.$driver.isPresent(e)}async getElementStrings(e){const t=[];return[{type:"eleTxt",value:await this.getText(e)},{type:"altTxt",value:await this.getAltText(e)},{type:"titleTxt",value:await this.getTitle(e)},{type:"placeTxt",value:await this.getPlaceholderText(e)},{type:"valueTxt",value:await this.getValue(e)}].forEach((({value:e})=>{this.checkIfNullOrEmpty(e)&&t.push(e)})),t}async getElementString(e){let t=null;const n=[this.getText,this.getAltText,this.getTitle,this.getPlaceholderText,this.getValue];for(const a of n)if(t=await a(e),null!==t)return t;return t}async captureScreenshot(e){await ot(this.$driver,e)}async getElementsCount(e){return e.length}async switchIframe(e){await this.$driver.frame(e,(()=>{it.debug(`Switching to ${e} frame`)}))}async switchToParentframe(){await this.$driver.frame(null)}pause(e){this.$driver.pause(1e3*e)}async onScreenStringHighlight(e,t){await this.$driver.execute(((e,t)=>{const n=window.getComputedStyle(e).border;e.style.border=`3px solid ${t}`,setTimeout((()=>{e.style.border=n}),40)}),[e,t])}async checkIfIframeIsPresent(){return new Promise((e=>{this.$driver.isPresent({selector:"//iframe",locateStrategy:"xpath",suppressNotFoundErrors:!0},(t=>{e(t.value)}))}))}async checkIfIframeBodyIsEmpty(){const e=await this.$driver.executeScript("return document.body.innerHTML");return""===await e.trim()}}const ot=async(t,n)=>{const a=await C({host:"localhost",port:9222}),{Page:r}=a;await r.enable();const{data:i}=await r.captureScreenshot({format:"png",captureBeyondViewport:!0}),s=Buffer.from(i,"base64");e.writeFileSync(n,s),console.log(`Screenshot saved as: ${n}`),await a.close()};class lt extends z{constructor(e){super(e)}getElement(e){return this.$driver.findElement("xpath",e)}async getElements(e){return await this.$driver.findElements("xpath",e)}async getText(e){return await $(e).getText()}async getTitle(e){return await $(e).getAttribute("title")}async getPlaceholderText(e){return await $(e).getAttribute("placeholder")}async getAltText(e){return await $(e).getAttribute("alt")}async getTagName(e){return await $(e).getTagName()}async getValue(e){return await $(e).getValue()}async getElementDimension(e){const t=await this.$driver.getElementRect(e["element-6066-11e4-a52e-4f735466cecf"]);if(![null,"",void 0].includes(t))return[t.x,t.y,t.height,t.width]}isElementDisplayed(e){return $(e).isDisplayed()}async getElementStrings(e){const t=[];return[{type:"eleTxt",value:await this.getText(e)},{type:"altTxt",value:await this.getAltText(e)},{type:"titleTxt",value:await this.getTitle(e)},{type:"placeTxt",value:await this.getPlaceholderText(e)},{type:"valueTxt",value:await this.getValue(e)}].forEach((({value:e})=>{this.checkIfNullOrEmpty(e)&&t.push(e)})),t}async captureScreenshot(e){await this.$driver.saveScreenshot(e)}async getElementsCount(e){return e.length}}const ct=({subject:e,selector:t,options:n={},driver:a})=>{if(!Cypress)return void a.printOnConsole("Cypress object is inaccessible");const r={name:"xpath",message:t};if(Cypress.dom.isElement(e)&&e.length>1)throw new Error("xpath() can only be called on a single element. Your subject contained "+e.length+" elements.");const i=()=>{let n,a=[],i=cy.state("withinSubject");n=Cypress.dom.isElement(e)?e[0]:Cypress.dom.isDocument(e)?e:i?i[0]:cy.state("window").document;let s=(n.ownerDocument||n).evaluate(t,n);if(s.resultType===XPathResult.NUMBER_TYPE){const e=(e=>e.numberValue)(s);return r.consoleProps=()=>({XPath:t,type:"number",result:e}),e}if((e=>e.resultType===XPathResult.STRING_TYPE)(s)){const e=(e=>e.stringValue)(s);return r.consoleProps=()=>({XPath:t,type:"string",result:e}),e}if((e=>e.resultType===XPathResult.BOOLEAN_TYPE)(s)){const e=(e=>e.booleanValue)(s);return r.consoleProps=()=>({XPath:t,type:"boolean",result:e}),e}try{let e=s.iterateNext();for(;e;)a.push(e),e=s.iterateNext();return r.consoleProps=()=>({XPath:t,result:1===a.length?a[0]:a}),a}catch(e){return console.error("Document tree modified during iteration",e),null}},s=()=>Cypress.Promise.try(i).then((e=>{var a;return a=e,Cypress._.isNumber(a)||Cypress._.isString(a)||Cypress._.isBoolean(a)||((e=Cypress.$(e)).selector=t),cy.verifyUpcomingAssertions(e,n,{onRetry:s})}));return s().then((e=>(!1!==n.log&&Cypress.log(r),e))).catch((e=>console.log(e)))};class dt extends z{constructor(e){super(e)}async getElement(e){return"string"!=typeof e?this.$driver.wrap(e):e.startsWith("//")?await this.xpath(e).first():await this.$driver.get(e).first()}async getElements(e){return"string"!=typeof e?this.$driver.wrap(e):e.startsWith("//")?await this.xpath(e):await this.$driver.get(e)}async getText(e){return"string"==typeof e?await this.$driver.get(e).invoke("text"):await this.$driver.wrap(e).invoke("text")}async getTitle(e){return"string"==typeof e?await this.$driver.get(e).title():this.$driver.wrap().title()}async getPlaceholderText(e){return"string"==typeof e?this.$driver.get(e).filter("input").invoke("attr","placeholder").then((e=>e)):this.$driver.$$(e).attr("placeholder")}async getAltText(e){return this.$driver.get(e).invoke("attr","alt")}async getWidth(e){return"string"==typeof e?this.$driver.get(e).invoke("width"):this.$driver.$$(e).width()}async getHeight(e){return"string"==typeof e?this.$driver.get(e).invoke("height"):this.$driver.$$(e).height()}async getTagName(e){return"string"==typeof e?this.$driver.get(e).invoke("prop","tagName").then((e=>e.toLowerCase())):this.$driver.$$(e).tagName}async getValue(e){return"string"==typeof e?this.$driver.get(e).invoke("val"):this.$driver.wrap(e).invoke("val")}async getLocation(e){if("string"==typeof e)return this.$driver.get(e).invoke("offset").then((e=>({x:e.left,y:e.top})));{const t=this.$driver.$$(e).offset();return{x:t.left,y:t.top}}}async isElementDisplayed(e){return"string"==typeof e?this.$driver.get(e).then((e=>e.is(":visible"))):this.$driver.$$(e).is(":visible")}async captureScreenshot(e){this.$driver.screenshot(e)}async getElementsCount(e){return new Promise((t=>"string"==typeof e?this.$driver.get(e).its("length").then((e=>t(e))):this.$driver.wrap(e,{timeout:8e3}).its("length").then((e=>t(e)))))}async getElementStrings(e){const t=[];try{[{type:"eleTxt",value:await this.getText(e)},{type:"altTxt",value:await this.getAltText(e)},{type:"placetxt",value:await this.getPlaceholderText(e)}].forEach((({value:e})=>{this.checkIfNullOrEmpty(e)&&t.push(e)}))}catch(e){it.error("Error getting text of element:",e)}return t}printOnConsole(e){this.$driver.log(e)}xpath(e,t,n={}){return ct({subject:e,selector:t,options:n,driver:this.$driver})}}class ut extends z{constructor(e){super(e)}async getElement(e){return await this.driver.findElement(e)}async getElements(e){return await this.driver.findElements(e)}async getText(e){return await e.getText()}async getTitle(){return await this.driver.getTitle()}async getAttribute(e,t){return await e.getAttribute(t)}async getTagName(e){return await e.getTagName()}async getElementDimension(e){const t=await e.getRect();if(![null,"",void 0].includes(t))return[t.x,t.y,t.height,t.width]}async isElementDisplayed(e){return await e.isDisplayed()}async getElementStrings(e){const t=[];return[{type:"eleTxt",value:await this.getText(e)},{type:"altTxt",value:await this.getAttribute(e,"alt")},{type:"titleTxt",value:await this.getAttribute(e,"title")},{type:"placeTxt",value:await this.getAttribute(e,"placeholder")},{type:"valueTxt",value:await this.getAttribute(e,"value")}].forEach((({value:e})=>{this.checkIfNullOrEmpty(e)&&t.push(e)})),t}async getElementsCount(e){return e.length}}const gt=(e,t=", ")=>e.join(t),pt=()=>{const e=Ce(process.cwd(),ye);if(!Le(e))throw new Error(`${ye} file is missing. Please add the file in your project root dir`);let t=Se(e);if(!t)throw new Error(`invalid ${ye} file. Please add valid file in your project root dir`);t=t.replace(/\/\/.+$/gm,"");try{t=JSON.parse(t)}catch(e){throw new Error(`invalid ${ye} file. Please add valid file in your project root dir`)}return t},ht=(e,t="")=>{e&&!Le(e)&&Ne(e,((e="")=>`{\n "type": "${e}", // set automation framework type ${gt(Object.values(x))}\n "qaLocale": "", // set the qa locale used in your project\n "l10nResourcePath": "./l10nResources", // set the dir path of l10n resources\n "l10nReportsPath": "./l10nReports/", // set the dir path of l10n reports\n "supportedLocales": ["en_US", "fr_FR", "ja_JP"], // set the list of supported locales\n "defaultLocale": "en_US", // set default locale of the application\n "qaMock": { // set the prefix and suffix characters of qa locale\n "prefix": "à_",\n "suffix": "_海"\n },\n "i18nVerify": true, // enable or disable I18n verification\n "sanityCapture": false, // will capture strings and highlight them when i18n verification is off\n "garbledChars": [""] // set the list of custom garbled characters\n}`)(t))};class mt{static#$e;static#Ae;static#r;static#Re;static#je;static#ke;static#Ue;static#Fe;static init(){try{const e=pt();(e=>{if("object"!=typeof e||Object.keys(e).length<1)throw new Error(`empty ${ye} file`);const t=[];if(!((e,t,n=[])=>["l10nResourcePath","l10nReportsPath","supportedLocales","defaultLocale","type"].every((e=>(((e,t)=>e in t)(e,t)||n.push(e),!0))))(0,e,t))throw new Error(`following properties are missing in ${ye} file: ${gt(t)}`);if(!Object.values(x).includes(e?.type||""))throw new Error(`${ye} has invalid system type`)})(e),this.#r=e?.type,this.#je=e?.qaLocale,this.#ke=e,this.#Fe=0,this.getGarbledChars()}catch(e){throw it.error(e.message),e}}static set(e,t){this.#Re=t,this.#$e=((e,t)=>{switch(e){case x.NIGHT_WATCH:return new st(t);case x.WEB_DRIVER_IO:return new lt(t);case x.CYPRESS:return new dt(t);case x.SELENIUMJS:return new ut(t);default:throw new Error("Unsupported framework")}})(this.#r,e)}static getGarbledChars(){return[...this.#ke.garbledChars||[],...fe]}static getL10nReportsPath(){return this.#ke.l10nReportsPath}static setDriver(e){this.#$e=e}static setType(e){this.#r=e}static setLocale(e){this.#Re=e}static setOptions(e){this.#ke=e}static getRunner(){if(mt.#Ae)return mt.#Ae;if(!mt.#$e)throw new Error("Unable to initialize I18n Runner");return this.#Ae=new yt(this.#$e),this.#Ae}static getDriver(){return this.#$e}static getLocale(){return this.#Re}static getDefaultLocale(){return this.#ke.defaultLocale}static getType(){return this.#r}static getOptions(){return this.#ke}static setQALocale(e){this.#je=e}static getQALocale(){return this.#je}static setResourceBundle(e){this.#Ue=e}static getResourceBundle(e){return this.#Ue?.[e]||this.#Ue||[]}static incrementCounter(){this.#Fe++}static getSSCount(){return this.#Fe}}class ft{static async drawRectangle(t,n,a){const r=t?.x-2,i=t?.y-2,s=t?.width+2,o=t?.height+2;try{const t=await N.read(a),c=N.cssColorToHex(n);this.drawRectangleOutline(t,r,i,s,o,c,2);const d=l.dirname(a),u=await t.getBufferAsync(N.MIME_PNG);e.existsSync(d)||(it.debug("folder not found"),e.mkdirSync(d,{recursive:!0})),e.writeFileSync(a,u)}catch(e){it.error(`Error: ${e}`)}}static async drawRectangleOutline(e,t,n,a,r,i,s){for(let o=t;o<t+a;o++)for(let t=0;t<s;t++)e.setPixelColor(i,o,n+t),e.setPixelColor(i,o,n+r-1-t);for(let o=n;o<n+r;o++)for(let n=0;n<s;n++)e.setPixelColor(i,t+n,o),e.setPixelColor(i,t+a-1-n,o)}}class yt{#$e;constructor(e){this.#$e=e}async verify({verificationArea:e,staticLocators:t,description:n}){let a,r=[];const i=mt.getOptions();if(Array.isArray(t)&&t.length>0)for(const n of t){let t=e+n;r.push(t)}else a=""!==e?e+he:he;mt.incrementCounter();const s=`${mt.getSSCount().toString().padStart(3,"0")}_${n.replace(/[^\w\s]/gi,"").replace(/\s+/g,"")}.png`;if(!i?.sanityCapture&&i?.i18nVerify){const e=Ce(rt.reviewedReports(),s);await this.#Ge(e)}if(i?.i18nVerify||i?.sanityCapture)try{if(r.length>0)for(const t of r)await this.#Ve(e,t,s,n,i?.i18nVerify);else await this.#Qe(e,a,s,n,i?.i18nVerify)}catch(e){it.error("Elements not found under specified locator on page: ",n)}else it.info("Skipped i18n verification as per user configuration...")}async#Ve(e,t,n,a,r=!1){const i=await this.#$e.getElement(t);if(i&&await this.#$e.isElementPresent(i)){let t;try{t=await this.#$e.getElementString(i);try{await this.#qe({verificationArea:e,ele:i,img_name:n,str:t,desc:a,doI18nVerification:r})}catch(e){it.error("Error generating report of element:",e)}}catch(e){it.error("Error getting text of element:",e)}}else it.error("No element found:",t)}async#Qe(e,t,n,a,r=!1){const i=await this.#$e.getElements(t);if(i.length>0)for(const t of i)if(await this.#$e.isElementPresent(t)){let i;try{i=await this.#$e.getElementStrings(t);try{for(const s of i)await this.#qe({verificationArea:e,el:t,img_name:n,str:s,desc:a,doI18nVerification:r})}catch(e){it.error("Error generating report of element:",e)}}catch(e){it.error("Error getting text of elements:",e)}}if(await this.#$e.checkIfIframeIsPresent()){const e=await this.#$e.getElements("//iframe");it.debug(`Total ${e.length} iframes are located on the ${a}`),await this.#Be({iframes:e,img_name:n,desc:a,doI18nVerification:r})}}async#qe({verificationArea:t,el:n,img_name:a,str:r,desc:i,iframePresent:s=!1,doI18nVerification:o=!1}){if("string"!=typeof r||!r||0===Number(r))return;const l=Ce(rt.reviewedReports(r,a),a);let c,d,u=!0;if(o?(rt.incrementCount(le,r,l,i),c=Qe.getIssueType(r),c&&l&&"function"==typeof rt[c]&&(d=Ce(rt[c](r,a),a))):(c=le,d=Ce(rt.reviewedReports(r,a),a),u=!1),d){e.existsSync(l)||await this.#Ge(l),e.existsSync(d)||e.copyFileSync(l,d);const a=this.#Ye(c,r);rt.incrementCount(c,r,d,i),u&&(this.#$e.onScreenStringHighlight(n,a),await this.#He({verificationArea:t,el:n,color:a,src_img:l,dest_img:d,str:r,iframePresent:s,desc:i}))}}async#He({verificationArea:e,el:t,color:n,dest_img:a,iframePresent:r}){let i,s=await this.#Ze(t);const o=O;if(r){i=e;const t=["x","y"];for(const e of t)e in s&&e in i&&(s[e]=i[e]+s[e])}else if(!mt.options?.sanityCapture){const t=await this.#$e.getElement(e);i=await this.#Ze(t)}mt.options?.sanityCapture||await ft.drawRectangle(i,o,a),await ft.drawRectangle(s,n,a)}async#Ge(e){try{await this.#$e.captureScreenshot(e)}catch(e){it.error("unable to capture screenshot")}}async#Ze(e){const t=await this.#$e.getElementDimension(e);return{x:t[0],y:t[1],height:t[2],width:t[3]}}#Ye(e,t){return it.debug(`"${t}" - ${de[e][1]}${ue[e]}`),de[e][0]}async#Be({iframes:e,img_name:t,desc:n,doI18nVerification:a=!1}){for(const r of e){const e=await this.#$e.getElementID(r);if(e&&""!==e){const i=await this.#Ze(r);this.#$e.switchIframe(e),this.#$e.pause(2);const s=await this.#$e.getElement("//body");if(await this.#$e.isElementPresent(s),!await this.#$e.checkIfIframeBodyIsEmpty()){const e=await this.#$e.getElements("//*[normalize-space(text())]");if(e.length>0)for(const r of e)if(await this.#$e.isElementPresent(r)){let e=await this.#$e.getElementStrings(r);try{for(const s of e)await this.#qe({verificationArea:i,el:r,img_name:t,str:s,desc:n,iframePresent:!0,doI18nVerification:a})}catch(e){it.error("Error generating report of iframe elements:",e)}}}}await this.#$e.switchToParentframe()}}}export{mt as C,yt as I,it as L,rt as R,x as S,We as a,ye as b,ht as c,Ze as g,Ce as j,He as l};
1
+ import e,{statSync as t,existsSync as n,readFileSync as a,readdirSync as r,writeFileSync as i,appendFileSync as s,mkdirSync as o}from"fs";import l,{join as c,dirname as d,extname as u}from"path";import g from"globalize";import h from"cldr-data";import{en as p,uk as m,nl as f,ru as y,zh as v,ja as w,pt as b,fr as L,es as D,de as T}from"chrono-node";import{DateTime as S}from"luxon";import{detectTextLangEx as I}from"@isdk/detect-text-language";import{Table as E}from"console-table-printer";import C from"chrome-remote-interface";import N from"jimp";class z{constructor(e){this.$driver=e}checkIfNullOrEmpty(e){return![null,"",void 0].includes(e)}getElement(){throw new Error("implementation is missing")}getElements(){throw new Error("implementation is missing")}getText(){throw new Error("implementation is missing")}getTitle(){throw new Error("implementation is missing")}getPlaceholderText(){throw new Error("implementation is missing")}getAltText(){throw new Error("implementation is missing")}getWidth(){throw new Error("implementation is missing")}getHeight(){throw new Error("implementation is missing")}getTagName(){throw new Error("implementation is missing")}getValue(){throw new Error("implementation is missing")}getLocation(){throw new Error("implementation is missing")}getElementDimension(){throw new Error("implementation is missing")}getElementID(){throw new Error("implementation is missing")}isElementDisplayed(){throw new Error("implementation is missing")}isElementPresent(){throw new Error("implementation is missing")}getElementString(){throw new Error("implementation is missing")}getElementStrings(){throw new Error("implementation is missing")}captureScreenshot(){throw new Error("implementation is missing")}getElementsCount(){throw new Error("implementation is missing")}switchIframe(){throw new Error("implementation is missing")}switchToParentframe(){throw new Error("implementation is missing")}pause(){throw new Error("implementation is missing")}onScreenStringHighlight(){throw new Error("implementation is missing")}checkIfIframeIsPresent(){throw new Error("implementation is missing")}checkIfIframeBodyIsEmpty(){throw new Error("implementation is missing")}printOnConsole(e){console.log(e)}}const x={NIGHT_WATCH:"nightwatch",WEB_DRIVER_IO:"webio",CYPRESS:"cypress",SELENIUMJS:"seleniumJS"},M="rgb(0, 154, 61)",P="rgb(255, 0, 0)",_="rgb(255, 255, 0)",A="rgb(0, 0, 255)",O="",R="",j="",k="STRING_LOCALIZED",U="STRING_PARTIALLY_LOCALIZED",F="NUMBER_LOCALIZED",G="CURRENCY_LOCALIZED",V="PERCENTAGE_LOCALIZED",Q="DATE_LOCALIZED",q="TIME_LOCALIZED",B="DATE_TIME_LOCALIZED",H="STRING_NOT_LOCALIZED",Y="NUMBER_NOT_LOCALIZED",Z="CURRENCY_NOT_LOCALIZED",W="PERCENTAGE_NOT_LOCALIZED",J="DATE_NOT_LOCALIZED",X="TIME_NOT_LOCALIZED",K="DATE_TIME_NOT_LOCALIZED",ee="TRUNCATION_ISSUE",te="OVERLAPPING_ISSUE",ne="ENCODING_ISSUE",ae="DNT",re="IGNORE",ie="UNTRANSLATED",se="AUTO_IGNORE",oe="USER_INPUT",le="REVIEWED",ce={[k]:0,[H]:0,[U]:0,[F]:0,[Y]:0,[Q]:0,[J]:0,[B]:0,[K]:0,[q]:0,[X]:0,[G]:0,[Z]:0,[V]:0,[W]:0,[ee]:0,[te]:0,[ne]:0,[ae]:0,[re]:0,[ie]:0,[se]:0,[oe]:0,[le]:0},de={[k]:[M,O],[U]:[_,j],[F]:[M,O],[Q]:[M,O],[q]:[M,O],[B]:[M,O],[G]:[M,O],[V]:[M,O],[H]:[P,R],[J]:[P,R],[K]:[P,R],[X]:[P,R],[Y]:[P,R],[Z]:[P,R],[W]:[P,R],[ee]:[P,R],[te]:[P,R],[ne]:[P,R],[ae]:[M,O],[re]:[M,O],[ie]:[M,O],[se]:[M,O],[oe]:[M,O],[le]:[M,O]},ue={[k]:"string is localized",[U]:"string is partially localized",[F]:"number is localized",[Q]:"date is localized",[B]:"dateTime is localized",[q]:"time is localized",[G]:"currency is localized",[V]:"percentage is localized",[H]:"string is not localized",[J]:"date is not localized",[K]:"dateTime is not localized",[X]:"time is not localized",[Y]:"number is not localized",[Z]:"currency is not localized",[W]:"percentage is not localized",[ee]:"truncation issue detected",[te]:"overlapping issue detected",[ne]:"encoding issue detected",[ae]:"do not translate",[re]:"ignored this issue",[ie]:"string is untranslated",[se]:"automatically ignored issue",[oe]:"user input field",[le]:"string has been reviewed"},ge={EMAIL:/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}\b/gi,URL:/^(https?:\/\/)?(www\.)?[a-zA-Z0-9-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?$/},he=[".txt",".json"],pe="//*[string-length(normalize-space(text())) > 0 and not(ancestor-or-self::*/@style[contains(.,'display:none')]) or @placeholder] | //input[@type='checkbox']/parent::*[text() and not(ancestor-or-self::*/@style[contains(.,'display:none')])]",me=!0,fe=["☐","�","퟿","â€","î","ÃÂ","í","ü","é","é","æ•°","据","ラã"],ye=".i18n-verify.rc",ve="html",we="ascii_table",be="metrics.cache",Le=e=>Te(e)&&t(e).isDirectory(),De=e=>Te(e)&&t(e).isFile(),Te=e=>n(e),Se=(e,t=!0)=>{Te(e)&&Le(e)||(t&&st.debug(`Folder doesn't exists, creating ${e}`),(e=>{!Te(e)&&o(e,{recursive:!0})})(e))},Ie=e=>De(e)?a(e,{encoding:"utf-8"}):"",Ee=e=>Le(e)?r(e):[],Ce=(...e)=>c(...e),Ne=(e,t,n="utf-8")=>i(e,t,{encoding:n}),ze=e=>e.replace(/[^a-zA-Z0-9]+/g,"_");class xe{#e;#t;constructor({appName:e,reportTime:t}){this.#e=e,this.#t=t}getAppName(){return this.#e}getReportTime(){return this.#t}}class Me{#n;$generatedContent;$type;constructor(e){this.$type=e}generate(e){this.#n=e,this.$generatedContent=this.buildContent()}export(e,t="report"){this.write(e,t,this.$generatedContent),st.info(`Exported consolidated I18n Verification ${this.$type} report in ${e}`)}write(e,t,n){throw new Error("should be implemented by child report classes")}buildContent(){throw new Error("should be implemented by child report classes")}getMetaInfo(){return{defaultLocale:yt.getDefaultLocale(),appName:this.#n.getAppName(),reportTime:this.#n.getReportTime(),sanityCapture:yt.getOptions()?.sanityCapture}}}class Pe extends Me{constructor(){super(ve)}buildContent(){const e=this.getMetaInfo(),t=`var DataStore;\n // global functions\n function openImageViewer(imageSrc) {\n var imageView = document.getElementById('imageView');\n imageView.src = \`\${window.getProductUrl()}/\${imageSrc}\`;\n document.getElementById('imageViewer').style.display = 'block';\n }\n\n function closeImageViewer() {\n delete document.getElementById('imageView').src;\n document.getElementById('imageViewer').style.display = 'none';\n }\n\n //to dynamically show/hide header based upon query param: ?standalone=<true|false>\n window.getProductUrl = () => {\n if (window.productUrl) {\n return window.productUrl;\n } else {\n window.productUrl = \`\${window.location.protocol}//\${\n window.location.host\n }\${window.location.pathname.match(/^.+[^\\/report\\.html]/g)?.[0]}\`;\n return window.productUrl;\n }\n };\n const params = new URLSearchParams(location.href.match(/(\\?.*$)/g)?.[0]);\n if (params.size) {\n window.reducedZoom = params.get('standalone') === 'false';\n if(window.reducedZoom) {\n const overview = document.getElementById('overview');\n if(overview) {\n overview.classList.add('--reduced-zoom');\n }\n }\n }\n ${(e=>`// DataStore\n (() => {\n // prepare appData and set DataStore\n var appData = {\n appName: '${e.appName}',\n defaultLocale: '${e.defaultLocale}',\n sanityRun: ${e.sanityCapture},\n timeStamp: '${e.reportTime}',\n metaData: {\n stats: {},\n statsByLocale: {}\n },\n stringsData: {},\n locales: [],\n hasRuntimeError: false\n };\n\n if (window.rawData) {\n for (const entry of Object.entries(window.rawData)) {\n const locale = entry[0];\n const stats = entry[1].metaData.stats;\n const stringsData = entry[1].stringsData;\n\n if (Object.keys(appData.metaData.stats).length) {\n for (const prop in stats) {\n appData.metaData.stats[prop] += stats[prop];\n }\n } else {\n appData.metaData.stats = {...stats};\n }\n\n appData.metaData.statsByLocale[locale] = stats;\n appData.stringsData[locale] = stringsData;\n }\n\n appData.locales = Object.keys(window.rawData);\n }\n else {\n appData.hasRuntimeError = true;\n }\n\n function SimpleDataStore() {\n this._getData = () => appData;\n\n this.ranSuccessfully = () => this.getLocales().length > 0;\n\n this.getTimestamp = () => this._getData().timeStamp;\n\n this.getAppName = () => this._getData().appName;\n\n this.isDefaultLocale = (locale) =>\n locale === this._getData().defaultLocale;\n\n this.getLocalesData = () => this._getData().stringsData || {};\n\n this.getLocales = () => this._getData().locales || [];\n\n this.getStatByLocale = (locale) =>\n this._getData().metaData.statsByLocale[locale] || {};\n\n this.getOverallStats = () => this._getData().metaData.stats || {};\n\n this.getDataByLocale = (locale) =>\n this._getData().stringsData[locale] || {};\n\n this.isSanityRun = () => this._getData().sanityRun;\n\n this.hasRuntimeError = () => this._getData().hasRuntimeError;\n }\n\n DataStore = new SimpleDataStore();\n })();`)(e)}\n (() => {\n // for sidebar menu\n // hide insights tab\n if(DataStore.hasRuntimeError() || !DataStore.ranSuccessfully()) {\n document.querySelectorAll('.menu-item[data-page="insights"]')?.remove();\n }\n\n const loadContent = (section, highlightMenu = false) => {\n if (highlightMenu) {\n document\n .querySelector('li[data-page="overview"]')\n ?.classList.add('selected');\n }\n\n const contents = document.querySelectorAll('.content');\n const wrapper = document.querySelector('.content-wrapper');\n\n contents.forEach((content) => {\n content.id !== section\n ? content.classList.remove('active')\n : content.classList.add('active');\n\n section === 'overview' &&\n window.persistOverviewCharts &&\n window.persistOverviewCharts();\n\n ['log', 'locale'].includes(section) ? wrapper.classList.add('--hide-overflow') : wrapper.classList.remove('--hide-overflow');\n window.currentPage = section;\n });\n };\n\n document.addEventListener('DOMContentLoaded', function () {\n const createMenuItems = (() => {\n const ul = document.querySelector('.sidebar .submenu');\n const createListItems = (locale) => {\n const li = document.createElement('li');\n li.classList.add('sub-menu-item');\n li.dataset.locale = locale;\n\n const a = document.createElement('a');\n a.href = '#';\n a.textContent = locale;\n\n li.appendChild(a);\n return li;\n };\n\n for (const locale of DataStore.getLocales()) {\n ul.appendChild(createListItems(locale));\n }\n })();\n\n const menuItems = document.querySelectorAll('.menu-item'),\n submenuItems = document.querySelectorAll('.sub-menu-item');\n\n menuItems.forEach((item) => {\n item.addEventListener('click', function (event) {\n const selectedMenuItem = document.querySelector(\n '.menu-item.selected'\n ),\n selectedSubmenu = document.querySelector('.submenu.active'),\n page = item.dataset.page;\n\n if (selectedMenuItem) {\n selectedMenuItem.classList.remove('selected');\n }\n\n if (selectedSubmenu) {\n selectedSubmenu.classList.remove('active');\n }\n\n if (item.classList.contains('has-submenu')) {\n event.preventDefault();\n item.classList.add('selected');\n const submenu = item.querySelector('.submenu');\n submenu.classList.add('active');\n } else {\n item.classList.add('selected');\n }\n\n if (selectedSubmenu) {\n selectedSubmenu\n .querySelectorAll('.sub-menu-item')\n .forEach((submenuItem) => {\n submenuItem.textContent !== item.textContent &&\n submenuItem.classList.remove('selected');\n });\n }\n\n loadContent(page);\n });\n\n loadContent('overview', true);\n });\n\n submenuItems.forEach((sItem) => {\n sItem.addEventListener('click', function (event) {\n const selectedSubMenuItem = document.querySelector(\n '.sub-menu-item.selected'\n );\n event.preventDefault();\n event.stopPropagation();\n\n if (selectedSubMenuItem) {\n selectedSubMenuItem.classList.remove('selected');\n window.previousSelectedLocale =\n selectedSubMenuItem.dataset.locale;\n }\n\n sItem.classList.add('selected');\n loadContent('locale');\n });\n });\n\n // update footer info\n const footer = document.querySelector('.sidebar .footer');\n footer.textContent = \`\${new Date().getFullYear()} @ Zeesoft. All rights reserved.\`;\n\n // update project info\n document.querySelector(\n 'header .logo'\n ).innerHTML = \`zAutomate.AI | \${DataStore.getAppName()} [\${DataStore.isSanityRun() ? 'Quick Sanity' : 'I18n Verification'}]<span class="project-info"><span class="time">Report generated at: \${DataStore.getTimestamp()}</span></span>\`;\n });\n })();\n //overview content\n (() => {\n if (DataStore.hasRuntimeError()) {\n document.getElementById('overview').innerHtml =\n 'zAutomate.AI was unable to perform the opertaion. Please check the logs for more information.';\n return;\n }\n\n document.addEventListener('DOMContentLoaded', function () {\n let overviewChart,\n stringChart,\n dateTimeChart,\n numberChart,\n ignoredChart;\n\n window.persistOverviewCharts = () => {\n const reset = (chart) => {\n chart.resetSeries(true, true);\n };\n\n reset(overviewChart);\n reset(stringChart);\n reset(dateTimeChart);\n reset(numberChart);\n reset(ignoredChart);\n };\n\n renderOverallChart();\n renderStringChart();\n renderIgnoredChart();\n renderNumberChart();\n renderDatetimeChart();\n\n function renderOverallChart() {\n const overallStats = DataStore.getOverallStats();\n const reviewed = overallStats.reviewed;\n const locales = DataStore.getLocales().length;\n const type = {\n I18NED: 'Internationalized',\n NOT_I18NED: 'Not Internationalized',\n SKIPPED: 'Skipped'\n },\n valueMap = {\n [type.I18NED]:\n overallStats.localizedStrings +\n overallStats.partialStrings + // TODO: need to confirm\n overallStats.untranslatedStrings +\n overallStats.localizedDateTime +\n overallStats.localizedDate +\n overallStats.localizedTime +\n overallStats.localizedNumber +\n overallStats.localizedCurrency +\n overallStats.localizedPercentage,\n [type.NOT_I18NED]:\n overallStats.notLocalizedStrings +\n overallStats.notLocalizedDateTime +\n overallStats.notLocalizedDate +\n overallStats.notLocalizedTime +\n overallStats.notLocalizedNumber +\n overallStats.notLocalizedCurrency +\n overallStats.notLocalizedPercentage,\n [type.SKIPPED]:\n overallStats.dnt +\n overallStats.ignored +\n overallStats.autoIgnored +\n overallStats.userInput\n },\n percentageCalc = (value) => {\n const val = ((value / reviewed) * 100).toFixed(0);\n return isNaN(val) || !isFinite(val) ? 0 : val;\n };\n\n var options = {\n series: [\n {\n name: '',\n data: [\n percentageCalc(valueMap[type.I18NED]),\n percentageCalc(valueMap[type.NOT_I18NED]),\n percentageCalc(valueMap[type.SKIPPED])\n ]\n }\n ],\n chart: {\n type: 'bar',\n height: 200,\n toolbar: {\n show: false\n },\n animations: {\n enabled: true,\n easing: 'easeinout',\n speed: 800,\n animateGradually: {\n enabled: true,\n delay: 150\n },\n dynamicAnimation: {\n enabled: true,\n speed: 350\n }\n }\n },\n plotOptions: {\n bar: {\n horizontal: true,\n borderRadius: 3,\n dataLabels: {\n position: 'right'\n }\n }\n },\n title: {\n text: \`Total Reviewed strings in \${locales} locales: \${reviewed}\`,\n align: 'center',\n floating: true,\n style: {\n fontSize: '14px',\n fontWeight: 'bold'\n }\n },\n dataLabels: {\n enabled: true,\n style: {\n colors: ['#080404b0']\n },\n formatter: (val) => {\n return \`\${val}%\`;\n }\n },\n xaxis: {\n categories: [type.I18NED, type.NOT_I18NED, type.SKIPPED],\n min: 0,\n max: 100,\n labels: {\n formatter: (v) => \`\${v}%\`\n }\n },\n yaxis: {\n labels: {\n style: {\n fontSize: '13px'\n }\n }\n },\n colors: [\n (v) => {\n switch (v.dataPointIndex) {\n case 0:\n return '#31E994'; //green\n case 1:\n return '#ff8173'; //red\n case 2:\n return '#f5eb5f'; //yellow\n }\n }\n ],\n tooltip: {\n theme: 'dark',\n x: {\n formatter: (v) => \`Total Number of \${v} instances:\`\n },\n y: {\n formatter: function (v, { dataPointIndex }) {\n let count = 0;\n switch (dataPointIndex) {\n case 0:\n count = valueMap[type.I18NED];\n break;\n case 1:\n count = valueMap[type.NOT_I18NED];\n break;\n case 2:\n count = valueMap[type.SKIPPED];\n break;\n }\n return \`\${v}% (\${count} strings)\`;\n }\n }\n }\n };\n\n (overviewChart = new ApexCharts(\n document.querySelector('.overall-quality .graph'),\n options\n )).render();\n }\n\n function renderStringChart() {\n const overallStats = DataStore.getOverallStats();\n const type = {\n LOCALIZED: 'Localized',\n PARTIAL: 'Partially Localized',\n NOT_LOCALIZED: 'Not Localized',\n UNTRANSLATED: 'Untranslated',\n ENCODING: 'Encoding Issue',\n IGNORED: 'Ignored'\n },\n valueMap = {\n [type.LOCALIZED]: overallStats.localizedStrings,\n [type.PARTIAL]: overallStats.partialStrings,\n [type.NOT_LOCALIZED]: overallStats.notLocalizedStrings,\n [type.UNTRANSLATED]: overallStats.untranslatedStrings,\n [type.ENCODING]: overallStats.encoding,\n [type.IGNORED]:\n overallStats.dnt +\n overallStats.ignored +\n overallStats.autoIgnored +\n overallStats.userInput\n },\n total = Object.values(valueMap).reduce(\n (acc, curr) => acc + curr,\n 0\n ),\n data = [\n valueMap[type.LOCALIZED],\n valueMap[type.PARTIAL],\n valueMap[type.NOT_LOCALIZED],\n valueMap[type.IGNORED],\n valueMap[type.ENCODING],\n valueMap[type.UNTRANSLATED]\n ],\n options = {\n series:\n data.reduce((acc, curr) => acc + curr, 0) === 0 ? [] : data,\n chart: {\n width: 415,\n type: 'pie',\n animations: {\n enabled: true,\n easing: 'easeinout',\n speed: 800,\n animateGradually: {\n enabled: true,\n delay: 150\n },\n dynamicAnimation: {\n enabled: true,\n speed: 350\n }\n }\n },\n noData: {\n text: 'No metrics available',\n align: 'left',\n verticalAlign: 'middle',\n offsetX: 0,\n offsetY: -50,\n style: {\n fontSize: '14px'\n }\n },\n labels: [\n type.LOCALIZED,\n type.PARTIAL,\n type.NOT_LOCALIZED,\n type.IGNORED,\n type.ENCODING,\n type.UNTRANSLATED\n ],\n tooltip: {\n theme: 'dark',\n y: {\n formatter: function (v, { config, dataPointIndex }) {\n let count = 0,\n value = Number(\n (v /\n config.series.reduce((acc, curr) => acc + curr, 0)) *\n 100\n ).toFixed(0);\n value = isNaN(value) || !isFinite(value) ? 0 : value;\n\n switch (dataPointIndex) {\n case 0:\n count = valueMap[type.LOCALIZED];\n break;\n case 1:\n count = valueMap[type.PARTIAL];\n break;\n case 2:\n count = valueMap[type.NOT_LOCALIZED];\n break;\n case 3:\n count = valueMap[type.IGNORED];\n break;\n case 4:\n count = valueMap[type.ENCODING];\n break;\n case 5:\n count = valueMap[type.UNTRANSLATED];\n break;\n }\n\n return \`\${value}% (\${count} strings)\`;\n },\n title: {\n formatter: function (a) {\n return \`Total Number of \${a} strings:\`;\n }\n }\n }\n },\n colors: [\n ({ seriesIndex, w }) => {\n const currType = w.config.labels[seriesIndex];\n\n switch (currType) {\n case type.LOCALIZED:\n return '#31E994';\n case type.NOT_LOCALIZED:\n return '#E44242';\n case type.PARTIAL:\n return '#DADF40';\n case type.UNTRANSLATED:\n return '#F44E9E';\n case type.IGNORED:\n return '#AFA6AB';\n case type.ENCODING:\n return '#3AD1F3';\n\n default:\n return '';\n }\n }\n ],\n legend: {\n offsetX: -50,\n width: 170,\n formatter: (seriesName, a, b, c) => {\n let value = ((valueMap[seriesName] / total) * 100).toFixed(0);\n value = isNaN(value) || !isFinite(value) ? 0 : value;\n return \`\${seriesName} (\${value}%)\`;\n }\n },\n dataLabels: {\n formatter: (v) => \`\${Number(v).toFixed(0)}%\`,\n dropShadow: { enabled: false },\n style: {\n colors: ['#080404b0']\n }\n }\n };\n\n (stringChart = new ApexCharts(\n document.querySelector('.string-quality .graph'),\n options\n )).render();\n }\n\n function renderIgnoredChart() {\n const overallStats = DataStore.getOverallStats();\n const type = {\n DNT: 'DNT',\n IGNORED: 'Ignored',\n USER_INPUTS: 'User Inputs'\n },\n valueMap = {\n [type.DNT]: overallStats.dnt,\n [type.IGNORED]: overallStats.ignored + overallStats.autoIgnored,\n [type.USER_INPUTS]: overallStats.userInput\n },\n total = Object.values(valueMap).reduce(\n (acc, curr) => acc + curr,\n 0\n ),\n data = [\n valueMap[type.DNT],\n valueMap[type.IGNORED],\n valueMap[type.USER_INPUTS]\n ],\n options = {\n series:\n data.reduce((acc, curr) => acc + curr, 0) === 0 ? [] : data,\n chart: {\n width: 360,\n type: 'pie',\n animations: {\n enabled: true,\n easing: 'easeinout',\n speed: 800,\n animateGradually: {\n enabled: true,\n delay: 150\n },\n dynamicAnimation: {\n enabled: true,\n speed: 350\n }\n }\n },\n labels: [type.DNT, type.IGNORED, type.USER_INPUTS],\n tooltip: {\n theme: 'dark',\n y: {\n formatter: function (v, { config, dataPointIndex }) {\n let count = 0,\n value = Number(\n (v /\n config.series.reduce((acc, curr) => acc + curr, 0)) *\n 100\n ).toFixed(0);\n value = isNaN(value) || !isFinite(value) ? 0 : value;\n\n switch (dataPointIndex) {\n case 0:\n count = valueMap[type.DNT];\n break;\n case 1:\n count = valueMap[type.IGNORED];\n break;\n case 2:\n count = valueMap[type.USER_INPUTS];\n break;\n }\n\n return \`\${value}% (\${count} strings)\`;\n },\n title: {\n formatter: function (a) {\n return \`Total Number of \${a} strings:\`;\n }\n }\n }\n },\n colors: [\n ({ seriesIndex, w }) => {\n const currType = w.config.labels[seriesIndex];\n\n switch (currType) {\n case type.DNT:\n return '#31E994';\n case type.IGNORED:\n return '#3AD1F3';\n case type.USER_INPUTS:\n return '#DADF40';\n\n default:\n return '';\n }\n }\n ],\n noData: {\n text: 'No metrics available',\n align: 'center',\n verticalAlign: 'middle',\n offsetX: -70,\n offsetY: -25,\n style: {\n fontSize: '14px'\n }\n },\n legend: {\n offsetX: -40,\n formatter: (seriesName) => {\n let value = ((valueMap[seriesName] / total) * 100).toFixed(0);\n value = isNaN(value) || !isFinite(value) ? 0 : value;\n return \`\${seriesName} (\${value}%)\`;\n }\n },\n dataLabels: {\n formatter: (v) => \`\${Number(v).toFixed(0)}%\`,\n style: {\n colors: ['#080404b0']\n },\n dropShadow: { enabled: false }\n }\n };\n\n (ignoredChart = new ApexCharts(\n document.querySelector('.skipped-items .graph'),\n options\n )).render();\n }\n\n function renderNumberChart() {\n const overallStats = DataStore.getOverallStats();\n const types = ['Number', 'Currency', 'Percentage'],\n data = {\n number_i18n: overallStats.localizedNumber,\n currency_i18n: overallStats.localizedCurrency,\n percentage_i18n: overallStats.localizedPercentage,\n number_not_i18n: overallStats.notLocalizedNumber,\n currency_not_i18n: overallStats.notLocalizedCurrency,\n percentage_not_i18n: overallStats.notLocalizedPercentage\n },\n total = Object.values(data).reduce((acc, curr) => acc + curr, 0),\n percentageCalc = (v, t) => {\n const val = ((v / t) * 100).toFixed(0);\n return isNaN(val) || !isFinite(val) ? 0 : val;\n },\n i18nPercentage = percentageCalc(\n data.number_i18n + data.percentage_i18n + data.currency_i18n,\n total\n ),\n nonI18nPercentage = percentageCalc(\n data.number_not_i18n +\n data.percentage_not_i18n +\n data.currency_not_i18n,\n total\n ),\n numberTotal = data.number_i18n + data.number_not_i18n,\n currencyTotal = data.currency_i18n + data.currency_not_i18n,\n percentageTotal = data.percentage_i18n + data.percentage_not_i18n,\n numberI18n = percentageCalc(data.number_i18n, numberTotal),\n currencyI18n = percentageCalc(data.currency_i18n, currencyTotal),\n percentageI18n = percentageCalc(\n data.percentage_i18n,\n currencyTotal\n ),\n numberNotI18n = percentageCalc(data.number_not_i18n, numberTotal),\n currencyNotI18n = percentageCalc(\n data.currency_not_i18n,\n currencyTotal\n ),\n percentageNotI18n = percentageCalc(\n data.percentage_not_i18n,\n currencyTotal\n ),\n options = {\n series: [\n {\n name: 'Internationalized',\n data: [numberI18n, currencyI18n, percentageI18n]\n },\n {\n name: 'Not Internationalized',\n data: [numberNotI18n, currencyNotI18n, percentageNotI18n]\n }\n ],\n chart: {\n type: 'bar',\n height: 220,\n width: 500,\n toolbar: {\n show: false\n },\n animations: {\n enabled: true,\n easing: 'easeinout',\n speed: 800,\n animateGradually: {\n enabled: true,\n delay: 150\n },\n dynamicAnimation: {\n enabled: true,\n speed: 350\n }\n }\n },\n dataLabels: {\n enabled: true,\n dropShadow: { enabled: false },\n style: {\n colors: ['#080404b0']\n },\n formatter: (val) => {\n return \`\${val}%\`;\n }\n },\n stroke: {\n show: true,\n width: 1,\n colors: ['#fff']\n },\n tooltip: {\n theme: 'dark',\n shared: true,\n intersect: false,\n x: {\n formatter: (type) => \`\${type} instances:\`\n },\n y: {\n formatter: (v, { seriesIndex, dataPointIndex }) => {\n const getI18nCount = (type) => {\n switch (type) {\n case 'number':\n return data.number_i18n;\n case 'currency':\n return data.currency_i18n;\n case 'percentage':\n return data.percentage_i18n;\n }\n },\n getNonI18nCount = (type) => {\n switch (type) {\n case 'number':\n return data.number_not_i18n;\n case 'currency':\n return data.currency_not_i18n;\n case 'percentage':\n return data.percentage_not_i18n;\n }\n },\n getCount = (type) => {\n return seriesIndex === 0\n ? getI18nCount(type)\n : getNonI18nCount(type);\n };\n\n switch (dataPointIndex) {\n case 0:\n return getCount('number');\n case 1:\n return getCount('currency');\n case 2:\n return getCount('percentage');\n }\n }\n }\n },\n xaxis: {\n categories: types\n },\n yaxis: {\n min: 0,\n max: 100,\n labels: {\n formatter: (v) => \`\${v}%\`\n }\n },\n colors: ['#31E994', '#ff8173'],\n legend: {\n offsetX: -13,\n position: 'right',\n formatter: (seriesName) => {\n if (seriesName === 'Internationalized') {\n return \`\${seriesName} (\${i18nPercentage}%)\`;\n }\n return \`\${seriesName} (\${nonI18nPercentage}%)\`;\n }\n },\n plotOptions: {\n bar: {\n borderRadius: 3,\n columnWidth: '85%'\n }\n }\n };\n\n (numberChart = new ApexCharts(\n document.querySelector('.number-quality .graph'),\n options\n )).render();\n }\n\n function renderDatetimeChart() {\n const overallStats = DataStore.getOverallStats();\n const types = ['Date', 'Time', 'DateTime'],\n data = {\n date_i18n: overallStats.localizedDate,\n time_i18n: overallStats.localizedTime,\n date_time_i18n: overallStats.localizedDateTime,\n date_not_i18n: overallStats.notLocalizedDate,\n time_not_i18n: overallStats.notLocalizedTime,\n date_time_not_i18n: overallStats.notLocalizedDateTime\n },\n total = Object.values(data).reduce((acc, curr) => acc + curr, 0),\n percentageCalc = (v, t) => {\n const val = ((v / t) * 100).toFixed(0);\n return isNaN(val) || !isFinite(val) ? 0 : val;\n },\n i18nPercentage = percentageCalc(\n data.date_i18n + data.time_i18n + data.date_time_i18n,\n total\n ),\n nonI18nPercentage = percentageCalc(\n data.date_not_i18n + data.time_not_i18n + data.date_time_not_i18n,\n total\n ),\n dateTotal = data.date_i18n + data.date_not_i18n,\n timeTotal = data.time_i18n + data.time_not_i18n,\n dateTimeTotal = data.date_time_i18n + data.date_time_not_i18n,\n dateI18n = percentageCalc(data.date_i18n, dateTotal),\n timeI18n = percentageCalc(data.time_i18n, timeTotal),\n dateTimeI18n = percentageCalc(data.date_time_i18n, dateTimeTotal),\n dateNotI18n = percentageCalc(data.date_not_i18n, dateTotal),\n timeNotI18n = percentageCalc(data.time_not_i18n, timeTotal),\n dateTimeNotI18n = percentageCalc(\n data.date_time_not_i18n,\n dateTimeTotal\n ),\n options = {\n series: [\n {\n name: 'Internationalized',\n data: [dateI18n, timeI18n, dateTimeI18n]\n },\n {\n name: 'Not Internationalized',\n data: [dateNotI18n, timeNotI18n, dateTimeNotI18n]\n }\n ],\n chart: {\n type: 'bar',\n height: 220,\n width: 500,\n toolbar: {\n show: false\n },\n animations: {\n enabled: true,\n easing: 'easeinout',\n speed: 800,\n animateGradually: {\n enabled: true,\n delay: 150\n },\n dynamicAnimation: {\n enabled: true,\n speed: 350\n }\n }\n },\n dataLabels: {\n enabled: true,\n dropShadow: { enabled: false },\n style: {\n colors: ['#080404b0']\n },\n formatter: (val) => {\n return \`\${val}%\`;\n }\n },\n stroke: {\n show: true,\n width: 1,\n colors: ['#fff']\n },\n tooltip: {\n theme: 'dark',\n shared: true,\n intersect: false,\n x: {\n formatter: (type) => \`\${type} instances:\`\n },\n y: {\n formatter: (v, { seriesIndex, dataPointIndex }) => {\n const getI18nCount = (type) => {\n switch (type) {\n case 'date':\n return data.date_i18n;\n case 'time':\n return data.time_i18n;\n case 'date_time':\n return data.date_time_i18n;\n }\n },\n getNonI18nCount = (type) => {\n switch (type) {\n case 'date':\n return data.date_not_i18n;\n case 'time':\n return data.time_not_i18n;\n case 'date_time':\n return data.date_time_not_i18n;\n }\n },\n getCount = (type) => {\n return seriesIndex === 0\n ? getI18nCount(type)\n : getNonI18nCount(type);\n };\n\n switch (dataPointIndex) {\n case 0:\n return getCount('date');\n case 1:\n return getCount('time');\n case 2:\n return getCount('date_time');\n }\n }\n }\n },\n xaxis: {\n categories: types\n },\n yaxis: {\n min: 0,\n max: 100,\n labels: {\n formatter: (v) => \`\${v}%\`\n }\n },\n colors: ['#31E994', '#ff8173'],\n legend: {\n offsetX: 4,\n position: 'right',\n formatter: (seriesName) => {\n if (seriesName === 'Internationalized') {\n return \`\${seriesName} (\${i18nPercentage}%)\`;\n }\n return \`\${seriesName} (\${nonI18nPercentage}%)\`;\n }\n },\n plotOptions: {\n bar: {\n borderRadius: 3,\n columnWidth: '85%'\n }\n }\n };\n\n (dateTimeChart = new ApexCharts(\n document.querySelector('.datetime-quality .graph'),\n options\n )).render();\n }\n });\n })();\n // insights content\n (() => {\n if (!DataStore.ranSuccessfully()) {\n document.getElementById('overview').innerHTML =\n 'Unable to prepare zQA automation report for the project.';\n return;\n }\n\n document.addEventListener('DOMContentLoaded', function () {\n renderCards();\n\n // helper methods to generate cards and its sections\n function createStatSection(locale, data) {\n const holder = document.createElement('div');\n const table = document.createElement('table');\n const tbody = document.createElement('tbody');\n const name = document.createElement('div');\n const tableData = {\n 'Internationlized Strings':\n data.localizedStrings +\n data.untranslatedStrings +\n data.partialStrings,\n 'Not Internationlized Strings': data.notLocalizedStrings,\n 'Internationlized Numbers': data.localizedNumber,\n 'Not Internationlized Numbers': data.notLocalizedNumber,\n 'Internationlized Currency': data.localizedCurrency,\n 'Not Internationlized Currency': data.notLocalizedCurrency,\n 'Internationlized Percentage': data.localizedPercentage,\n 'Not Internationlized Percentage': data.notLocalizedPercentage,\n 'Internationlized Date': data.localizedDate,\n 'Not Internationlized Date': data.notLocalizedDate,\n 'Internationlized Time': data.localizedTime,\n 'Not Internationlized Time': data.notLocalizedTime,\n 'Internationlized DateTime': data.localizedDate,\n 'Not Internationlized DateTime': data.notLocalizedDateTime,\n 'Encoding Issue Strings': data.encoding,\n 'DNT Strings': data.dnt,\n 'Ignored Strings': data.ignored,\n 'Untranslated Strings': data.untranslatedStrings,\n 'Auto Ignored Strings': data.autoIgnored,\n 'User Input Strings': data.userInput,\n 'Total Reviewed': data.reviewed\n };\n const addRow = (name, value) => {\n const row = document.createElement('tr');\n\n const col1 = document.createElement('td');\n col1.classList.add('name');\n col1.textContent = name;\n\n const col2 = document.createElement('td');\n col2.classList.add('value');\n col2.textContent = value;\n\n row.appendChild(col1);\n row.appendChild(col2);\n return row;\n };\n\n for (const rowData of Object.entries(tableData)) {\n if (!DataStore.isSanityRun() || !DataStore.isDefaultLocale(locale) || rowData[0] !== 'Untranslated Strings') {\n tbody.appendChild(addRow(rowData[0], rowData[1]));\n }\n }\n\n holder.classList.add('stat');\n name.classList.add('name');\n name.textContent = 'Summary';\n holder.append(name);\n\n table.appendChild(tbody);\n holder.appendChild(table);\n return holder;\n }\n\n function createStatusBarSection(locale, data) {\n const holder = document.createElement('div');\n holder.classList.add('status-bar');\n\n const generateBarEl = (name, total, current) => {\n const getColorClass = (value) => {\n if (value <= 25) {\n return 'red';\n } else if (value <= 50) {\n return 'yellow';\n } else if (value <= 75) {\n return 'blue';\n } else if (value <= 100) {\n return 'green';\n }\n };\n current = (current / total) * 100;\n current = isNaN(current) || !isFinite(current) ? 0 : current;\n const holder = document.createElement('div');\n holder.classList.add('bar-container');\n\n const nameHolder = document.createElement('div');\n nameHolder.classList.add('name');\n nameHolder.textContent = name;\n\n const barHolder = document.createElement('div');\n barHolder.classList.add('bar-holder');\n\n const bar = document.createElement('div');\n bar.classList.add('bar');\n bar.classList.add(\`--\${getColorClass(current)}\`);\n bar.style.width = \`\${current}%\`;\n bar.textContent = \`\${current.toFixed(0)}%\`;\n\n barHolder.appendChild(bar);\n holder.appendChild(nameHolder);\n holder.appendChild(barHolder);\n\n return holder;\n };\n\n const showFull = DataStore.isSanityRun() || DataStore.isDefaultLocale(locale),\n totalI18nCount = showFull\n ? 100\n : data.localizedStrings +\n data.untranslatedStrings +\n data.partialStrings +\n data.notLocalizedStrings,\n i18nStrings = showFull\n ? 100\n : data.localizedStrings +\n data.untranslatedStrings +\n data.partialStrings,\n totalLocCount = showFull\n ? 100\n : totalI18nCount -\n data.untranslatedStrings -\n data.notLocalizedStrings,\n totalNumberCount = showFull\n ? 100\n : data.localizedNumber +\n data.localizedCurrency +\n data.localizedPercentage +\n data.notLocalizedPercentage +\n data.notLocalizedCurrency +\n data.notLocalizedNumber,\n i18nNumbers = showFull\n ? 100\n : totalNumberCount -\n data.notLocalizedPercentage -\n data.notLocalizedCurrency -\n data.notLocalizedNumber,\n totalI18nDateTimeCount = showFull\n ? 100\n : data.localizedDate +\n data.localizedDateTime +\n data.localizedTime +\n data.notLocalizedDate +\n data.notLocalizedDateTime +\n data.notLocalizedTime,\n i18nDateTime = showFull\n ? 100\n : totalI18nDateTimeCount -\n data.notLocalizedDate -\n data.notLocalizedDateTime -\n data.notLocalizedTime;\n\n holder.appendChild(\n generateBarEl('String I18n level', totalI18nCount, i18nStrings)\n );\n\n holder.appendChild(\n generateBarEl('String L10n level', totalI18nCount, totalLocCount)\n );\n\n holder.appendChild(\n generateBarEl('Number I18n level', totalNumberCount, i18nNumbers)\n );\n\n holder.appendChild(\n generateBarEl(\n 'DateTime I18n level',\n totalI18nDateTimeCount,\n i18nDateTime\n )\n );\n return holder;\n }\n\n function generateCardContents(locale, data) {\n const cardContent = document.createElement('div');\n cardContent.classList.add('card-content');\n\n cardContent.appendChild(createStatusBarSection(locale, data));\n cardContent.appendChild(createStatSection(locale, data));\n return cardContent;\n }\n\n function createCardEl(locale, data) {\n const card = document.createElement('div');\n const title = document.createElement('div');\n card.classList.add('card');\n card.dataset.locale = locale;\n\n if(window.reducedZoom) {\n card.classList.add('--reduced-zoom');\n }\n\n title.classList.add('title');\n title.textContent = \`\${locale} details\`;\n\n // fire menu selection event on clicking the card\n card.addEventListener('click', () => {\n const previousSelectedSubMenu = document.querySelector(\n '.sub-menu-item.selected'\n );\n if (previousSelectedSubMenu) {\n window.previousSelectedLocale =\n previousSelectedSubMenu.dataset.locale;\n }\n\n document\n .querySelector(\`.sub-menu-item[data-locale="\${locale}"]\`)\n .click();\n });\n\n card.appendChild(title);\n card.appendChild(generateCardContents(locale, data));\n return card;\n }\n\n function renderCards() {\n // read from global variable appData;\n const localeInfo = DataStore.getLocalesData();\n\n if (Object.keys(localeInfo).length) {\n const cardHolder = document.querySelector(\n '#insights .cards .holder'\n );\n for (const locale in localeInfo) {\n const cardEl = createCardEl(\n locale,\n DataStore.getStatByLocale(locale)\n );\n cardHolder.appendChild(cardEl);\n }\n }\n }\n });\n })();\n // locale grid\n (() => {\n if (!DataStore.ranSuccessfully()) {\n return;\n }\n\n document.addEventListener('DOMContentLoaded', function () {\n let table;\n document.querySelectorAll('.sub-menu-item').forEach((menu) => {\n menu.addEventListener('click', (e) => {\n render(e.currentTarget.dataset.locale);\n });\n });\n\n const updateTitle = (locale) => {\n document.querySelector(\n '#locale .title'\n ).textContent = \`\${locale} I18n Coverage Details\`;\n };\n\n const buildGrid = (locale) => {\n const data = DataStore.getDataByLocale(locale) || {};\n $.fn.dataTable.ext.errMode = 'none';\n const dataSet = [];\n Object.entries(data).map((entry) =>\n entry[1].forEach(\n (v) =>\n (v.type !== 'REVIEWED' || DataStore.isSanityRun()) &&\n dataSet.push([entry[0], v.type, v.description, v.imagePath])\n )\n );\n const containerHeight = document\n .querySelector('#locale')\n .getBoundingClientRect().height;\n const scrollHeight = (72 / 100) * containerHeight;\n table = new DataTable('#locale .coverage-info table', {\n columns: [\n { title: 'String' },\n { title: 'Type' },\n { title: 'Page' },\n { title: 'Screenshot' }\n ],\n columnDefs: [\n {\n width: '44%',\n targets: 0\n },\n {\n width: '18%',\n targets: 1\n },\n {\n width: '18%',\n targets: 2\n },\n {\n width: '18%',\n targets: 3,\n orderable: false,\n searchable: false,\n data: null,\n render: function (data) {\n return \`<a href="#" class="view-screenshot-btn" onclick="openImageViewer('\${data[3]}')"><img title="View screenshot for '\${data[2]}'" class="view-screenshot-image"></img></a>\`;\n },\n className: 'dt-head-center dt-body-center'\n }\n ],\n data: dataSet,\n initComplete: function () {\n this.api()\n .columns()\n .every(function () {\n const column = this;\n\n if (column[0][0] === 3) {\n return;\n }\n\n const select = $(\n '<select class="filter dt-input"><option value="">Filter By</option></select>'\n )\n .appendTo($(column.header()).before())\n .on('change', function () {\n const val = $.fn.dataTable.util.escapeRegex(\n $(this).val()\n );\n\n column\n .search(val ? '^' + val + '$' : '', true, false)\n .draw();\n })\n .on('click', function (e) {\n e.stopPropagation();\n e.stopImmediatePropagation();\n });\n\n column\n .data()\n .unique()\n .sort()\n .each(function (d, j) {\n select.append(\n '<option value="' + d + '">' + d + '</option>'\n );\n });\n });\n },\n sScrollY: scrollHeight,\n pageLength: 25,\n lengthMenu: [10, 25, 50, 100]\n });\n };\n\n const render = (locale) => {\n if (table) {\n table.destroy();\n }\n updateTitle(locale);\n buildGrid(locale);\n };\n });\n })();\n\n // log content\n (() => {\n document.addEventListener('DOMContentLoaded', function () {\n const pre = document.querySelector('#log .log-content pre');\n pre.textContent = 'Loading...';\n document\n .querySelector('li[data-page="log"]')\n ?.addEventListener('click', (e) => {\n pre.textContent = window.logData || (DataStore.hasRuntimeError() ? 'We are facing internal issue. Please try again after sometime.' : 'No log data found!');\n });\n });\n })();`,n=[],a=Ce(it.getReportPath(),"logs","log"),r=!0===yt.getOptions()?.sanityCapture,i=yt.getOptions()?.supportedLocales?.map((e=>ze(e))),s=Ee(it.getReportPath()).filter((e=>i.includes(e))),o=1===s.length&&s[0]===ze(yt.getDefaultLocale());let l="";if(s.forEach((t=>(t!==e.defaultLocale||t===e.defaultLocale&&o||r)&&De(Ce(it.getReportPath(),t,be))&&n.push(Ce(t,be).replace(/\\/g,"/")))),De(a)){const t=[e.appName,...yt.getL10nReportsPath().split(/[\\/]+/g)];t.push(it.getReportTimeStamp()),l=Ie(a).replace(new RegExp(it.getReportPath().replace(/\\/g,"\\\\"),"g"),Ce(...t)).replace(/\\/g,"\\\\").replace(/`/g,"\\`")}return function({appName:e,reportTime:t,script:n,style:a,body:r,dataFilePaths:i=[],logData:s}){return`<!DOCTYPE html>\n<html lang="en">\n <head>\n <meta charset="UTF-8" />\n <meta name="charset" content="charset='UTF-8'" />\n <meta name="viewport" content="width=device-width, initial-scale=1.0" />\n <meta name="company" content="Zeesoft" />\n <meta name="product" content="zAutomate.AI" />\n <meta name="author" content="Jitendra Maheshwari" />\n <meta name="email" content="jm@zeesoft.com" />\n <meta\n name="description"\n content="zAutomate.AI report"\n />\n <title>${e} - zAutomate.AI report | ${t}</title>\n \x3c!-- 3rd party dependencies --\x3e\n <link\n rel="stylesheet"\n href="https://cdn.datatables.net/2.0.3/css/dataTables.dataTables.min.css"\n />\n ${i.map((e=>`<script\n src="${e}"\n type="text/javascript">\n <\/script>`)).join("")}\n ${s?`<script type="text/javascript" async/>window.logData = \`${s}\`;<\/script>`:""}\n <script\n src="https://code.jquery.com/jquery-3.7.1.slim.min.js"\n integrity="sha256-kmHvs0B+OpCW5GVHUNjv9rOmY0IvSIRcf7zGUDTDQM8="\n crossorigin="anonymous"\n defer\n ><\/script>\n <script src="https://cdn.jsdelivr.net/npm/apexcharts" defer><\/script>\n <script\n src="https://cdn.datatables.net/2.0.3/js/dataTables.min.js"\n defer\n ><\/script>\n <style>\n ${a}\n </style>\n </head>\n <body>\n ${r}\n </body>\n <script type="text/javascript" defer>\n ${n}\n <\/script>\n</html>\n`}({appName:e.appName,reportTime:e.reportTime,body:'<header><div class="logo">zAutomate.AI</div></header>\n <main>\n <div class="sidebar">\n <ul class="menu" id="menu">\n <li class="menu-item" data-page="overview">\n <a href="#">Overview</a>\n </li>\n <li class="menu-item" data-page="log">\n <a href="#">View Log</a>\n </li>\n <li class="menu-item has-submenu" data-page="insights">\n <a href="#" data-page="insights">Insights</a>\n <ul class="submenu"></ul>\n </li>\n </ul>\n <div class="footer"></div>\n </div>\n <div class="content-wrapper">\n <div id="overview" class="content">\n <div class="overall-quality card">\n <span class="title">Overall I18n Coverage</span>\n <div class="section">\n <div class="block">\n <article>\n <p class="desc">\n zI18n-Verify report provides a comprehensive information\n about the I18n and L10n quailty of your application.\n </p>\n <ul class="items">\n <li>\n <h4>Reviewed:</h4>\n <p class="detail">\n Total strings which are captured and processed by\n zI18n-Verify.\n </p>\n </li>\n <li>\n <h4>Internationlized:</h4>\n <p class="detail">\n Different types of value like string, number, date-time\n which are properly Internationalized.\n </p>\n </li>\n <li>\n <h4>Not Internationalized:</h4>\n <p class="detail">\n Values which are not Internationalized. Also includes\n Partially Localized strings and Encoding Issues.\n </p>\n </li>\n <li>\n <h4>Skipped:</h4>\n <p class="detail">\n Values which are skipped from processing because they\n are listed in DNT / Ignored lists or contains Auto\n Ignored pattern / User input pattern.\n </p>\n </li>\n </ul>\n </article>\n </div>\n <div class="block">\n <div class="graph"></div>\n </div>\n </div>\n </div>\n <div class="string-quality card">\n <span class="title">String Coverage</span>\n <div class="graph"></div>\n </div>\n <div class="skipped-items card">\n <span class="title">Skipped Items</span>\n <div class="graph"></div>\n </div>\n <div class="number-quality card">\n <span class="title">Number Coverage</span>\n <div class="graph"></div>\n </div>\n <div class="datetime-quality card">\n <span class="title">DateTime Coverage</span>\n <div class="graph"></div>\n </div>\n </div>\n <div id="log" class="content">\n <span class="title">Runtime log</span>\n <div class="log-content"><pre></pre></div>\n </div>\n <div id="insights" class="content">\n <div class="cards">\n <span class="title">Locale Quality</span>\n <div class="holder"></div>\n </div>\n </div>\n <div id="locale" class="content">\n <span class="title">Locale Quality</span>\n <div class="coverage-info">\n <table class="row-border hover order-column stripe"></table>\n </div>\n <div id="imageViewer" class="image-viewer">\n <span class="close-button" onclick="closeImageViewer()"\n >&times;</span\n >\n <div class="image-container">\n <img id="imageView" src="" alt="Image" />\n </div>\n </div>\n </div>\n </div>\n </main>',script:t,style:"html {\n width: 100vw;\n height: 100vh;\n }\n\n * {\n user-select: none;\n }\n\n body {\n width: 100%;\n height: 100%;\n margin: 0;\n display: flex;\n flex-direction: column;\n font-family: Arial, sans-serif;\n font-family: 'Helvetica Neue', Arial, sans-serif;\n -webkit-font-smoothing: antialiased; /* Webkit-based browsers */\n -moz-osx-font-smoothing: grayscale; /* Firefox on OS X */\n font-smooth: always; /* Non-standard, some browsers */\n }\n\n header {\n background-color: #333;\n height: 8%;\n }\n\n main {\n display: flex;\n flex-direction: row;\n width: 100%;\n height: 92%\n }\n\n .sidebar {\n width: 16%;\n height: 100%;\n background-color: #333;\n color: #fff;\n padding: 20px;\n box-sizing: border-box;\n float: left;\n }\n\n .logo {\n letter-spacing: 0.1rem;\n color: #14cf96;\n font-weight: bold;\n padding-top: 1.4%;\n padding-left: 2.1%;\n font-size: 1.6rem;\n }\n\n .menu {\n list-style-type: none;\n padding: 0;\n margin: 0;\n }\n\n .menu-item {\n margin-bottom: 10px;\n }\n\n .menu-item a {\n color: #fff;\n text-decoration: none;\n display: block;\n padding: 10px;\n border-radius: 5px;\n font-size: 1.05rem;\n }\n\n .menu-item a:hover {\n background-color: #555;\n }\n\n .submenu {\n display: none;\n list-style-type: none;\n padding-left: 20px;\n }\n\n .menu-item.has-submenu > a::after {\n content: '⯆';\n float: right;\n margin-left: 5px;\n }\n\n .menu-item.has-submenu.selected > a::after {\n content: '⯅';\n float: right;\n margin-left: 5px;\n }\n\n .menu-item.selected > a {\n background-color: #555;\n }\n\n .submenu .sub-menu-item {\n margin: 3px auto;\n }\n\n .submenu .sub-menu-item a:hover {\n background-color: #777;\n }\n\n .submenu .sub-menu-item.selected a {\n background-color: #555 !important;\n }\n\n .submenu.active {\n display: block !important;\n }\n\n .view-screenshot-image {\n width: 100px;\n height: 30px;\n content: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBVcGxvYWRlZCB0bzogU1ZHIFJlcG8sIHd3dy5zdmdyZXBvLmNvbSwgR2VuZXJhdG9yOiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4NCjxzdmcgZmlsbD0iIzAwMDAwMCIgaGVpZ2h0PSI4MDBweCIgd2lkdGg9IjgwMHB4IiB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIA0KCSB2aWV3Qm94PSIwIDAgNDkwIDQ5MCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8cGF0aCBkPSJNMjQ1LjIwNCwxMDEuMjY3QzY3LjE3MSwxMDEuMjY3LDAsMjQ1LDAsMjQ1czY2Ljc2MywxNDMuNzMzLDI0NC43OTYsMTQzLjczM0M0MjIuODI5LDM4OC43MzMsNDkwLDI0NSw0OTAsMjQ1DQoJCVM0MjMuMjM4LDEwMS4yNjcsMjQ1LjIwNCwxMDEuMjY3eiBNMjQ0Ljc5NiwzNzMuNDIxYy0xNDYuMzkzLDAtMjEyLjM2Ny0xMDEuMDUzLTIyNy41MDYtMTI4LjMzMw0KCQljMTUuMjQ5LTI2Ljc5Niw4Mi43MzMtMTI4LjUwOCwyMjcuOTE0LTEyOC41MDhjMTQ2LjUxNCwwLDIxMi40NzUsMTAxLjIyLDIyNy41NDMsMTI4LjQNCgkJQzQ1Ny41NzgsMjcyLjIwMywzOTEuMzEzLDM3My40MjEsMjQ0Ljc5NiwzNzMuNDIxeiIvPg0KCTxwYXRoIGQ9Ik0yNDUuMDAzLDE0Ni4xMjRjLTU0LjUyMSwwLTk4Ljg4MSw0NC4zNTItOTguODgxLDk4Ljg3M2MwLDU0LjUyMSw0NC4zNiw5OC44ODEsOTguODgxLDk4Ljg4MXM5OC44NzMtNDQuMzYsOTguODczLTk4Ljg4MQ0KCQlDMzQzLjg3NiwxOTAuNDc3LDI5OS41MjQsMTQ2LjEyNCwyNDUuMDAzLDE0Ni4xMjR6IE0yNDUuMDAzLDMyOC41NjZjLTQ2LjA4LDAtODMuNTY4LTM3LjQ4OS04My41NjgtODMuNTY4DQoJCWMwLTQ2LjA3MiwzNy40ODktODMuNTYxLDgzLjU2OC04My41NjFjNDYuMDcyLDAsODMuNTYxLDM3LjQ4OSw4My41NjEsODMuNTYxQzMyOC41NjQsMjkxLjA3NywyOTEuMDc1LDMyOC41NjYsMjQ1LjAwMywzMjguNTY2eiIvPg0KCTxwYXRoIGQ9Ik0yNDUuMDAzLDE3NS41ODNjLTM4LjI4MSwwLTY5LjQyMiwzMS4xNDEtNjkuNDIyLDY5LjQxNWMwLDM4LjI3NCwzMS4xNDEsNjkuNDE1LDY5LjQyMiw2OS40MTUNCgkJYzM4LjI3NCwwLDY5LjQxNS0zMS4xNDEsNjkuNDE1LTY5LjQxNUMzMTQuNDE3LDIwNi43MjQsMjgzLjI3NywxNzUuNTgzLDI0NS4wMDMsMTc1LjU4M3ogTTI0NS4wMDMsMjk5LjENCgkJYy0yOS44MzMsMC01NC4xMS0yNC4yNy01NC4xMS01NC4xMDJjMC0yOS44MzIsMjQuMjc3LTU0LjEwMiw1NC4xMS01NC4xMDJzNTQuMTAyLDI0LjI3LDU0LjEwMiw1NC4xMDINCgkJQzI5OS4xMDUsMjc0LjgzLDI3NC44MzUsMjk5LjEsMjQ1LjAwMywyOTkuMXoiLz4NCgk8cGF0aCBkPSJNMjQ1LjAwMywyMDYuNjc5Yy0yMS4xMywwLTM4LjMyNiwxNy4xODktMzguMzI2LDM4LjMxOWMwLDIxLjEyOSwxNy4xOTcsMzguMzI2LDM4LjMyNiwzOC4zMjZzMzguMzE5LTE3LjE5NywzOC4zMTktMzguMzI2DQoJCUMyODMuMzIxLDIyMy44NjgsMjY2LjEzMiwyMDYuNjc5LDI0NS4wMDMsMjA2LjY3OXogTTI0NS4wMDMsMjY4LjAxMWMtMTIuNjg4LDAtMjMuMDE0LTEwLjMyNi0yMy4wMTQtMjMuMDE0DQoJCWMwLTEyLjY4OCwxMC4zMjUtMjMuMDA2LDIzLjAxNC0yMy4wMDZjMTIuNjg4LDAsMjMuMDA2LDEwLjMxOCwyMy4wMDYsMjMuMDA2QzI2OC4wMDksMjU3LjY4NiwyNTcuNjkxLDI2OC4wMTEsMjQ1LjAwMywyNjguMDExeiIvPg0KPC9nPg0KPC9zdmc+);\n }\n\n .content-wrapper {\n padding: 1%;\n float: left;\n width: 84%;\n background-color: #f4f4f4;\n overflow: hidden;\n overflow-y: auto;\n height: 96%;\n }\n\n .content {\n display: none;\n }\n\n .content .title {\n font-size: 1rem;\n color: #080404e2;\n font-weight: 600;\n }\n\n .content .title::after {\n content: ':';\n }\n\n .content.active {\n display: flex !important;\n flex-direction: column;\n gap: 0.9rem;\n flex-wrap: wrap;\n transition: all 2s ease-in-out;\n }\n\n .sidebar .footer {\n bottom: 1.5%;\n position: absolute;\n font-size: 0.8rem;\n color: #14cf96;\n font-family: system-ui;\n }\n\n #overview {\n flex-direction: row;\n justify-content: space-between;\n }\n\n #overview .card {\n display: flex;\n flex-direction: column;\n width: 25rem;\n height: 12.5rem;\n border: 1px solid #ddd;\n box-shadow: 0 22px 35px -16px rgba(0, 0, 0, 0.3);\n border-radius: 5px;\n background: white;\n padding: 1rem;\n }\n\n #overview .overall-quality {\n height: 20rem;\n flex-basis: 100%;\n line-height: 14px;\n }\n\n #overview .overall-quality .section {\n display: flex;\n flex-direction: row;\n }\n\n #overview .overall-quality .section .block {\n width: 50%;\n }\n\n #overview .overall-quality .section .block article {\n padding: 5px;\n }\n\n #overview .overall-quality .section .block article p.desc {\n font-size: 0.9em;\n }\n\n #overview .overall-quality .section .block article .items li {\n font-size: 0.87em;\n }\n\n #overview .overall-quality .section .block article .items li .detail {\n margin-top: -10px;\n }\n\n #overview .overall-quality .section .block .graph {\n margin-top: 1.5em;\n }\n\n #overview .string-quality,\n #overview .number-quality,\n #overview .datetime-quality,\n #overview .skipped-items {\n flex-basis: 45%;\n }\n\n #overview .string-quality .graph,\n #overview .number-quality .graph,\n #overview .datetime-quality .graph,\n #overview .skipped-items .graph {\n align-self: center;\n }\n\n #overview .string-quality .graph {\n margin-left: 4rem;\n }\n\n #overview .number-quality.card,\n #overview .datetime-quality.card {\n height: 13rem;\n }\n\n #overview .number-quality .graph,\n #overview .datetime-quality .graph {\n margin-top: -0.9rem;\n margin-left: 4.5rem;\n }\n\n #insights .cards {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n }\n\n #insights .cards .holder {\n display: flex;\n flex-direction: row;\n gap: 1.5rem;\n flex-wrap: wrap;\n }\n\n #insights .cards .card {\n display: flex;\n flex-direction: column;\n width: 20rem;\n min-height: 10rem;\n border: 1px solid #ddd;\n box-shadow: 0 22px 35px -16px rgba(0, 0, 0, 0.3);\n border-radius: 5px;\n background: white;\n }\n\n #insights .cards .card:hover {\n transform: scale(1.015);\n box-shadow: 0 22px 35px -16px #07ff7d33;\n cursor: pointer;\n transition: all 0.1s ease-in-out;\n }\n\n #insights .cards .card .title {\n height: 2.5rem;\n font-size: 1rem;\n padding-top: 1rem;\n font-weight: 500;\n width: calc(100% - 1rem);\n background: #0c5ad9d6;\n border-top-left-radius: 5px;\n border-top-right-radius: 5px;\n padding-left: 1rem;\n color: white;\n }\n\n #insights .cards .card .title::after {\n content: '';\n }\n\n #insights .cards .card .card-content {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n padding: 1rem;\n }\n\n #insights .cards .card .status-bar {\n display: flex;\n flex-direction: column;\n gap: 0.8rem;\n }\n\n #insights .cards .card .status-bar .bar-container .name {\n font-size: 0.78rem;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n #insights .cards .card .status-bar .bar-container .name::after {\n content: ':';\n }\n\n #insights .cards .card .status-bar .bar-container .bar-holder {\n width: 100%;\n height: 10px;\n border: 1px solid #00000038;\n border-radius: 2px;\n }\n\n #insights .cards .card .status-bar .bar-container .bar-holder .bar {\n height: 100%;\n font-size: 0.63rem;\n text-align: right;\n color: rgb(0, 0, 0);\n }\n\n .bar.--green {\n background-color: #1dedaf;\n }\n\n .bar.--red {\n background-color: #fe3e3e;\n }\n\n .bar.--yellow {\n background-color: #faef1f;\n }\n\n .bar.--blue {\n background-color: #77c2ff;\n }\n\n #insights .cards .card .stat {\n display: flex;\n flex-direction: column;\n gap: 0.3rem;\n border: 0.5px solid #00000012;\n border-radius: 6px;\n }\n\n #insights .cards .card .stat table td {\n font-size: 0.78rem;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n #insights .cards .card .stat table td.name {\n width: 70%;\n }\n\n #insights .cards .card .stat table td.value::before {\n content: ': ';\n }\n\n #locale {\n background: white;\n padding: 12px;\n border-radius: 5px;\n padding-top: 20px;\n height: 96%;\n flex-direction: row;\n }\n\n #locale .title {\n content: ':';\n }\n\n #locale .coverage-info {\n margin-top: 0.6rem;\n width: 100%;\n max-height: 94%;\n padding-right: 1rem;\n padding-left: 0.1rem;\n }\n\n #locale table thead th select.filter {\n margin-left: 1rem;\n max-width: 8rem;\n text-overflow: ellipsis;\n }\n\n #locale .image-viewer {\n display: none;\n position: fixed;\n z-index: 9999;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.8);\n text-align: center;\n }\n\n #locale .image-container {\n position: relative;\n top: 50%;\n transform: translateY(-50%);\n display: inline-block;\n }\n\n #locale .image-viewer img {\n max-width: 90%;\n max-height: 90%;\n }\n\n #locale .close-button {\n position: absolute;\n top: 0.5rem;\n right: 1rem;\n color: #ffffffbf;\n font-size: 3.1rem;\n cursor: pointer;\n z-index: 9999;\n }\n\n #locale .close-button:hover {\n color: white;\n }\n\n #locale table tbody td {\n font-size: 0.9em;\n }\n\n #locale table td .view-screenshot-btn {\n color: blue;\n }\n\n .project-info {\n font-size: 1rem;\n color: #90a3a9;\n }\n\n .project-info .time {\n float: right;\n position: relative;\n top: 1rem;\n margin-right: 0.5%;\n }\n\n @media (max-width: 768px) {\n .sidebar {\n width: 16rem;\n padding: 10px;\n }\n }\n\n .--hidden {\n display: none;\n visibility: hidden;\n }\n\n #log .log-content {\n width: 98%;\n height: 82vh;\n background: white;\n border-radius: 3px;\n overflow: hidden;\n padding: 1em;\n }\n\n #log .log-content pre {\n height: 100%;\n white-space: pre-line;\n word-break: break-all;\n padding: 0;\n margin: 0;\n width: 100%;\n overflow: hidden;\n overflow-y: auto;\n }\n\n .--reduced-zoom {\n zoom: 0.9123;\n }\n \n .--hide-overflow {\n overflow: hidden;\n }",dataFilePaths:n,logData:l})}write(e,t,n){Ne(Ce(e,`${t}.html`),n,"utf-8")}}const _e=(e=!0)=>e?"(?:\\s|\\t|(?:&nbsp;))":/(?:\s|\t|(?:&nbsp;))/g;class Ae{#a={};#r;constructor(e){this.#r=e,this.#i(),this.buildConfig(),this.#s()}#i(){this.addToConfig("supportedLocales",yt.getOptions()?.supportedLocales,[]),this.addToConfig("defaultLocale",yt.getDefaultLocale()),this.addToConfig("defaultLanguage",yt.getDefaultLocale()?.split(/[-_ ]/g)[0]),this.addToConfig("language",yt.getLocale()?.split(/[-_ ]/g)[0]),this.addToConfig("locale",yt.getLocale()),this.addToConfig("qaLocale",yt.getQALocale())}buildConfig(){throw new Error(`{{${this.#r}}} buildConfig should be implemented by child class`)}#s(){g.load(h.entireSupplemental()),g.load(h.entireMainFor(this.#o(this.#a.defaultLocale),this.#o(this.#a.locale)))}#o(e){if(this.isQaLocale())return"en";e=e.replace(/[-_ ]/g,"-");const t=h.availableLocales;let n;if(t.find((t=>t===e)))n=e;else{const a=e.split("-")[0];n=t.find((e=>e===a))?a:e}return n}validate(e){throw new Error(`{{${this.#r}}} validate should be implemented by child class`)}isInternationalized(e){throw new Error(`{{${this.#r}}} isInternationalized should be implemented by child class`)}setConfig(e){this.#a=e}addToConfig(e,t,n){this.#a[e]=t??n}getConfig(){return this.#a}isSupportedLocale(){return this.#a.supportedLocales.includes(this.currentLocale())}isQaLocale(){return this.currentLocale()===this.#a?.qaLocale}isDefaultLocale(){return this.currentLocale()===this.defaultLocale()}defaultLocale(){return this.#a?.defaultLocale}defaultLanguage(){return this.#a?.defaultLanguage}currentLocale(){return this.#a?.locale}currentLanguage(){return this.#a.language}getGlobalize(e){return g(this.#o(e))}}class Oe extends Ae{constructor(){super("currency")}validate(e){return this.#l(e)||this.isInternationalized(e)}isInternationalized(e){return this.#c(this.currentLocale(),e)}buildConfig(){}#c(e,t){const n=this.#d(e),a=this.#u(e,n);if(!this.#g(n,a,t))return!1;const r=this.#h(n,a,t);return!isNaN(this.getGlobalize(e).numberParser()(r))}#g(e,t,n){return new RegExp(`^(?:-)?(?:${e}|\\${t})(?:${_e()})?(?:-)?[0-9,. ]+$`,"gi").test(n)||new RegExp(`^(?:[- ]?)[0-9,. ]+(?:${_e()})?(?:${e}|\\${t})$`,"gi").test(n)}#h(e,t,n){return n.replace(new RegExp(`^(?:-)(?:${_e()})?`,"gi"),"").replace(new RegExp(`^(?:${_e()})?(?:${e}|\\${t})`,"gi"),"").replace(new RegExp(`^(?:-)(?:${_e()})?`,"gi"),"").replace(new RegExp(`(?:${_e()})?(?:${e}|\\${t})$`,"gi"),"").trim()}#p(e){return(this.getGlobalize(e).cldr.supplemental(["likelySubtags",e])||e).split(/[-_ ]/).pop()}#d(e){const t=this.#p(e),n=this.getGlobalize(e).cldr.supplemental("currencyData").region[t];if(n){const e=n.find((e=>{const t=Object.values(e)[0];return!t._tender&&(!t._to||new Date(t._to)>=new Date)}));return e?Object.keys(e)[0]:"USD"}return"USD"}#u(e,t){const n=this.getGlobalize(e).cldr.main(`numbers/currencies/${t}`);return n?.symbol||"$"}#l(e){return this.#c(this.defaultLocale(),e)}}const $e=(e,t)=>{t=String(t);const n=(e=>{let[t="en",n="us"]=e.split(/[-_ ]/g);switch(n=String(n).toLowerCase(),t){case"en":return"gb"===n?p.GB:p;case"de":return T;case"es":return D;case"fr":return L;case"pt":return b;case"ja":return w;case"zh":return["hans","cn","sg","hans-cn"].includes(n)?v.hans:["hant","tw","hk","mo","hant-tw"].includes(n)?v.hant:v;case"ru":return y;case"nl":return f;case"uk":return m;default:return p}})(e).parse(String(t).trim());return n.forEach((e=>{t=t.replace(e.text,"")})),0===t.replace(/[^\p{L}\p{N}]+/gu,"").trim().length},Re=e=>{try{return e=e.replace("_","-"),Intl.DateTimeFormat.supportedLocalesOf(e)[0]}catch(t){return Logger.warn(`${e} is unsupported by Intl`),!1}},je=(e,t,n)=>{if(!1!==(e=Re(e))){if(S.fromFormat(n,t,{locale:Re(e)}).isValid)return!0}return!1};class ke extends Ae{constructor(){super("date")}validate(e){return this.#m(e)||this.isInternationalized(e)}isInternationalized(e){return this.#f(this.isQaLocale()?this.defaultLocale():this.currentLocale(),e)}buildConfig(){}#f(e,t){return this.#y(e,t)||this.#v(e,t)||this.#w(e,t)}#m(e){return this.#f(this.defaultLocale(),e)}#y(e,t){const n=["short","medium","long","full"];for(let a of n){if(this.getGlobalize(e).dateParser({date:a})(t))return!0}return!1}#v(e,t){const n=[S.DATE_SHORT,S.DATE_MED,S.DATE_FULL,S.DATE_HUGE,S.DATE_MED_WITH_WEEKDAY,"D","DD","DDD","DDDD"];for(let a of n){if(je(e,a,t))return!0}return!1}#w(e,t){return $e(this.isQaLocale()?this.defaultLocale():e,t)}}class Ue extends Ae{constructor(){super("dateTime")}validate(e){return this.#b(e)||this.isInternationalized(e)}isInternationalized(e){return this.#L(this.isQaLocale()?this.defaultLocale():this.currentLocale(),e)}buildConfig(){}#L(e,t){return this.#y(e,t)||this.#v(e,t)||this.#w(e,t)}#b(e){return this.#L(this.defaultLocale(),e)}#y(e,t){const n=["short","medium","long","full"];for(let a of n){if(this.getGlobalize(e).dateParser({datetime:a})(t))return!0}return!1}#v(e,t){const n=[S.DATETIME_SHORT,S.DATETIME_SHORT_WITH_SECONDS,S.DATETIME_MED,S.DATETIME_MED_WITH_SECONDS,S.DATETIME_MED_WITH_WEEKDAY,S.DATETIME_FULL,S.DATETIME_FULL_WITH_SECONDS,S.DATETIME_HUGE,S.DATETIME_HUGE_WITH_SECONDS,"f","F","ff","FF"];for(let a of n){if(je(e,a,t))return!0}return!1}#w(e,t){return $e(this.isQaLocale()?this.defaultLocale():e,t)}}class Fe extends Ae{constructor(){super("number")}validate(e){return this.#D(e)||this.isInternationalized(e)}isInternationalized(e){return this.#T(this.currentLocale(),e)}buildConfig(){}#T(e,t){const n=this.getGlobalize(e).numberParser();return!isNaN(n(t))}#D(e){return this.#T(this.defaultLocale(),e)}}class Ge extends Ae{constructor(){super("percentage")}validate(e){return this.#S(e)||this.isInternationalized(e)}isInternationalized(e){return this.#I(this.currentLocale(),e)}buildConfig(){}#I(e,t){if(!this.#E(e,t))return!1;const n=this.#C(t);return!isNaN(this.getGlobalize(e).numberParser()(n))}#C(e=""){return e.replace(new RegExp(`(^(?:${_e()})*|(?:${_e()})*$)`,"g"),"").replace(/^-/,"").replace(/٪|%/g,"").trim()}#E(e,t){const n="[0-9,. ]+";let a;return a=["fa-IR","fa-ir"].includes(e)||e.startsWith("ar")?new RegExp(`(?:-)?(?:${_e()})?(?:٪|%)(?:${_e()})?${n}`,"g"):new RegExp(`(?:-)?(?:${_e()})?${n}(?:${_e()})?(?:٪|%)`,"g"),a.test(t)}#S(e){return this.#I(this.defaultLocale(),e)}}class Ve extends Ae{constructor(){super("string")}buildConfig(){const e=yt.getOptions();this.addToConfig("mockChars",e?.qaMock),this.addToConfig("resource",yt.getResourceBundle(),{}),this.addToConfig("garbledChars",yt.getGarbledChars()?.filter((e=>String(e).trim())).filter(Boolean),[])}isInternationalized(e){const t=e.trim().replace(/\s*:\s*$/,""),n=this.getConfig()?.resource?.[this.defaultLocale()];return n?.includes(e)||n?.includes(t)}validate(e){return"string"==typeof e}isDntText(e){return this.getConfig()?.resource?.dnt?.includes(e)}isAutoIgnoredText(e){return this.isDefaultLocale()||this.isUserInputText(e)||this.isEmailText(e)||this.isUrlText(e)}isIgnoredText(e){return this.getConfig()?.resource?.ignore?.includes(e)}isUserInputText(e){return e.startsWith("zqa_")}isEmailText(e){return ge.EMAIL.test(e)}isUrlText(e){return ge.URL.test(e)}isFullQaLanguageText(e){const t=this.getConfig();return(e.slice(0,2)===t?.mockChars?.prefix||e.slice(0,2)===t?.mockChars?.prefix.toUpperCase())&&e.slice(-2)===t?.mockChars.suffix}isPartialQaLanguageText(e){const t=this.getConfig();return e.slice(0,2)===t?.mockChars.prefix||e.slice(0,2)===t?.mockChars.prefix.toUpperCase()||e.slice(-2)===t?.mockChars.suffix}hasEncodingIssue(e){return this.getConfig()?.garbledChars?.length>0&&this.getConfig().garbledChars.some((t=>e.includes(t)))}isPartiallyLocalizedText(e){return this.#N(e)===this.currentLanguage()}#N(e){const t=Object.keys(I(e)?.scores||{}).filter(Boolean)||[],n=this.currentLanguage();return t.length?t.includes(n)?n:t[0]:this.defaultLanguage()}isLocalized(e){const t=e.trim().replace(/\s*:\s*$/,""),n=this.getConfig()?.resource?.[this.currentLocale()];return n?.includes(e)||n?.includes(t)}}class Qe extends Ae{constructor(){super("time")}validate(e){return this.#z(e)||this.isInternationalized(e)}isInternationalized(e){return this.#x(this.isQaLocale()?this.defaultLocale():this.currentLocale(),e)}buildConfig(){}#x(e,t){return this.#y(e,t)||this.#v(e,t)||this.#w(e,t)}#z(e){return this.#x(this.defaultLocale(),e)}#y(e,t){const n=["short","medium","long","full"];for(let a of n){if(this.getGlobalize(e).dateParser({time:a})(t))return!0}return!1}#v(e,t){const n=[S.TIME_SIMPLE,S.TIME_WITH_SECONDS,S.TIME_WITH_SHORT_OFFSET,S.TIME_WITH_LONG_OFFSET,S.TIME_24_SIMPLE,S.TIME_24_WITH_LONG_OFFSET,S.TIME_24_WITH_SECONDS,S.TIME_24_WITH_SHORT_OFFSET,"t","T","tt","TT"];for(let a of n){if(je(e,a,t))return!0}return!1}#w(e,t){return $e(this.isQaLocale()?this.defaultLocale():e,t)}}class qe{static#M={};static#P;static#_;static#A;static#O;static#$;static#R;static#j;static load(){qe.#P=new Ve,qe.#_=new Fe,qe.#A=new ke,qe.#O=new Qe,qe.#$=new Ue,qe.#R=new Oe,qe.#j=new Ge}static getIssueType(e){const t=yt.getLocale();if(t){let n=ie;return qe.#M[t]||(qe.#M[t]={}),qe.#M[t][e]?qe.#M[t][e]:(this.#P.isAutoIgnoredText(e)?n=se:this.#P.isDntText(e)?n=ae:this.#P.isIgnoredText(e)?n=re:this.#P.hasEncodingIssue(e)?n=ne:this.#R.validate(e)?n=this.#R.isInternationalized(e)?G:Z:this.#j.validate(e)?n=this.#j.isInternationalized(e)?V:W:this.#_.validate(e)?n=this.#_.isInternationalized(e)?F:Y:this.#A.validate(e)?n=this.#A.isInternationalized(e)?Q:J:this.#O.validate(e)?n=this.#O.isInternationalized(e)?q:X:this.#$.validate(e)?n=this.#$.isInternationalized(e)?B:K:this.#P.validate(e)?this.#P.isQaLocale()?n=this.#P.isFullQaLanguageText(e)?k:this.#P.isPartialQaLanguageText(e)?U:H:!this.#P.isDefaultLocale()&&this.#P.isSupportedLocale()&&(n=this.#P.isLocalized(e)?k:this.#P.isPartiallyLocalizedText(e)?U:this.#P.isInternationalized(e)?ie:H):this.#P.isDefaultLocale()&&(n=se),qe.#M[t][e]=n,n)}return ie}}class Be{static load(){const e={};if(yt.getOptions()?.l10nResourcePath){const t=Ce(process.cwd(),yt.getOptions()?.l10nResourcePath);if(De(t))Be.#k(t,e);else{if(!Le(t))return void console.error(`${t} invalid resource path`);for(const n of Ee(t)){const a=Ce(t,n);Be.#k(a,e)}}yt.setResourceBundle(e)}}static#k(e,t){const n=yt.getLocale(),a=yt.getDefaultLocale(),r=Ie(e),i=(e=>De(e)?u(e):"")(e);if(he.includes(i)){if(!r)return void console.error(`${e} is empty or invalid`);if(e.toLowerCase().includes("dnt"))t.dnt=r.split(/\r?\n/);else if(e.toLowerCase().includes("ignore"))t.ignore=r.split(/\r?\n/);else if(e.includes(n)){const e=r.split(/\r?\n/);t[n]=e.map(He)}else e.includes(a)&&(t[a]=r.split(/\r?\n/))}}}function He(e){return e.replace(/<\/?[^>]+>/gi,"")}class Ye{static#U;static#F;static init(){Ye.#F=Ce(it.getReportPath(),ze(yt.getLocale())),Ye.#U=Ce(Ye.#F,be),this.#G()}static exists(){return De(Ye.#U)}static save(e){this.#G();const t=`!window.rawData && (window.rawData={'${yt.getLocale()}':{}});window.rawData['${yt.getLocale()}']=${JSON.stringify(e)};`;Ne(Ye.#U,t)}static getData(){if(!this.exists())return{};try{return JSON.parse(Ie(Ye.#U).replace(new RegExp(`(\\!window.rawData && \\(window\\.rawData=\\{'${yt.getLocale()}':\\{\\}\\}\\);window\\.rawData\\['${yt.getLocale()}'\\]=)|(;$)`,"g"),""))}catch(e){return{}}}static#G(){Se(Ye.#F)}static getCacheDirPath(){return Ye.#F}}const Ze=()=>{Be.load(),qe.load(),it.setup(),Ye.init()},We=()=>{let e=process.cwd(),t=0;for(;t<10;){const n=Ce(e,"package.json");if(De(n)){const e=Ie(n),t=JSON.parse(e),a={...t?.dependencies||{},...t?.devDependencies||{},...t?.peerDependencies||{}};if("@zeesoft/i18n-verify"!==t.name&&JSON.stringify(a).includes('"@zeesoft/i18n-verify"'))break}e=d(e),t++}return e},Je=(e=We())=>Ie(Ce(e,"package.json"));class Xe extends Me{#V;#Q=!1;static#q="STATUS";static#B="COUNTS";constructor(){super(we),this.#H()}#H(){this.#V=new E({style:{headerTop:{left:"╔",mid:"╦",right:"╗",other:"═"},headerBottom:{left:"╟",mid:"╬",right:"╢",other:"═"},tableBottom:{left:"╚",mid:"╩",right:"╝",other:"═"},vertical:"║"},columns:[{name:Xe.#q,alignment:"left"},{name:Xe.#B,alignment:"center"}]})}buildContent(){if(ce[le]>0){this.#Q=!0;for(const e in ce)e!==le?ce.hasOwnProperty(e)&&this.#V.addRows([{STATUS:e,COUNTS:`${ce[e]}`}]):(this.#V.addRows([{STATUS:""+"═".repeat(28)+"",COUNTS:""+"═".repeat(8)+""}]),this.#V.addRows([{STATUS:"OVERALL_REVIEWED",COUNTS:`${ce[e]}`}]))}}export(){this.#Q?this.#V.printTable():st.info("There are no visbile elements with UI strings")}}class Ke{static#Y(e){switch(e){case ve:return new Pe;case we:return new Xe;default:throw new Error("unsupported report type requested")}}static export(e,t,n){const a=Ke.#Y(e),r=(new Date).toLocaleString(),i=Je()?.match(/"name": "([^"]+)",/)?.[1]||"",s=new xe({appName:i,reportTime:r});a.generate(s),a.export(t,n)}}class et{#Z;#W;#J;#X;#K;#ee;#te;#ne;#ae;#re;#ie;#se;#oe;#le;#ce;#de;#ue;#ge;#he;#pe;#me;#fe;#ye;#ve;constructor(e={}){this.#Z=e?.localizedStrings||0,this.#W=e?.notLocalizedStrings||0,this.#J=e?.untranslatedStrings||0,this.#X=e?.partialStrings||0,this.#K=e?.localizedDateTime||0,this.#ee=e?.localizedDate||0,this.#te=e?.localizedTime||0,this.#ne=e?.notLocalizedDateTime||0,this.#ae=e?.notLocalizedDate||0,this.#re=e?.notLocalizedTime||0,this.#ie=e?.localizedNumber||0,this.#se=e?.notLocalizedNumber||0,this.#oe=e?.localizedCurrency||0,this.#le=e?.notLocalizedCurrency||0,this.#ce=e?.localizedPercentage||0,this.#de=e?.notLocalizedPercentage||0,this.#ue=e?.ignored||0,this.#ge=e?.dnt||0,this.#he=e?.autoIgnored||0,this.#pe=e?.userInput||0,this.#me=e?.encoding||0,this.#fe=e?.truncation||0,this.#ye=e?.overlapping||0,this.#ve=e?.reviewed||0}getLocalizedStrings(){return this.#Z}setLocalizedStrings(e){this.#Z=e}getUntranslatedStrings(){return this.#J}setUntranslatedStrings(e){this.#J=e}getNotLocalizedStrings(){return this.#W}setNotLocalizedStrings(e){this.#W=e}getPartialStrings(){return this.#X}setPartialStrings(e){this.#X=e}getLocalizedDateTime(){return this.#K}setLocalizedDateTime(e){this.#K=e}getLocalizedDate(){return this.#ee}setLocalizedDate(e){this.#ee=e}getLocalizedTime(){return this.#te}setLocalizedTime(e){this.#te=e}getNotLocalizedDateTime(){return this.#ne}setNotLocalizedDateTime(e){this.#ne=e}getNotLocalizedDate(){return this.#ae}setNotLocalizedDate(e){this.#ae=e}getNotLocalizedTime(){return this.#re}setNotLocalizedTime(e){this.#re=e}getLocalizedNumber(){return this.#ie}setLocalizedNumber(e){this.#ie=e}getNotLocalizeNumber(){return this.#se}setNotLocalizeNumber(e){this.#se=e}getCurrency(){return this.#oe}setCurrency(e){this.#oe=e}getNotLocalizeCurrency(){return this.#le}setNotLocalizeCurrency(e){this.#le=e}getPercentage(){return this.#ce}setPercentage(e){this.#ce=e}getNotLocalizePercentage(){return this.#de}setNotLocalizePercentage(e){this.#de=e}getIgnored(){return this.#ue}setIgnored(e){this.#ue=e}getUserInput(){return this.#pe}setUserInput(e){this.#pe=e}getDnt(){return this.#ge}setDnt(e){this.#ge=e}getAutoIgnored(){return this.#he}setAutoIgnored(e){this.#he=e}getEncoding(){return this.#me}setEncoding(e){this.#me=e}getTruncation(){return this.#fe}setTruncation(e){this.#fe=e}getOverlapping(){return this.#ye}setOverlapping(e){this.#ye=e}getReviewed(){return this.#ve}setReviewed(e){this.#ve=e}incrementByType(e){switch(e){case k:++this.#Z;break;case H:++this.#W;break;case ie:++this.#J;break;case U:++this.#X;break;case se:++this.#he;break;case re:++this.#ue;break;case ae:++this.#ge;break;case ne:++this.#me;break;case Q:++this.#ee;break;case q:++this.#te;break;case B:++this.#K;break;case J:++this.#ae;break;case X:++this.#re;break;case K:++this.#ne;break;case F:++this.#ie;break;case Y:++this.#se;break;case G:++this.#oe;break;case Z:++this.#le;break;case V:++this.#ce;break;case W:++this.#de;break;case ee:++this.#fe;break;case te:++this.#ye;break;case le:++this.#ve;break;case oe:++this.#pe}}toJSON(){return{localizedStrings:this.#Z,notLocalizedStrings:this.#W,untranslatedStrings:this.#J,partialStrings:this.#X,localizedDateTime:this.#K,localizedDate:this.#ee,localizedTime:this.#te,notLocalizedDateTime:this.#ne,notLocalizedDate:this.#ae,notLocalizedTime:this.#re,localizedNumber:this.#ie,notLocalizedNumber:this.#se,localizedCurrency:this.#oe,notLocalizedCurrency:this.#le,localizedPercentage:this.#ce,notLocalizedPercentage:this.#de,ignored:this.#ue,dnt:this.#ge,autoIgnored:this.#he,userInput:this.#pe,encoding:this.#me,truncation:this.#fe,overlapping:this.#ye,reviewed:this.#ve}}}class tt{#we;constructor(e={}){this.#we=new et(e.stats)}getStats(){return this.#we}setStats(e){this.#we=e}toJSON(){return{stats:this.#we}}}class nt{#r;#be;#Le;constructor(e){this.#r=e?.type||"",this.#be=e?.imagePath||"",this.#Le=e?.description||""}getType(){return this.#r}setType(e){this.#r=e}getImagePath(){return this.#be}setImagePath(e){this.#be=e}getDescription(){return this.#Le}setDescription(e){this.#Le=e}toJSON(){return{type:this.#r,description:this.#Le,imagePath:this.#be}}}class at{#De={};constructor(e){if(e)for(const t in e)e[t].forEach((e=>{this.#De[t]||(this.#De[t]=[]),this.#De[t].push(new nt(e))}))}getStringData(e){return this.#De[e]||[]}setStringData(e,t){return!this.#De[e]&&(this.#De[e]=[]),this.#De[e].push(new nt(t)),!0}checkAndAdd(e,t){!this.#De[e]&&(this.#De[e]=[]);const n=this.getStringData(e).some((e=>e.getDescription()!==t.description||e.getImagePath()!==t.imagePath||e.getType()!==e.type));return n&&this.setStringData(e,t),n}hasStringData(e){return e in this.#De}static createNew(e,t){return t=Array.isArray(t)?t:[t],new at({data:{[e]:t}})}toJSON(){return this.#De}}class rt{#Te;#Se;constructor(e={}){this.#Te=new tt(e.metaData),this.#Se=new at(e.stringsData)}getMetaData(){return this.#Te}setMetaData(e){this.#Te=e}getStringEntry(e){return this.#Se.getStringData(e)}static addString(e,t,n,a){const r=rt.getInstance(),i=r.#Ie(e,t,n,a.replace(/\\/g,"/"));return i&&r.save(),i}#Ie(e,t,n,a){let r=!1;const i={type:t,description:n,imagePath:a};return r=this.#Se.hasStringData(e)?this.#Se.checkAndAdd(e,i):this.#Se.setStringData(e,i),r&&this.#Te.getStats().incrementByType(t),r}toJSON(){return{metaData:this.#Te,stringsData:this.#Se}}save(){Ye.save(this)}remove(){Ye.delete()}static getInstance(){return new rt(Ye.getData())}}class it{static#Ee;static#Ce;static setup(){it.#Ce=it.#$();const e=l.resolve();it.#Ee=Ce(e,yt.getL10nReportsPath(),it.#Ce)}static getReportTimeStamp(){return it.#Ce}static getReportPath(){return it.#Ee}static reviewedReports(e=null,t=null){return it.#Ne(le,e,t)}static[k](e,t){return it.#Ne(k,e,t)}static[H](e,t){return it.#Ne(H,e,t)}static[U](e,t){return it.#Ne(U,e,t)}static[ae](e,t){return it.#Ne(ae,e,t)}static[re](e,t){return it.#Ne(re,e,t)}static[se](e,t){return it.#Ne(se,e,t)}static[ie](e,t){return it.#Ne(ie,e,t)}static[ne](e,t){return it.#Ne(ne,e,t)}static[B](e,t){return it.#Ne(B,e,t)}static[K](e,t){return it.#Ne(K,e,t)}static[Q](e,t){return it.#Ne(Q,e,t)}static[J](e,t){return it.#Ne(J,e,t)}static[q](e,t){return it.#Ne(q,e,t)}static[X](e,t){return it.#Ne(X,e,t)}static[G](e,t){return it.#Ne(G,e,t)}static[Z](e,t){return it.#Ne(Z,e,t)}static[V](e,t){return it.#Ne(V,e,t)}static[W](e,t){return it.#Ne(W,e,t)}static[F](e,t){return it.#Ne(F,e,t)}static[Y](e,t){return it.#Ne(Y,e,t)}static incrementCount(e,t,n,a){ce.hasOwnProperty(e)&&(ce[e]++,rt.addString(t,e,a,n.replace(it.#Ee,"")))}static#$(){const e=new Date;return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}-${String(e.getHours()).padStart(2,"0")}-${String(e.getMinutes()).padStart(2,"0")}`}static#Ne=(e,t,n)=>{const a=Ce(it.#Ee,ze(yt.getLocale()),"screenshots",String(e).toLowerCase());Se(a,me);const r=Ce(it.#Ee,ze(yt.getLocale()),"strings");if(Se(r,me),null!=t){let a="";if(Te(Ce(r,e+".txt"))){Ie(Ce(r,e+".txt")).includes(n)||(a+=`\n|<<<<<<<<<<<<<------${n}------\x3e>>>>>>>>>>>>|\n`),a+=t}else a+=`\n|<<<<<<<<<<<<<------${n}------\x3e>>>>>>>>>>>>|\n`,a+=t;((e,t,n="utf-8")=>{if(e&&t)try{s(e,t+"\n",{encoding:n,flag:"a"})}catch(e){st.error(e)}})(Ce(r,e+".txt"),a)}return a};static#ze(e){Ke.export(e,it.#Ee)}static generateHtml(){it.#ze(ve)}static generateAsciiTable(){it.#ze(we)}}class st{static#xe=!1;static#Me;static#Pe=[];static info(e){st.#_e("info",e)}static warn(e){st.#_e("warn",e)}static error(e,t){st.#_e("errr",e,t)}static debug(e){st.#_e("dbug",e)}static#_e(e,t,n=""){const a={INFO:"",WARN:"",ERRR:"",DBUG:""};let r=a[e=e.toUpperCase()]||a.DEFAULT;n=n?` reason: ${n.toString()}`:"";let i=`[${(new Date).toLocaleString()}] [${r}${e}] [${yt.getLocale()}] - ${t}${n}`;switch(e){case"INFO":console.info(i);break;case"WARN":console.warn(i);break;case"ERRR":console.error(i);break;case"DBUG":console.debug(i);break;default:console.log(i)}i=i.replace(/\x1b\[\d+m/g,""),st.#Ae(`${i}\n`)}static#Ae=t=>{if(st.#xe)st.#Pe.push(t),st.#Me=setInterval((()=>{st.#xe||(clearInterval(st.#Me),t=st.#Pe.join("\n"),st.#Pe=[],t&&st.#Ae(t))}),10);else{st.#xe=!0;const n=Ce(it.getReportPath(),"logs"),a=Ce(n,"log");Se(n,me),e.appendFileSync(a,t),st.#xe=!1}}}class ot extends z{constructor(e){super(e)}getElement(e){return this.$driver.element.find({selector:e,locateStrategy:e.startsWith("/")?"xpath":"css selector"})}async getElements(e){return await this.$driver.element.findAll({selector:e,locateStrategy:e.startsWith("/")?"xpath":"css selector"})}async getText(e){return await e.getText()}async getTitle(e){return await e.getAttribute("title")}async getPlaceholderText(e){return await e.getAttribute("placeholder")}async getAltText(e){return await e.getAttribute("alt")}async getTagName(e){return await e.getTagName()}async getValue(e){return await e.getAttribute("value")}async getElementID(e){return await e.getAttribute("id")}async getElementDimension(e){const t=await e.getRect();if(![null,"",void 0].includes(t))return[t.x,t.y,t.height,t.width]}async isElementDisplayed(e){return await this.$driver.isVisible(e)}async isElementPresent(e){return await this.$driver.isPresent(e)}async getElementStrings(e){const t=[];return[{type:"eleTxt",value:await this.getText(e)},{type:"altTxt",value:await this.getAltText(e)},{type:"titleTxt",value:await this.getTitle(e)},{type:"placeTxt",value:await this.getPlaceholderText(e)},{type:"valueTxt",value:await this.getValue(e)}].forEach((({value:e})=>{this.checkIfNullOrEmpty(e)&&t.push(e)})),t}async getElementString(e){let t=null;const n=[this.getText,this.getAltText,this.getTitle,this.getPlaceholderText,this.getValue];for(const a of n)if(t=await a(e),null!==t)return t;return t}async captureScreenshot(e){await lt(this.$driver,e)}async getElementsCount(e){return e.length}async switchIframe(e){await this.$driver.frame(e,(()=>{st.debug(`Switching to ${e} frame`)}))}async switchToParentframe(){await this.$driver.frame(null)}pause(e){this.$driver.pause(1e3*e)}async onScreenStringHighlight(e,t){await this.$driver.execute(((e,t)=>{const n=window.getComputedStyle(e).border;e.style.border=`3px solid ${t}`,setTimeout((()=>{e.style.border=n}),40)}),[e,t])}async checkIfIframeIsPresent(){return new Promise((e=>{this.$driver.isPresent({selector:"//iframe",locateStrategy:"xpath",suppressNotFoundErrors:!0},(t=>{e(t.value)}))}))}async checkIfIframeBodyIsEmpty(){const e=await this.$driver.executeScript("return document.body.innerHTML");return""===await e.trim()}}const lt=async(t,n)=>{const a=await C({host:"localhost",port:ct(t)}),{Page:r}=a;await r.enable();const{data:i}=await r.captureScreenshot({format:"png",captureBeyondViewport:!0}),s=Buffer.from(i,"base64");e.writeFileSync(n,s),console.log(`Screenshot saved as: ${n}`),await a.close()},ct=e=>{const t=e?.capabilities?.["goog:chromeOptions"]?.debuggerAddress;return t&&t.split(":")?.[1]||9229};class dt extends z{constructor(e){super(e)}getElement(e){return this.$driver.findElement("xpath",e)}async getElements(e){return await this.$driver.findElements("xpath",e)}async getText(e){return await $(e).getText()}async getTitle(e){return await $(e).getAttribute("title")}async getPlaceholderText(e){return await $(e).getAttribute("placeholder")}async getAltText(e){return await $(e).getAttribute("alt")}async getTagName(e){return await $(e).getTagName()}async getValue(e){return await $(e).getValue()}async getElementDimension(e){const t=await this.$driver.getElementRect(e["element-6066-11e4-a52e-4f735466cecf"]);if(![null,"",void 0].includes(t))return[t.x,t.y,t.height,t.width]}isElementDisplayed(e){return $(e).isDisplayed()}async getElementStrings(e){const t=[];return[{type:"eleTxt",value:await this.getText(e)},{type:"altTxt",value:await this.getAltText(e)},{type:"titleTxt",value:await this.getTitle(e)},{type:"placeTxt",value:await this.getPlaceholderText(e)},{type:"valueTxt",value:await this.getValue(e)}].forEach((({value:e})=>{this.checkIfNullOrEmpty(e)&&t.push(e)})),t}async captureScreenshot(e){await this.$driver.saveScreenshot(e)}async getElementsCount(e){return e.length}}const ut=({subject:e,selector:t,options:n={},driver:a})=>{if(!Cypress)return void a.printOnConsole("Cypress object is inaccessible");const r={name:"xpath",message:t};if(Cypress.dom.isElement(e)&&e.length>1)throw new Error("xpath() can only be called on a single element. Your subject contained "+e.length+" elements.");const i=()=>{let n,a=[],i=cy.state("withinSubject");n=Cypress.dom.isElement(e)?e[0]:Cypress.dom.isDocument(e)?e:i?i[0]:cy.state("window").document;let s=(n.ownerDocument||n).evaluate(t,n);if(s.resultType===XPathResult.NUMBER_TYPE){const e=(e=>e.numberValue)(s);return r.consoleProps=()=>({XPath:t,type:"number",result:e}),e}if((e=>e.resultType===XPathResult.STRING_TYPE)(s)){const e=(e=>e.stringValue)(s);return r.consoleProps=()=>({XPath:t,type:"string",result:e}),e}if((e=>e.resultType===XPathResult.BOOLEAN_TYPE)(s)){const e=(e=>e.booleanValue)(s);return r.consoleProps=()=>({XPath:t,type:"boolean",result:e}),e}try{let e=s.iterateNext();for(;e;)a.push(e),e=s.iterateNext();return r.consoleProps=()=>({XPath:t,result:1===a.length?a[0]:a}),a}catch(e){return console.error("Document tree modified during iteration",e),null}},s=()=>Cypress.Promise.try(i).then((e=>{var a;return a=e,Cypress._.isNumber(a)||Cypress._.isString(a)||Cypress._.isBoolean(a)||((e=Cypress.$(e)).selector=t),cy.verifyUpcomingAssertions(e,n,{onRetry:s})}));return s().then((e=>(!1!==n.log&&Cypress.log(r),e))).catch((e=>console.log(e)))};class gt extends z{constructor(e){super(e)}async getElement(e){return"string"!=typeof e?this.$driver.wrap(e):e.startsWith("//")?await this.xpath(e).first():await this.$driver.get(e).first()}async getElements(e){return"string"!=typeof e?this.$driver.wrap(e):e.startsWith("//")?await this.xpath(e):await this.$driver.get(e)}async getText(e){return"string"==typeof e?await this.$driver.get(e).invoke("text"):await this.$driver.wrap(e).invoke("text")}async getTitle(e){return"string"==typeof e?await this.$driver.get(e).title():this.$driver.wrap().title()}async getPlaceholderText(e){return"string"==typeof e?this.$driver.get(e).filter("input").invoke("attr","placeholder").then((e=>e)):this.$driver.$$(e).attr("placeholder")}async getAltText(e){return this.$driver.get(e).invoke("attr","alt")}async getWidth(e){return"string"==typeof e?this.$driver.get(e).invoke("width"):this.$driver.$$(e).width()}async getHeight(e){return"string"==typeof e?this.$driver.get(e).invoke("height"):this.$driver.$$(e).height()}async getTagName(e){return"string"==typeof e?this.$driver.get(e).invoke("prop","tagName").then((e=>e.toLowerCase())):this.$driver.$$(e).tagName}async getValue(e){return"string"==typeof e?this.$driver.get(e).invoke("val"):this.$driver.wrap(e).invoke("val")}async getLocation(e){if("string"==typeof e)return this.$driver.get(e).invoke("offset").then((e=>({x:e.left,y:e.top})));{const t=this.$driver.$$(e).offset();return{x:t.left,y:t.top}}}async isElementDisplayed(e){return"string"==typeof e?this.$driver.get(e).then((e=>e.is(":visible"))):this.$driver.$$(e).is(":visible")}async captureScreenshot(e){this.$driver.screenshot(e)}async getElementsCount(e){return new Promise((t=>"string"==typeof e?this.$driver.get(e).its("length").then((e=>t(e))):this.$driver.wrap(e,{timeout:8e3}).its("length").then((e=>t(e)))))}async getElementStrings(e){const t=[];try{[{type:"eleTxt",value:await this.getText(e)},{type:"altTxt",value:await this.getAltText(e)},{type:"placetxt",value:await this.getPlaceholderText(e)}].forEach((({value:e})=>{this.checkIfNullOrEmpty(e)&&t.push(e)}))}catch(e){st.error("Error getting text of element:",e)}return t}printOnConsole(e){this.$driver.log(e)}xpath(e,t,n={}){return ut({subject:e,selector:t,options:n,driver:this.$driver})}}class ht extends z{constructor(e){super(e)}async getElement(e){return await this.driver.findElement(e)}async getElements(e){return await this.driver.findElements(e)}async getText(e){return await e.getText()}async getTitle(){return await this.driver.getTitle()}async getAttribute(e,t){return await e.getAttribute(t)}async getTagName(e){return await e.getTagName()}async getElementDimension(e){const t=await e.getRect();if(![null,"",void 0].includes(t))return[t.x,t.y,t.height,t.width]}async isElementDisplayed(e){return await e.isDisplayed()}async getElementStrings(e){const t=[];return[{type:"eleTxt",value:await this.getText(e)},{type:"altTxt",value:await this.getAttribute(e,"alt")},{type:"titleTxt",value:await this.getAttribute(e,"title")},{type:"placeTxt",value:await this.getAttribute(e,"placeholder")},{type:"valueTxt",value:await this.getAttribute(e,"value")}].forEach((({value:e})=>{this.checkIfNullOrEmpty(e)&&t.push(e)})),t}async getElementsCount(e){return e.length}}const pt=(e,t=", ")=>e.join(t),mt=()=>{const e=Ce(process.cwd(),ye);if(!De(e))throw new Error(`${ye} file is missing. Please add the file in your project root dir`);let t=Ie(e);if(!t)throw new Error(`invalid ${ye} file. Please add valid file in your project root dir`);t=t.replace(/\/\/.+$/gm,"");try{t=JSON.parse(t)}catch(e){throw new Error(`invalid ${ye} file. Please add valid file in your project root dir`)}return t},ft=(e,t="")=>{e&&!De(e)&&Ne(e,((e="")=>`{\n "type": "${e}", // set automation framework type ${pt(Object.values(x))}\n "qaLocale": "", // set the qa locale used in your project\n "l10nResourcePath": "./l10nResources", // set the dir path of l10n resources\n "l10nReportsPath": "./l10nReports/", // set the dir path of l10n reports\n "supportedLocales": ["en_US", "fr_FR", "ja_JP"], // set the list of supported locales\n "defaultLocale": "en_US", // set default locale of the application\n "qaMock": { // set the prefix and suffix characters of qa locale\n "prefix": "à_",\n "suffix": "_海"\n },\n "i18nVerify": true, // enable or disable I18n verification\n "sanityCapture": false, // will capture strings and highlight them when i18n verification is off\n "garbledChars": [""] // set the list of custom garbled characters\n}`)(t))};class yt{static#Oe;static#$e;static#r;static#Re;static#je;static#ke;static#Ue;static#Fe;static init(){try{const e=mt();(e=>{if("object"!=typeof e||Object.keys(e).length<1)throw new Error(`empty ${ye} file`);const t=[];if(!((e,t,n=[])=>["l10nResourcePath","l10nReportsPath","supportedLocales","defaultLocale","type"].every((e=>(((e,t)=>e in t)(e,t)||n.push(e),!0))))(0,e,t))throw new Error(`following properties are missing in ${ye} file: ${pt(t)}`);if(!Object.values(x).includes(e?.type||""))throw new Error(`${ye} has invalid system type`)})(e),this.#r=e?.type,this.#je=e?.qaLocale,this.#ke=e,this.#Fe=0,this.getGarbledChars()}catch(e){throw st.error(e.message),e}}static set(e,t){this.#Re=t,this.#Oe=((e,t)=>{switch(e){case x.NIGHT_WATCH:return new ot(t);case x.WEB_DRIVER_IO:return new dt(t);case x.CYPRESS:return new gt(t);case x.SELENIUMJS:return new ht(t);default:throw new Error("Unsupported framework")}})(this.#r,e)}static getGarbledChars(){return[...this.#ke.garbledChars||[],...fe]}static getL10nReportsPath(){return this.#ke.l10nReportsPath}static setDriver(e){this.#Oe=e}static setType(e){this.#r=e}static setLocale(e){this.#Re=e}static setOptions(e){this.#ke=e}static getRunner(){if(yt.#$e)return yt.#$e;if(!yt.#Oe)throw new Error("Unable to initialize I18n Runner");return this.#$e=new wt(this.#Oe),this.#$e}static getDriver(){return this.#Oe}static getLocale(){return this.#Re}static getDefaultLocale(){return this.#ke.defaultLocale}static getType(){return this.#r}static getOptions(){return this.#ke}static setQALocale(e){this.#je=e}static getQALocale(){return this.#je}static setResourceBundle(e){this.#Ue=e}static getResourceBundle(e){return this.#Ue?.[e]||this.#Ue||[]}static incrementCounter(){this.#Fe++}static getSSCount(){return this.#Fe}}class vt{static async drawRectangle(t,n,a){const r=t?.x-2,i=t?.y-2,s=t?.width+2,o=t?.height+2;try{const t=await N.read(a),c=N.cssColorToHex(n);this.drawRectangleOutline(t,r,i,s,o,c,2);const d=l.dirname(a),u=await t.getBufferAsync(N.MIME_PNG);e.existsSync(d)||(st.debug("folder not found"),e.mkdirSync(d,{recursive:!0})),e.writeFileSync(a,u)}catch(e){st.error(`Error: ${e}`)}}static async drawRectangleOutline(e,t,n,a,r,i,s){for(let o=t;o<t+a;o++)for(let t=0;t<s;t++)e.setPixelColor(i,o,n+t),e.setPixelColor(i,o,n+r-1-t);for(let o=n;o<n+r;o++)for(let n=0;n<s;n++)e.setPixelColor(i,t+n,o),e.setPixelColor(i,t+a-1-n,o)}}class wt{#Oe;constructor(e){this.#Oe=e}async verify({verificationArea:e,staticLocators:t,description:n}){let a,r=[];const i=yt.getOptions();if(Array.isArray(t)&&t.length>0)for(const n of t){let t=e+n;r.push(t)}else a=""!==e?e+pe:pe;yt.incrementCounter();const s=`${yt.getSSCount().toString().padStart(3,"0")}_${n.replace(/[^\w\s]/gi,"").replace(/\s+/g,"")}.png`;if(!i?.sanityCapture&&i?.i18nVerify){const e=Ce(it.reviewedReports(),s);await this.#Ge(e)}if(i?.i18nVerify||i?.sanityCapture)try{if(r.length>0)for(const t of r)await this.#Ve(e,t,s,n,i?.i18nVerify);else await this.#Qe(e,a,s,n,i?.i18nVerify)}catch(e){st.error("Elements not found under specified locator on page: ",n)}else st.info("Skipped i18n verification as per user configuration...")}async#Ve(e,t,n,a,r=!1){const i=await this.#Oe.getElement(t);if(i&&await this.#Oe.isElementPresent(i)){let t;try{t=await this.#Oe.getElementString(i);try{await this.#qe({verificationArea:e,ele:i,img_name:n,str:t,desc:a,doI18nVerification:r})}catch(e){st.error("Error generating report of element:",e)}}catch(e){st.error("Error getting text of element:",e)}}else st.error("No element found:",t)}async#Qe(e,t,n,a,r=!1){const i=await this.#Oe.getElements(t);if(i.length>0)for(const t of i)if(await this.#Oe.isElementPresent(t)){let i;try{i=await this.#Oe.getElementStrings(t);try{for(const s of i)await this.#qe({verificationArea:e,el:t,img_name:n,str:s,desc:a,doI18nVerification:r})}catch(e){st.error("Error generating report of element:",e)}}catch(e){st.error("Error getting text of elements:",e)}}if(await this.#Oe.checkIfIframeIsPresent()){const e=await this.#Oe.getElements("//iframe");st.debug(`Total ${e.length} iframes are located on the ${a}`),await this.#Be({iframes:e,img_name:n,desc:a,doI18nVerification:r})}}async#qe({verificationArea:t,el:n,img_name:a,str:r,desc:i,iframePresent:s=!1,doI18nVerification:o=!1}){if("string"!=typeof r||!r||0===Number(r))return;const l=Ce(it.reviewedReports(r,a),a);let c,d,u=!0;if(o?(it.incrementCount(le,r,l,i),c=qe.getIssueType(r),c&&l&&"function"==typeof it[c]&&(d=Ce(it[c](r,a),a))):(c=le,d=Ce(it.reviewedReports(r,a),a),u=!1),d){e.existsSync(l)||await this.#Ge(l),e.existsSync(l)&&!e.existsSync(d)&&e.copyFileSync(l,d);const a=this.#He(c,r);it.incrementCount(c,r,d,i),u&&(this.#Oe.onScreenStringHighlight(n,a),await this.#Ye({verificationArea:t,el:n,color:a,src_img:l,dest_img:d,str:r,iframePresent:s,desc:i}))}}async#Ye({verificationArea:e,el:t,color:n,dest_img:a,iframePresent:r}){let i,s=await this.#Ze(t);const o=A;if(r){i=e;const t=["x","y"];for(const e of t)e in s&&e in i&&(s[e]=i[e]+s[e])}else if(!yt.options?.sanityCapture){const t=await this.#Oe.getElement(e);i=await this.#Ze(t)}yt.options?.sanityCapture||await vt.drawRectangle(i,o,a),await vt.drawRectangle(s,n,a)}async#Ge(e){try{await this.#Oe.captureScreenshot(e)}catch(e){st.error("unable to capture screenshot")}}async#Ze(e){const t=await this.#Oe.getElementDimension(e);return{x:t[0],y:t[1],height:t[2],width:t[3]}}#He(e,t){return st.debug(`"${t}" - ${de[e][1]}${ue[e]}`),de[e][0]}async#Be({iframes:e,img_name:t,desc:n,doI18nVerification:a=!1}){for(const r of e){const e=await this.#Oe.getElementID(r);if(e&&""!==e){const i=await this.#Ze(r);this.#Oe.switchIframe(e),this.#Oe.pause(2);const s=await this.#Oe.getElement("//body");if(await this.#Oe.isElementPresent(s),!await this.#Oe.checkIfIframeBodyIsEmpty()){const e=await this.#Oe.getElements("//*[normalize-space(text())]");if(e.length>0)for(const r of e)if(await this.#Oe.isElementPresent(r)){let e=await this.#Oe.getElementStrings(r);try{for(const s of e)await this.#qe({verificationArea:i,el:r,img_name:t,str:s,desc:n,iframePresent:!0,doI18nVerification:a})}catch(e){st.error("Error generating report of iframe elements:",e)}}}}await this.#Oe.switchToParentframe()}}}export{yt as C,wt as I,st as L,it as R,x as S,Je as a,ye as b,ft as c,We as g,Ce as j,Ze as l};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeesoft/i18n-verify",
3
- "version": "2.2.1",
3
+ "version": "2.2.2",
4
4
  "description": "Library to perform I18n verification over Nightwatch or WebdriverIO frameworks",
5
5
  "main": "dist/index.mjs",
6
6
  "module": "dist/index.mjs",