{"version":3,"file":"mobile.languages.structured.js","mappings":"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","sources":["webpack://mfModules/./src/mobile.languages.structured/LanguageSearcher.js","webpack://mfModules/./src/mobile.languages.structured/mobile.languages.structured.js","webpack://mfModules/./src/mobile.languages.structured/rtlLanguages.js","webpack://mfModules/./src/mobile.languages.structured/util.js"],"sourcesContent":["const\n\tView = require( '../mobile.startup/View' ),\n\tutil = require( '../mobile.startup/util' ),\n\tlangUtil = require( './util' );\n\n/**\n * Overlay displaying a structured list of languages for a page, only accessible via\n * the {@link Hooks~'mobileFrontend.languageSearcher.onOpen' mobileFrontend.languageSearcher.onOpen hook}.\n *\n * @hideconstructor\n */\nclass LanguageSearcher extends View {\n\t/**\n\t * @param {Object} props Configuration options\n\t * @param {Object[]} props.languages list of language objects as returned by the API\n\t * @param {Array|boolean} props.variants language variant objects\n\t *  or false if no variants exist\n\t * @param {boolean} props.showSuggestedLanguages If the suggested languages\n\t *  section should be rendered.\n\t * @param {string} [props.deviceLanguage] the device's primary language\n\t * @param {Function} [props.onOpen] callback that fires on opening the searcher\n\t */\n\tconstructor( props ) {\n\t\t/**\n\t\t * @prop {StructuredLanguages} languages` JSDoc.\n\t\t */\n\t\tconst languages = langUtil.getStructuredLanguages(\n\t\t\tprops.languages,\n\t\t\tprops.variants,\n\t\t\tlangUtil.getFrequentlyUsedLanguages(),\n\t\t\tprops.showSuggestedLanguages,\n\t\t\tprops.deviceLanguage\n\t\t);\n\n\t\tsuper(\n\t\t\tutil.extend(\n\t\t\t\t{\n\t\t\t\t\tclassName: 'language-searcher',\n\t\t\t\t\tevents: {\n\t\t\t\t\t\t'click a': 'onLinkClick',\n\t\t\t\t\t\t'click .language-search-banner': 'onSearchBannerClick',\n\t\t\t\t\t\t'input .search': 'onSearchInput'\n\t\t\t\t\t},\n\t\t\t\t\t// the rest are template properties\n\t\t\t\t\tinputPlaceholder: mw.msg( 'mobile-frontend-languages-structured-overlay-search-input-placeholder' ),\n\t\t\t\t\t// we can't rely on CSS only to uppercase the headings. See https://stackoverflow.com/questions/3777443/css-text-transform-not-working-properly-for-turkish-characters\n\t\t\t\t\tallLanguagesHeader: mw.msg( 'mobile-frontend-languages-structured-overlay-all-languages-header' ).toLocaleUpperCase(),\n\t\t\t\t\tsuggestedLanguagesHeader: mw.msg( 'mobile-frontend-languages-structured-overlay-suggested-languages-header' ).toLocaleUpperCase(),\n\t\t\t\t\tnoResultsFoundHeader: mw.msg( 'mobile-frontend-languages-structured-overlay-no-results' ),\n\t\t\t\t\tnoResultsFoundMessage: mw.msg( 'mobile-frontend-languages-structured-overlay-no-results-body' ),\n\t\t\t\t\tallLanguages: languages.all,\n\t\t\t\t\tallLanguagesCount: languages.all.length,\n\t\t\t\t\tsuggestedLanguages: languages.suggested,\n\t\t\t\t\tsuggestedLanguagesCount: languages.suggested.length,\n\t\t\t\t\tshowSuggestedLanguagesHeader: languages.suggested.length > 0\n\t\t\t\t},\n\t\t\t\tprops\n\t\t\t)\n\t\t);\n\n\t\t// defer event to be emitted after event handler has been registered\n\t\tconst onOpen = props.onOpen;\n\t\tif ( !onOpen ) {\n\t\t\treturn;\n\t\t}\n\t\tsetTimeout( () => {\n\t\t\tonOpen( this );\n\t\t}, 0 );\n\t}\n\n\t/**\n\t * @inheritdoc\n\t */\n\tget template() {\n\t\treturn util.template( `\n<div class=\"panel\">\n\t<div class=\"panel-body search-box\">\n\t\t<input type=\"search\" class=\"search\" placeholder=\"{{inputPlaceholder}}\">\n\t</div>\n</div>\n\n<div class=\"overlay-content-body\">\n\t{{#showSuggestedLanguagesHeader}}\n\t<h3 class=\"list-header\">{{suggestedLanguagesHeader}}</h3>\n\t{{/showSuggestedLanguagesHeader}}\n\t{{#suggestedLanguagesCount}}\n\t<ol class=\"site-link-list suggested-languages\">\n\t\t{{#suggestedLanguages}}\n\t\t\t<li>\n\t\t\t\t<a href=\"{{url}}\" class=\"{{lang}}\" hreflang=\"{{lang}}\" lang=\"{{lang}}\" dir=\"{{dir}}\">\n\t\t\t\t\t<span class=\"autonym\">{{autonym}}</span>\n\t\t\t\t\t{{#title}}\n\t\t\t\t\t\t<span class=\"title\">{{title}}</span>\n\t\t\t\t\t{{/title}}\n\t\t\t\t</a>\n\t\t\t</li>\n\t\t{{/suggestedLanguages}}\n\t</ol>\n\t{{/suggestedLanguagesCount}}\n\t{{#bannerHTML}}\n\t<div class=\"language-search-banner\">\n\t\t{{{.}}}\n\t</div>\n\t{{/bannerHTML}}\n\t{{#allLanguagesCount}}\n\t<h3 class=\"list-header\">{{allLanguagesHeader}} ({{allLanguagesCount}})</h3>\n\t<ul class=\"site-link-list all-languages\">\n\t\t{{#allLanguages}}\n\t\t\t<li>\n\t\t\t\t<a href=\"{{url}}\" class=\"{{lang}}\" hreflang=\"{{lang}}\" lang=\"{{lang}}\" dir=\"{{dir}}\">\n\t\t\t\t\t<span class=\"autonym\">{{autonym}}</span>\n\t\t\t\t\t{{#title}}\n\t\t\t\t\t\t<span class=\"title\">{{title}}</span>\n\t\t\t\t\t{{/title}}\n\t\t\t\t</a>\n\t\t\t</li>\n\t\t{{/allLanguages}}\n\t</ul>\n\t{{/allLanguagesCount}}\n\t<section class=\"empty-results hidden\">\n\t\t<h4 class=\"empty-results-header\">{{noResultsFoundHeader}}</h4>\n\t\t<p class=\"empty-results-body\">{{noResultsFoundMessage}}</p>\n\t</section>\n</div>\n\t` );\n\t}\n\n\t/**\n\t * @inheritdoc\n\t */\n\tpostRender() {\n\t\t// cache\n\t\tthis.$siteLinksList = this.$el.find( '.site-link-list' );\n\t\tthis.$languageItems = this.$siteLinksList.find( 'a' );\n\t\tthis.$subheaders = this.$el.find( 'h3' );\n\t\tthis.$emptyResultsSection = this.$el.find( '.empty-results' );\n\t}\n\n\t/**\n\t * Method that can be called outside MF extension to render\n\t * a banner inside the language overlay.\n\t *\n\t * Stable for use inside ContentTranslation\n\t *\n\t * @param {string} bannerHTML\n\t * @param {string} firstMissingLanguage\n\t */\n\taddBanner( bannerHTML, firstMissingLanguage ) {\n\t\tthis.options.bannerHTML = bannerHTML;\n\t\tthis.options.bannerFirstLanguage = firstMissingLanguage;\n\t\tthis.options.showSuggestedLanguagesHeader = true;\n\t\tthis.render();\n\t}\n\n\tonSearchBannerClick() {\n\t\tthis.$el.find( '.search' ).val( this.options.bannerFirstLanguage ).trigger( 'input' );\n\t}\n\n\t/**\n\t * Article link click event handler\n\t *\n\t * @param {jQuery.Event} ev\n\t */\n\tonLinkClick( ev ) {\n\t\tconst $link = this.$el.find( ev.currentTarget ),\n\t\t\tlang = $link.attr( 'lang' );\n\t\t/**\n\t\t * Internal for use in GrowthExperiments only.\n\t\t *\n\t\t * @event ~'mobileFrontend.languageSearcher.linkClick'\n\t\t * @memberof Hooks\n\t\t */\n\t\tmw.hook( 'mobileFrontend.languageSearcher.linkClick' ).fire( lang );\n\t\tlangUtil.saveLanguageUsageCount( lang, langUtil.getFrequentlyUsedLanguages() );\n\t}\n\n\t/**\n\t * Search input handler\n\t *\n\t * @param {jQuery.Event} ev Event object.\n\t */\n\tonSearchInput( ev ) {\n\t\tconst searchOrigin = ev.originalEvent === undefined ? 'entrypoint-banner' : 'ui';\n\n\t\tthis.filterLanguages( ev.target.value.toLowerCase(), searchOrigin );\n\t}\n\n\t/**\n\t * Filter the language list to only show languages that match the current search term.\n\t *\n\t * @param {string} searchQuery of search term (lowercase).\n\t * @param {'entrypoint-banner'|'ui'} searchOrigin for internal use by CX entrypoints only\n\t */\n\tfilterLanguages( searchQuery, searchOrigin ) {\n\t\tconst filteredList = [];\n\n\t\tif ( searchQuery ) {\n\t\t\tthis.options.languages.forEach( ( language ) => {\n\t\t\t\tconst langname = language.langname;\n\t\t\t\t// search by language code or language name\n\t\t\t\tif ( language.autonym.toLowerCase().indexOf( searchQuery ) > -1 ||\n\t\t\t\t\t\t( langname && langname.toLowerCase().indexOf( searchQuery ) > -1 ) ||\n\t\t\t\t\t\tlanguage.lang.toLowerCase().indexOf( searchQuery ) > -1\n\t\t\t\t) {\n\t\t\t\t\tfilteredList.push( language.lang );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tif ( this.options.variants ) {\n\t\t\t\tthis.options.variants.forEach( ( variant ) => {\n\t\t\t\t\t// search by variant code or variant name\n\t\t\t\t\tif ( variant.autonym.toLowerCase().indexOf( searchQuery ) > -1 ||\n\t\t\t\t\t\tvariant.lang.toLowerCase().indexOf( searchQuery ) > -1\n\t\t\t\t\t) {\n\t\t\t\t\t\tfilteredList.push( variant.lang );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tthis.$languageItems.addClass( 'hidden' );\n\t\t\tif ( filteredList.length ) {\n\t\t\t\tthis.$siteLinksList.find(\n\t\t\t\t\t`.${ mw.util.escapeRegExp( filteredList.join( ',.' ) ) }`\n\t\t\t\t).removeClass( 'hidden' );\n\t\t\t\tthis.$emptyResultsSection.addClass( 'hidden' );\n\t\t\t} else {\n\t\t\t\tthis.$emptyResultsSection.removeClass( 'hidden' );\n\t\t\t\t// Fire with the search query and the DOM element corresponding to no-results\n\t\t\t\t// message so that it can be customized in hook handler\n\t\t\t\t/**\n\t\t\t\t * Internal for use in ContentTranslation only.\n\t\t\t\t *\n\t\t\t\t * @event ~'mobileFrontend.editorOpening'\n\t\t\t\t * @memberof Hooks\n\t\t\t\t */\n\t\t\t\tmw.hook( 'mobileFrontend.languageSearcher.noresults' )\n\t\t\t\t\t.fire( searchQuery, this.$emptyResultsSection.get( 0 ), searchOrigin );\n\t\t\t}\n\t\t\tthis.$siteLinksList.addClass( 'filtered' );\n\t\t\tthis.$subheaders.addClass( 'hidden' );\n\t\t} else {\n\t\t\tthis.$languageItems.removeClass( 'hidden' );\n\t\t\tthis.$siteLinksList.removeClass( 'filtered' );\n\t\t\tthis.$subheaders.removeClass( 'hidden' );\n\t\t\tthis.$emptyResultsSection.addClass( 'hidden' );\n\t\t}\n\t}\n}\n\nmodule.exports = LanguageSearcher;\n","const\n\tm = require( '../mobile.startup/moduleLoaderSingleton' ),\n\tLanguageSearcher = require( './LanguageSearcher' );\n\n// Needed because LanguageSearcher is lazy loaded, and if we try to use require\n// (instead of m.require), webpack will excise it into mobile.common.\nm.define( 'mobile.languages.structured/LanguageSearcher', LanguageSearcher );\n","/**\n * @private\n */\nmodule.exports = [\n\t'acm',\n\t'aeb',\n\t'aeb-arab',\n\t'apc',\n\t'ar',\n\t'arc',\n\t'arq',\n\t'ary',\n\t'arz',\n\t'azb',\n\t'bcc',\n\t'bgn',\n\t'bqi',\n\t'ckb',\n\t'dv',\n\t'fa',\n\t'glk',\n\t'he',\n\t'hno',\n\t'khw',\n\t'kk-arab',\n\t'kk-cn',\n\t'ks',\n\t'ks-arab',\n\t'ku-arab',\n\t'lki',\n\t'lrc',\n\t'luz',\n\t'ms-arab',\n\t'mzn',\n\t'nqo',\n\t'pnb',\n\t'ps',\n\t'sd',\n\t'sdh',\n\t'skr',\n\t'skr-arab',\n\t'ug',\n\t'ug-arab',\n\t'ur',\n\t'yi'\n];\n","const\n\tmfUtils = require( '../mobile.startup/util' ),\n\trtlLanguages = require( './rtlLanguages' );\n\n/**\n * @typedef {Object} Language\n * @prop {string} autonym of language e.g. français\n * @prop {string} langname in the user's current language e.g French\n * @prop {string} title of the page in the language e.g. Espagne\n * @prop {string} dir (rtl or ltr)\n * @prop {string} url of the page\n *\n * @typedef {Object} SuggestedLanguage\n * @prop {string} autonym of language e.g. français\n * @prop {string} langname in the user's current language e.g French\n * @prop {string} title of the page in the language e.g. Espagne\n * @prop {string} dir (rtl or ltr)\n * @prop {string} url of the page\n * @prop {number} frequency of times the language has been used by the given user\n *\n * @typedef {Object} StructuredLanguages\n * @prop {Language[]} all languages that are available\n * @prop {SuggestedLanguage[]} suggested languages based on users browsing history\n * @ignore\n */\n\n/**\n * Return the device language if it's in the list of article languages.\n * If the language is a variant of a general language, and if the article\n * is not available in that language, then return the general language\n * if article is available in it. For example, if the device language is\n * 'en-gb', and the article is only available in 'en', then return 'en'.\n *\n * @ignore\n * @param {Object[]} languages list of language objects as returned by the API\n * @param {string|undefined} deviceLanguage the device's primary language\n * @return {string|undefined} Return undefined if the article is not available in\n *  the (general or variant) device language\n */\nfunction getDeviceLanguageOrParent( languages, deviceLanguage ) {\n\tlet parentLanguage;\n\n\tconst\n\t\thasOwn = Object.prototype.hasOwnProperty,\n\t\tdeviceLanguagesWithVariants = {};\n\n\tif ( !deviceLanguage ) {\n\t\treturn;\n\t}\n\n\t// Are we dealing with a variant?\n\tconst index = deviceLanguage.indexOf( '-' );\n\tif ( index !== -1 ) {\n\t\tparentLanguage = deviceLanguage.slice( 0, index );\n\t}\n\n\tlanguages.forEach( ( language ) => {\n\t\tif ( language.lang === parentLanguage || language.lang === deviceLanguage ) {\n\t\t\tdeviceLanguagesWithVariants[ language.lang ] = true;\n\t\t}\n\t} );\n\n\tif ( hasOwn.call( deviceLanguagesWithVariants, deviceLanguage ) ) {\n\t\t// the device language is one of the available languages\n\t\treturn deviceLanguage;\n\t} else if ( hasOwn.call( deviceLanguagesWithVariants, parentLanguage ) ) {\n\t\t// no device language, but the parent language is one of the available languages\n\t\treturn parentLanguage;\n\t}\n}\n\n/**\n * Utility function for the structured language overlay\n *\n * @class util\n * @singleton\n * @private\n */\nmodule.exports = {\n\t/**\n\t * Determine whether a language is LTR or RTL\n\t * This works around T74153 and T189036\n\t * and the fact that adding dir attribute to HTML in core\n\t * at time of writing is memory-intensive\n\t * (I7cd8a3117f49467e3ff26f35371459a667c71470)\n\t *\n\t * @memberof util\n\t * @instance\n\t * @param {Object} language with 'lang' key.\n\t * @return {Object} language with 'lang' key and new 'dir' key.\n\t */\n\tgetDir( language ) {\n\t\tconst dir = rtlLanguages.indexOf( language.lang ) > -1 ? 'rtl' : 'ltr';\n\t\treturn mfUtils.extend( {}, language, { dir } );\n\t},\n\n\t/**\n\t * Return two sets of languages: suggested and all (everything else)\n\t *\n\t * Suggested languages are the ones that the user has used before. This also\n\t * includes the user device's primary language. Suggested languages are ordered\n\t * by frequency in descending order. The device's language is always at the top.\n\t * This group also includes the variants.\n\t *\n\t * All languages are the languages that are not suggested.\n\t * Languages in this list are ordered in the lexicographical order of\n\t * their language names.\n\t *\n\t * @memberof util\n\t * @ignore\n\t * @instance\n\t * @param {Object[]} languages list of language objects as returned by the API\n\t * @param {Array|boolean} variants language variant objects or false if no variants exist\n\t * @param {Object} frequentlyUsedLanguages list of the frequently used languages\n\t * @param {boolean} showSuggestedLanguages\n\t * @param {string} [deviceLanguage] the device's primary language\n\t * @return {StructuredLanguages}\n\t */\n\tgetStructuredLanguages(\n\t\tlanguages,\n\t\tvariants,\n\t\tfrequentlyUsedLanguages,\n\t\tshowSuggestedLanguages,\n\t\tdeviceLanguage\n\t) {\n\t\tconst hasOwn = Object.prototype.hasOwnProperty;\n\n\t\tlet maxFrequency = 0,\n\t\t\tminFrequency = 0,\n\t\t\tsuggestedLanguages = [],\n\t\t\tallLanguages = [];\n\n\t\t// Is the article available in the user's device language?\n\t\tdeviceLanguage = getDeviceLanguageOrParent( languages, deviceLanguage );\n\t\tif ( deviceLanguage ) {\n\t\t\tObject.keys( frequentlyUsedLanguages ).forEach( ( language ) => {\n\t\t\t\tconst frequency = frequentlyUsedLanguages[ language ];\n\t\t\t\tmaxFrequency = maxFrequency < frequency ? frequency : maxFrequency;\n\t\t\t\tminFrequency = minFrequency > frequency ? frequency : minFrequency;\n\t\t\t} );\n\n\t\t\t// Make the device language the most frequently used one so that\n\t\t\t// it appears at the top of the list when sorted by frequency.\n\t\t\tfrequentlyUsedLanguages[ deviceLanguage ] = maxFrequency + 1;\n\t\t}\n\n\t\t/**\n\t\t * @param {Object} language\n\t\t * @return {Object} which has 'dir' key.\n\t\t */\n\t\tconst addLangDir = ( language ) => {\n\t\t\tif ( language.dir ) {\n\t\t\t\treturn language;\n\t\t\t} else {\n\t\t\t\treturn this.getDir( language );\n\t\t\t}\n\t\t};\n\n\t\t// Separate languages into suggested and all languages.\n\t\tif ( showSuggestedLanguages ) {\n\t\t\tlanguages.map( addLangDir ).forEach( ( language ) => {\n\t\t\t\tif ( hasOwn.call( frequentlyUsedLanguages, language.lang ) ) {\n\t\t\t\t\tlanguage.frequency = frequentlyUsedLanguages[language.lang];\n\t\t\t\t\tsuggestedLanguages.push( language );\n\t\t\t\t} else {\n\t\t\t\t\tallLanguages.push( language );\n\t\t\t\t}\n\t\t\t} );\n\t\t} else {\n\t\t\tallLanguages = languages.map( addLangDir );\n\t\t}\n\n\t\t// Add variants to the suggested languages list and assign the lowest\n\t\t// frequency because the variant hasn't been clicked on yet.\n\t\t// Note that the variants data doesn't contain the article title, thus\n\t\t// we cannot show it for the variants.\n\t\tif ( variants && showSuggestedLanguages ) {\n\t\t\tvariants.map( addLangDir ).forEach( ( variant ) => {\n\t\t\t\tif ( hasOwn.call( frequentlyUsedLanguages, variant.lang ) ) {\n\t\t\t\t\tvariant.frequency = frequentlyUsedLanguages[variant.lang];\n\t\t\t\t} else {\n\t\t\t\t\tvariant.frequency = minFrequency - 1;\n\t\t\t\t}\n\t\t\t\tsuggestedLanguages.push( variant );\n\t\t\t} );\n\t\t}\n\n\t\t// sort suggested languages in descending order by frequency\n\t\tsuggestedLanguages = suggestedLanguages.sort( ( a, b ) => b.frequency - a.frequency );\n\n\t\t/**\n\t\t * Compare language names lexicographically\n\t\t *\n\t\t * @param {Object} a first language\n\t\t * @param {Object} b second language\n\t\t * @return {number} Comparison value, 1 or -1\n\t\t */\n\t\tfunction compareLanguagesByLanguageName( a, b ) {\n\t\t\treturn a.autonym.toLocaleLowerCase() < b.autonym.toLocaleLowerCase() ? -1 : 1;\n\t\t}\n\n\t\tallLanguages = allLanguages.sort( compareLanguagesByLanguageName );\n\t\treturn {\n\t\t\tsuggested: suggestedLanguages,\n\t\t\tall: allLanguages\n\t\t};\n\t},\n\n\t/**\n\t * Return a map of frequently used languages on the current device.\n\t *\n\t * @memberof util\n\t * @instance\n\t * @return {Object}\n\t */\n\tgetFrequentlyUsedLanguages() {\n\t\tconst languageMap = mw.storage.get( 'langMap' );\n\n\t\treturn languageMap ? JSON.parse( languageMap ) : {};\n\t},\n\n\t/**\n\t * Save the frequently used languages to the user's device\n\t *\n\t * @memberof util\n\t * @instance\n\t * @param {Object} languageMap\n\t */\n\tsaveFrequentlyUsedLanguages( languageMap ) {\n\t\tmw.storage.set( 'langMap', JSON.stringify( languageMap ) );\n\t},\n\n\t/**\n\t * Increment the current language usage by one and save it to the device.\n\t * Cap the result at 100.\n\t *\n\t * @memberof util\n\t * @instance\n\t * @param {string} languageCode\n\t * @param {Object} frequentlyUsedLanguages list of the frequently used languages\n\t */\n\tsaveLanguageUsageCount( languageCode, frequentlyUsedLanguages ) {\n\t\tlet count = frequentlyUsedLanguages[ languageCode ] || 0;\n\n\t\tcount += 1;\n\t\t// cap at 100 as this is enough data to work on\n\t\tfrequentlyUsedLanguages[ languageCode ] = count > 100 ? 100 : count;\n\t\tthis.saveFrequentlyUsedLanguages( frequentlyUsedLanguages );\n\t}\n};\n"],"names":["View","util","langUtil","module","exports","constructor","props","languages","getStructuredLanguages","variants","getFrequentlyUsedLanguages","showSuggestedLanguages","deviceLanguage","super","extend","className","events","inputPlaceholder","mw","msg","allLanguagesHeader","toLocaleUpperCase","suggestedLanguagesHeader","noResultsFoundHeader","noResultsFoundMessage","allLanguages","all","allLanguagesCount","length","suggestedLanguages","suggested","suggestedLanguagesCount","showSuggestedLanguagesHeader","onOpen","setTimeout","this","template","postRender","$siteLinksList","$el","find","$languageItems","$subheaders","$emptyResultsSection","addBanner","bannerHTML","firstMissingLanguage","options","bannerFirstLanguage","render","onSearchBannerClick","val","trigger","onLinkClick","ev","lang","currentTarget","attr","hook","fire","saveLanguageUsageCount","onSearchInput","searchOrigin","undefined","originalEvent","filterLanguages","target","value","toLowerCase","searchQuery","filteredList","forEach","language","langname","autonym","indexOf","push","variant","addClass","escapeRegExp","join","removeClass","get","m","LanguageSearcher","define","mfUtils","rtlLanguages","getDir","dir","frequentlyUsedLanguages","hasOwn","Object","prototype","hasOwnProperty","maxFrequency","minFrequency","parentLanguage","deviceLanguagesWithVariants","index","slice","call","getDeviceLanguageOrParent","keys","frequency","addLangDir","map","sort","a","b","toLocaleLowerCase","languageMap","storage","JSON","parse","saveFrequentlyUsedLanguages","set","stringify","languageCode","count"],"sourceRoot":""}