1const field = document.getElementById("search") 2const datasrc = [ 3 { label: "App Localization Services", value: "app_localization.html", keywords: "translate internationalization l10n i18n application" }, 4 { label: "iOS Localization Services", value: "ios_localization_services.html", keywords: "iphone ipad xcode Localizable stringsdict xliff xcloc siri" }, 5 { 6 label: "AI translation review (MTPE)", 7 value: "ai_assisted_translation_mtpe.html", 8 keywords: "AI review claude gen generative chatgpt gpt artificial intelligence machine post editing mtpe", 9 }, 10 { label: "Contact us", value: "contact.html", keywords: "Benjamin Zadik Salim Martell write message email e-mail" }, 11 { label: "Our team", value: "team.html", keywords: "about translators company info" }, 12 { label: "Frequently Asked Questions", value: "app-localization-faq.html", keywords: "help support" }, 13 { label: "Babble Blog", value: "/blog", keywords: "news" }, 14 { label: "Game Localization", value: "game_localization.html", keywords: "video console sony nintendo xbox playstation ps4 ps3 ps5 casual translate" }, 15 { label: "Website Localization", value: "website-localization.html", keywords: "html wordpress joomla drupal blog translate" }, 16 { label: "App Store Description", value: "app-store-app-description-writing.html", keywords: "english apple google play appstore writing copywriting example" }, 17 { label: "Press Releases", value: "app-press-release-writing.html", keywords: "english news pr prmac write writing copywriting example" }, 18 { label: "Transcreation", value: "transcreation.html", keywords: "english language creative ads advertising SEO writing copywriting transcreate" }, 19 { label: "Pseudolocalization", value: "pseudolocalization.html", keywords: "testing test formats xliff strings pot properties xml pseudo qa quality assurance" }, 20 { label: "iOS Localization Tutorial", value: "iphone_app_localization.html", keywords: "do iphone step xcode xliff export import how help example guide" }, 21 { label: "SwiftUI Localization Tutorial", value: "swiftui_localization_tutorial.html", keywords: "ios step xcode xliff export import how help example guide" }, 22 { label: "Android Localization Services", value: "android_localization_services.html", keywords: "google studio xml values pixel samsung galaxy" }, 23 { 24 label: "Android Localization Tutorial", 25 value: "android_app_localization_translation.html", 26 keywords: "do android google step studio strings.xml export import xml how help example guide", 27 }, 28 { 29 label: "Adding Localized App Descriptions", 30 value: "add-localized-app-store-description-tutorial.html", 31 keywords: "itunes app store connect keyword languages how help example guide", 32 }, 33 { label: "List of iOS & Android Language Codes", value: "iOS-Language-Codes-ISO-639.html", keywords: "lproj xcode official supported apple google languages how help guide" }, 34 { 35 label: "iOS Multilingual Term Glossary", 36 value: "apple-ios-localization-term-glossary.html", 37 keywords: 38 "official supported dictionary translation translate keyword term base languages russian spanish chinese dutch korean french italian german korean japanese simplified traditional", 39 }, 40 { label: "Localized Screenshots QA", value: "localized-screenshots-qa-review.html", keywords: "quality assurance how help test testing review revision in-app device guide" }, 41 { label: "Localization Managers (LPM)", value: "localization-manager-vendors.html", keywords: "project lsp language service provider vendor why compare best practices" }, 42 { label: "Localization Style Guides", value: "localization-style-guide-tips-best-practices.html", keywords: "project lpm lsp language service provider best practices" }, 43 { label: "Localizing Your Help Center", value: "localizing-zendesk-wix-help-center.html", keywords: "knowledge base files export import translate" }, 44 { label: "Crowdsourcing Management", value: "crowdsource_translation_management_localization.html", keywords: "crowdin lsp vendor help volunteers users" }, 45 { label: "Crowdin + Babble-on", value: "crowdin.html", keywords: "crowdsourcing crowdsource" }, 46 { label: "Pricing", value: "pricing.html", keywords: "cost money fee monthly setup hosting word roi estimat smartling onesky much" }, 47 { label: "Plural translation in iOS", value: "ios_plurals_localizable_stringsdict.html", keywords: "stringsdict plist pluralization tutorial guide" }, 48 { label: "Accidental Tech Podcast", value: "atp.html", keywords: "atp accidental tech podcast ad advertisement discount coupon" }, 49 50] 51 52const DEFAULTS = { 53 threshold: 2, 54 maximumItems: 5, 55 highlightTyped: true, 56 highlightClass: "text-primary", 57} 58 59class Autocomplete { 60 constructor(field, options) { 61 this.field = field 62 this.options = Object.assign({}, DEFAULTS, options) 63 this.dropdown = null 64 65 field.parentNode.classList.add("dropdown") 66 field.setAttribute("data-toggle", "dropdown") 67 //field.classList.add('dropdown-toggle'); 68 69 const dropdown = ce(`<div class="dropdown-menu" ></div>`) 70 if (this.options.dropdownClass) dropdown.classList.add(this.options.dropdownClass) 71 72 insertAfter(dropdown, field) 73 74 this.dropdown = new bootstrap.Dropdown(field, this.options.dropdownOptions) 75 76 field.addEventListener("click", (e) => { 77 if (this.createItems() === 0) { 78 e.stopPropagation() 79 this.dropdown.hide() 80 } 81 }) 82 83 field.addEventListener("input", () => { 84 if (this.options.onInput) this.options.onInput(this.field.value) 85 this.renderIfNeeded() 86 }) 87 88 field.addEventListener("keydown", (e) => { 89 if (e.keyCode === 27) { 90 this.dropdown.hide() 91 return 92 } 93 }) 94 95 field.addEventListener("blur", (e) => { 96 this.dropdown.hide() 97 }) 98 } 99 100 setData(data) { 101 this.options.data = data 102 } 103 104 renderIfNeeded() { 105 if (this.createItems() > 0) this.dropdown.show() 106 else this.field.click() 107 } 108 109 createItem(lookup, item) { 110 let label 111 const idx = item.label.toLowerCase().indexOf(lookup.toLowerCase()) 112 if (this.options.highlightTyped && idx >= 0) { 113 const className = Array.isArray(this.options.highlightClass) 114 ? this.options.highlightClass.join(" ") 115 : typeof this.options.highlightClass == "string" 116 ? this.options.highlightClass 117 : "" 118 label = 119 item.label.substring(0, idx) + 120 `<span class="${className}">${item.label.substring(idx, idx + lookup.length)}</span>` + 121 item.label.substring(idx + lookup.length, item.label.length) 122 } else label = item.label 123 return ce( 124 `<button type="button" class="dropdown-item fw-bold" data-value="${item.value}">${label}<small class="text-muted ms-2" data-value="${item.value}"> â ${item.value}</small></button>` 125 ) 126 } 127 128 createItems() { 129 const lookup = this.field.value 130 if (lookup.length < this.options.threshold) { 131 this.dropdown.hide() 132 return 0 133 } 134 135 const items = this.field.nextSibling 136 items.innerHTML = "" 137
138 let count = 0 139 for (let i = 0; i < this.options.data.length; i++) { 140 const { label, value, keywords } = this.options.data[i] 141 const item = { label, value, keywords } 142 var bloodhound = item.label + " " + item.keywords + " " + item.value.replace(/(_|-)/g, " ") 143 if (bloodhound.toLowerCase().indexOf(lookup.toLowerCase()) >= 0) { 144 // if (item.label.toLowerCase().indexOf(lookup.toLowerCase()) >= 0) { 145 items.appendChild(this.createItem(lookup, item)) 146 if (this.options.maximumItems > 0 && ++count >= this.options.maximumItems) break 147 } 148 } 149 150 this.field.nextSibling.querySelectorAll(".dropdown-item").forEach((item) => { 151 item.addEventListener("click", (e) => { 152 let dataValue = e.target.getAttribute("data-value") 153 let dataText = e.target.innerText.substring(0, e.target.innerText.indexOf("â")).trim() 154 this.field.value = dataText 155 if (this.options.onSelectItem) 156 this.options.onSelectItem({ 157 value: e.target.dataset.value, 158 label: dataText, 159 }) 160 this.dropdown.hide() 161 }) 162 }) 163 164 return items.childNodes.length 165 } 166} 167 168/** 169 * @param html 170 * @returns {Node} 171 */ 172function ce(html) { 173 let div = document.createElement("div") 174 div.innerHTML = html 175 return div.firstChild 176} 177 178/** 179 * @param elem 180 * @param refElem 181 * @returns {*} 182 */ 183function insertAfter(elem, refElem) { 184 return refElem.parentNode.insertBefore(elem, refElem.nextSibling) 185} 186 187const ac = new Autocomplete(field, { 188 data: datasrc, 189 maximumItems: 5, 190 threshold: 0, 191 highlightTyped: true, 192 highlightClass: "text-primary h6", 193 onSelectItem: ({ label, value }) => { 194 window.location.href = "https://www.ibabbleon.com/" + value 195 }, 196})
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.