From fc6060b67bd93be25c4cbbcd79604cdb2862372c Mon Sep 17 00:00:00 2001 From: Roman Bertolami Date: Mon, 2 Aug 2021 17:00:53 +0200 Subject: [PATCH 1/5] property tNoResults and tests for existing listLabel --- awesomplete.js | 7 ++++--- test/api/evaluateSpec.js | 18 ++++++++++++++++++ test/init/optionsSpec.js | 12 +++++++++++- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/awesomplete.js b/awesomplete.js index 95188f21..5113100d 100644 --- a/awesomplete.js +++ b/awesomplete.js @@ -39,7 +39,8 @@ var _ = function (input, o) { item: _.ITEM, replace: _.REPLACE, tabSelect: false, - listLabel: "Results List" + listLabel: "Results List", + tNoResults: "No results found" }, o); this.index = -1; @@ -328,7 +329,7 @@ _.prototype = { if (this.ul.children.length === 0) { - this.status.textContent = "No results found"; + this.status.textContent = this.tNoResults; // "No results found"; this.close({ reason: "nomatches" }); @@ -341,7 +342,7 @@ _.prototype = { else { this.close({ reason: "nomatches" }); - this.status.textContent = "No results found"; + this.status.textContent = this.tNoResults; // "No results found"; } } }; diff --git a/test/api/evaluateSpec.js b/test/api/evaluateSpec.js index b8107bb3..e1466ad8 100644 --- a/test/api/evaluateSpec.js +++ b/test/api/evaluateSpec.js @@ -18,6 +18,7 @@ describe("awesomplete.evaluate", function () { expect(this.subject.close).toHaveBeenCalledWith({ reason: "nomatches" }); + expect(this.subject.status.textContent).toBe("No results found") }); }); @@ -93,4 +94,21 @@ describe("awesomplete.evaluate", function () { expect(this.subject.index).toBe(-1); }); }); + + describe("with no results and German text", function () { + beforeEach(function () { + this.subject.tNoResults = "Keine Resultate gefunden"; + $.type(this.subject.input, "nosuchitem"); + }); + + it("closes completer", function () { + spyOn(this.subject, "close"); + this.subject.evaluate(); + + expect(this.subject.close).toHaveBeenCalledWith({ + reason: "nomatches" + }); + expect(this.subject.status.textContent).toBe("Keine Resultate gefunden") + }); + }); }); diff --git a/test/init/optionsSpec.js b/test/init/optionsSpec.js index fc60997c..732c6733 100644 --- a/test/init/optionsSpec.js +++ b/test/init/optionsSpec.js @@ -38,6 +38,14 @@ describe("Constructor options", function () { it("replaces input value with REPLACE", function () { expect(this.subject.replace).toEqual(Awesomplete.REPLACE); }); + + it("uses 'Results List' as list label", function () { + expect(this.subject.listLabel).toEqual("Results List"); + }); + + it("uses 'No results found' as tNoResults", function () { + expect(this.subject.tNoResults).toEqual("No results found"); + }); }); describe("with custom options in constructor", function () { @@ -50,7 +58,8 @@ describe("Constructor options", function () { filter: $.noop, sort: $.noop, item: $.noop, - replace: $.noop + replace: $.noop, + listLabel: 'new list label' }; }); @@ -58,6 +67,7 @@ describe("Constructor options", function () { expect(this.subject.minChars).toBe(3); expect(this.subject.maxItems).toBe(9); expect(this.subject.autoFirst).toBe(true); + expect(this.subject.listLabel).toBe("new list label"); }); it("overrides default functions", function () { From 75c0005db6cbb45e1246396a4c10cc8d10896c7c Mon Sep 17 00:00:00 2001 From: Roman Bertolami Date: Mon, 2 Aug 2021 17:49:28 +0200 Subject: [PATCH 2/5] add i18n fields --- awesomplete.js | 16 ++++++++++------ test/api/gotoSpec.js | 13 +++++++++++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/awesomplete.js b/awesomplete.js index 5113100d..5251470f 100644 --- a/awesomplete.js +++ b/awesomplete.js @@ -40,7 +40,11 @@ var _ = function (input, o) { replace: _.REPLACE, tabSelect: false, listLabel: "Results List", - tNoResults: "No results found" + tStatusResult: "${length} results found", + tNoResults: "No results found", + tStatusQueryTooShort: "Type ${minChars} or more characters for results.", + tStatusStartTyping: "Begin typing for results.", + tListItemText: "list item ${index} of ${length}" }, o); this.index = -1; @@ -63,7 +67,7 @@ var _ = function (input, o) { "aria-live": "assertive", "aria-atomic": true, inside: this.container, - textContent: this.minChars != 0 ? ("Type " + this.minChars + " or more characters for results.") : "Begin typing for results." + textContent: this.minChars != 0 ? this.tStatusQueryTooShort.replace("${minChars}", this.minChars) : this.tStatusStartTyping }); // Bind events @@ -260,7 +264,7 @@ _.prototype = { if (i > -1 && lis.length > 0) { lis[i].setAttribute("aria-selected", "true"); - this.status.textContent = lis[i].textContent + ", list item " + (i + 1) + " of " + lis.length; + this.status.textContent = lis[i].textContent + ", "+ this.tListItemText.replace("${index}", (i + 1)).replace("${length}", lis.length); this.input.setAttribute("aria-activedescendant", this.ul.id + "_item_" + this.index); @@ -329,20 +333,20 @@ _.prototype = { if (this.ul.children.length === 0) { - this.status.textContent = this.tNoResults; // "No results found"; + this.status.textContent = this.tNoResults; this.close({ reason: "nomatches" }); } else { this.open(); - this.status.textContent = this.ul.children.length + " results found"; + this.status.textContent = this.tStatusResult.replace("${length}", this.ul.children.length); } } else { this.close({ reason: "nomatches" }); - this.status.textContent = this.tNoResults; // "No results found"; + this.status.textContent = this.tNoResults; } } }; diff --git a/test/api/gotoSpec.js b/test/api/gotoSpec.js index 8a31dde5..fcfec69e 100644 --- a/test/api/gotoSpec.js +++ b/test/api/gotoSpec.js @@ -54,6 +54,19 @@ describe("awesomplete.goto", function () { }); }); + + describe("with German text and item index > -1", function () { + beforeEach(function () { + this.subject.tListItemText = "Listenelement ${index} von ${length}"; + this.subject.goto(0); + }); + + it("updates status", function () { + expect(this.subject.status.textContent).toBe("item1, Listenelement 1 von 3"); + }); + }); + + describe("with item index = -1", function () { beforeEach(function () { this.subject.goto(0); From 52da59e2fd7e6079846dba5e84234d872d73764e Mon Sep 17 00:00:00 2001 From: Roman Bertolami Date: Mon, 2 Aug 2021 17:59:14 +0200 Subject: [PATCH 3/5] doc --- README.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 48d7f564..1be38257 100644 --- a/README.md +++ b/README.md @@ -83,13 +83,19 @@ There are multiple customizations and properties able to be instantiated within ## Options -| JS Property | HTML Attribute | Description | Value | Default | -| ----------- | -------------- | ------------------------------------------------------------------------------- | ------- | ------------ | -| list | data-list | Where to find the list of suggestions. | Array of strings, HTML element, CSS selector (no groups, i.e. no commas), String containing a comma-separated list of items | N/A | -| minChars | data-minchars | Minimum characters the user has to type before the autocomplete popup shows up. | Number | 2 | -| maxItems | data-maxitems | Maximum number of suggestions to display. | Number | 10 | -| autoFirst | data-autofirst | Should the first element be automatically | Boolean | false | -| listLabel | data-listlabel | Denotes a label to be used as aria-label on the generated autocomplete list. | String | Results List | +| JS Property | HTML Attribute | Description | Value | Default | +|----------------------|---------------------------|---------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------| +| list | data-list | Where to find the list of suggestions. | Array of strings, HTML element, CSS selector (no groups, i.e. no commas), String containing a comma-separated list of items | N/A | +| minChars | data-minchars | Minimum characters the user has to type before the autocomplete popup shows up. | Number | 2 | +| maxItems | data-maxitems | Maximum number of suggestions to display. | Number | 10 | +| autoFirst | data-autofirst | Should the first element be automatically | Boolean | false | +| listLabel | data-listlabel | Denotes a label to be used as aria-label on the generated autocomplete list. | String | Results List | +| tStatusResult | data-tstatusresult | Allows for translations of the result list status. | String | ${length} results found | +| tNoResults | data-tnoresults | Allows for translations of the notification that no result has been found. | String | No results found | +| tStatusQueryTooShort | data-tstatusquerytooshort | Text output when not enough chars have been entered | String | Type ${minChars} or more characters for results. | +| tStatusStartTyping | data-tstatusstarttyping | Text output when no chars have been entered | String | Begin typing for results. | +| tListItemText | data-tstatusquerytooshort | Text output for found list items | String | list item ${index} of ${length} | + ## License From 61773e9c3327079cec6158026ce7a9f0722b868f Mon Sep 17 00:00:00 2001 From: Roman Bertolami Date: Tue, 3 Aug 2021 13:58:49 +0200 Subject: [PATCH 4/5] add language as property - wip --- awesomplete.js | 53 +++++++++++++++++++++++++++++++--------- test/api/evaluateSpec.js | 2 +- test/api/gotoSpec.js | 2 +- test/init/optionsSpec.js | 12 +++------ 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/awesomplete.js b/awesomplete.js index 5251470f..d52dc367 100644 --- a/awesomplete.js +++ b/awesomplete.js @@ -39,14 +39,13 @@ var _ = function (input, o) { item: _.ITEM, replace: _.REPLACE, tabSelect: false, - listLabel: "Results List", - tStatusResult: "${length} results found", - tNoResults: "No results found", - tStatusQueryTooShort: "Type ${minChars} or more characters for results.", - tStatusStartTyping: "Begin typing for results.", + language: "en", + + tListItemText: "list item ${index} of ${length}" }, o); + this.index = -1; // Create necessary elements @@ -58,7 +57,7 @@ var _ = function (input, o) { role: "listbox", id: "awesomplete_list_" + this.count, inside: this.container, - "aria-label": this.listLabel + "aria-label":phrase(this, 'list-label') }); this.status = $.create("span", { @@ -67,7 +66,7 @@ var _ = function (input, o) { "aria-live": "assertive", "aria-atomic": true, inside: this.container, - textContent: this.minChars != 0 ? this.tStatusQueryTooShort.replace("${minChars}", this.minChars) : this.tStatusStartTyping + textContent: this.minChars != 0 ? phrase(this, 'status-query-too-short', {"${minChars}": this.minChars}) : phrase(this, 'status-start-typing') }); // Bind events @@ -264,7 +263,7 @@ _.prototype = { if (i > -1 && lis.length > 0) { lis[i].setAttribute("aria-selected", "true"); - this.status.textContent = lis[i].textContent + ", "+ this.tListItemText.replace("${index}", (i + 1)).replace("${length}", lis.length); + this.status.textContent = lis[i].textContent + ", "+ phrase(this, "list-item-text", {"${index}" : (i + 1), "${length}": lis.length}); this.input.setAttribute("aria-activedescendant", this.ul.id + "_item_" + this.index); @@ -333,20 +332,20 @@ _.prototype = { if (this.ul.children.length === 0) { - this.status.textContent = this.tNoResults; + this.status.textContent = phrase(this, 'no-results'); this.close({ reason: "nomatches" }); } else { this.open(); - this.status.textContent = this.tStatusResult.replace("${length}", this.ul.children.length); + this.status.textContent = phrase(this, 'status-result', {"${length}": this.ul.children.length}); } } else { this.close({ reason: "nomatches" }); - this.status.textContent = this.tNoResults; + this.status.textContent = phrase(this, 'no-results'); } } }; @@ -355,6 +354,25 @@ _.prototype = { _.all = []; +_.languages = { + "en": { + "list-label": "Results List", + "status-result": "${length} results found", + "no-results": "No results found", + "status-query-too-short": "Type ${minChars} or more characters for results.", + "status-start-typing": "Begin typing for results.", + "list-item-text": "list item ${index} of ${length}" + }, + "de": { + "list-label": "Suchresultate", + "status-result": "${length} Resultate gefunden", + "no-results": "Keine Resultate gefunden", + "status-query-too-short": "Geben Sie ${minChars} oder mehr Zeichen für die Suche ein", + "status-start-typing": "Beginnen Sie mit der Eingabe", + "list-item-text": "Listenelement ${index} von ${length}" + } +}; + _.FILTER_CONTAINS = function (text, input) { return RegExp($.regExpEscape(input.trim()), "i").test(text); }; @@ -434,6 +452,19 @@ function configure(instance, properties, o) { } } } +function phrase(instance, key, replacements) { + const translations = _.languages[instance.language]; + var result = translations[key]; + if(result === undefined) { + console.log(instance.language + "no result found " + key) + + } + for (var i in replacements) { + //console.log(i + ":::"+ replacements[i]) + result = result.replace(i, replacements[i]) + } + return result; +} // Helpers diff --git a/test/api/evaluateSpec.js b/test/api/evaluateSpec.js index e1466ad8..d7cb651f 100644 --- a/test/api/evaluateSpec.js +++ b/test/api/evaluateSpec.js @@ -97,7 +97,7 @@ describe("awesomplete.evaluate", function () { describe("with no results and German text", function () { beforeEach(function () { - this.subject.tNoResults = "Keine Resultate gefunden"; + this.subject.language = "de" $.type(this.subject.input, "nosuchitem"); }); diff --git a/test/api/gotoSpec.js b/test/api/gotoSpec.js index fcfec69e..cd44b333 100644 --- a/test/api/gotoSpec.js +++ b/test/api/gotoSpec.js @@ -57,7 +57,7 @@ describe("awesomplete.goto", function () { describe("with German text and item index > -1", function () { beforeEach(function () { - this.subject.tListItemText = "Listenelement ${index} von ${length}"; + this.subject.language = "de" this.subject.goto(0); }); diff --git a/test/init/optionsSpec.js b/test/init/optionsSpec.js index 732c6733..635109d3 100644 --- a/test/init/optionsSpec.js +++ b/test/init/optionsSpec.js @@ -39,12 +39,8 @@ describe("Constructor options", function () { expect(this.subject.replace).toEqual(Awesomplete.REPLACE); }); - it("uses 'Results List' as list label", function () { - expect(this.subject.listLabel).toEqual("Results List"); - }); - - it("uses 'No results found' as tNoResults", function () { - expect(this.subject.tNoResults).toEqual("No results found"); + it("uses en as default language", function () { + expect(this.subject.language).toEqual("en"); }); }); @@ -59,7 +55,7 @@ describe("Constructor options", function () { sort: $.noop, item: $.noop, replace: $.noop, - listLabel: 'new list label' + language: 'de' }; }); @@ -67,7 +63,7 @@ describe("Constructor options", function () { expect(this.subject.minChars).toBe(3); expect(this.subject.maxItems).toBe(9); expect(this.subject.autoFirst).toBe(true); - expect(this.subject.listLabel).toBe("new list label"); + expect(this.subject.language).toBe("de"); }); it("overrides default functions", function () { From 2b578f260db88f4ee4993fc541de51b15c86d565 Mon Sep 17 00:00:00 2001 From: Roman Bertolami Date: Tue, 10 Aug 2021 16:05:14 +0200 Subject: [PATCH 5/5] add translations for fr, en, it. allow for multiple replacement --- awesomplete.js | 32 ++++++++++++++++++++++++-------- test/api/evaluateSpec.js | 2 +- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/awesomplete.js b/awesomplete.js index d52dc367..8061e2bb 100644 --- a/awesomplete.js +++ b/awesomplete.js @@ -364,13 +364,29 @@ _.languages = { "list-item-text": "list item ${index} of ${length}" }, "de": { - "list-label": "Suchresultate", - "status-result": "${length} Resultate gefunden", - "no-results": "Keine Resultate gefunden", + "list-label": "Ergebnisliste", + "status-result": "${length} Ergebnisse gefunden", + "no-results": "Keine Ergebnisse gefunden", "status-query-too-short": "Geben Sie ${minChars} oder mehr Zeichen für die Suche ein", "status-start-typing": "Beginnen Sie mit der Eingabe", "list-item-text": "Listenelement ${index} von ${length}" - } + }, + "fr": { + "list-label": "Liste des résultats", + "status-result": "${length} résultats trouvés", + "no-results": "Aucun résultat trouvé", + "status-query-too-short": "Tapez ${minChars} ou plusieurs caractères pour les résultats.", + "status-start-typing": "Commencer à écrire", + "list-item-text": "élément de liste ${index} de ${length}" + }, + "it": { + "list-label": "Elenco dei risultati", + "status-result": "${length} risultati trovati", + "no-results": "Nessun risultato trovato", + "status-query-too-short": "Digita ${minChars} o più caratteri per i risultati.", + "status-start-typing": "Inizia a digitare per i risultati.", + "list-item-text": "elemento dell'elenco ${index} di ${length}" + }, }; _.FILTER_CONTAINS = function (text, input) { @@ -456,12 +472,12 @@ function phrase(instance, key, replacements) { const translations = _.languages[instance.language]; var result = translations[key]; if(result === undefined) { - console.log(instance.language + "no result found " + key) - + console.warn(instance.language + "no result found " + key) } for (var i in replacements) { - //console.log(i + ":::"+ replacements[i]) - result = result.replace(i, replacements[i]) + while(result.indexOf(i) >= 0) { + result = result.replace(i, replacements[i]) + } } return result; } diff --git a/test/api/evaluateSpec.js b/test/api/evaluateSpec.js index d7cb651f..45f674b8 100644 --- a/test/api/evaluateSpec.js +++ b/test/api/evaluateSpec.js @@ -108,7 +108,7 @@ describe("awesomplete.evaluate", function () { expect(this.subject.close).toHaveBeenCalledWith({ reason: "nomatches" }); - expect(this.subject.status.textContent).toBe("Keine Resultate gefunden") + expect(this.subject.status.textContent).toBe("Keine Ergebnisse gefunden") }); }); });