Skip to content

Commit dc16ab6

Browse files
chukaraveguergana
andauthored
Allow the language selector to detect autonym by exonym (#883)
* add API call to get language code * get an array of lang codes and filter from that * simplify response handling and improve api constant name * debounce api requests * don't make api calls with empty inputs * Mock svg import files in jest tests * add test skeleton * add test --------- Co-authored-by: gtzatchkova <guergana.tzatchkova@wikimedia.de>
1 parent 843d74f commit dc16ab6

File tree

6 files changed

+86
-8
lines changed

6 files changed

+86
-8
lines changed

jest.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ module.exports = {
1212
"transform": {
1313
".*\\.(vue)$": "<rootDir>/node_modules/@vue/vue3-jest",
1414
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
15-
"^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest"
15+
"^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest",
16+
'.+\\.svg$': '<rootDir>/tests/Vue/helpers/jest-svg-component-transformer.js'
1617
},
1718
// (Optional) This file helps you later for global settings
1819
"setupFilesAfterEnv": [

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"@inertiajs/inertia-vue3": "^0.6.0",
6262
"date-fns": "^3.3.1",
6363
"lodash": "^4.17.21",
64+
"lodash.debounce": "^4.0.8",
6465
"pinia": "^2.1.7",
6566
"ress": "^5.0.2",
6667
"vue": "^3.3.8",

resources/js/Components/LanguageSelector.vue

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,16 @@ import LanguageSelectorOptionsMenu from "./LanguageSelectorOptionsMenu.vue";
3939
import LanguageSelectorInput from "./LanguageSelectorInput.vue";
4040
import Language from '../types/Language';
4141
import closeUrlSvg from '../../img/close.svg';
42-
42+
import axios from 'axios';
4343
import {ref, computed} from "vue";
4444
import type {Ref} from 'vue';
4545
import languageData from "@wikimedia/language-data";
46+
import debounce from "lodash.debounce";
4647
4748
const searchInput: Ref<string> = ref('');
4849
const highlightedIndex: Ref<number> = ref(-1);
4950
const closeUrl = ref(closeUrlSvg);
51+
const apiLanguageCodes = ref(['']);
5052
5153
const input = ref<InstanceType<typeof LanguageSelectorInput> | null>(null);
5254
@@ -63,17 +65,35 @@ const languages = computed<Language[]>(() => {
6365
});
6466
6567
const shownLanguages = computed<Language[]>(() => {
66-
return languages.value.filter((language) =>
67-
language.code.startsWith(searchInput.value.toLowerCase()) ||
68-
language.autonym.toLowerCase().includes(searchInput.value.toLowerCase()),
69-
);
68+
return languages.value.filter((language) =>
69+
language.code.startsWith(searchInput.value.toLowerCase()) ||
70+
language.autonym.toLowerCase().includes(searchInput.value.toLowerCase()) ||
71+
apiLanguageCodes.value.includes(language.code)
72+
)
7073
});
7174
7275
function onInput(searchedLanguage: string): void {
7376
searchInput.value = searchedLanguage;
77+
if (searchInput.value) {
78+
debouncedApiLanguageSearch(searchInput.value);
79+
}
80+
7481
highlightedIndex.value = 0;
7582
}
7683
84+
const debouncedApiLanguageSearch = debounce(async (debouncedInputValue: string) => {
85+
await axios.get(
86+
'https://www.wikidata.org/w/api.php?action=languagesearch&format=json&formatversion=2',
87+
{
88+
params: {
89+
search: debouncedInputValue,
90+
origin: '*' // avoid CORS console errors
91+
}
92+
}).then((response) => {
93+
apiLanguageCodes.value = Object.keys(response.data.languagesearch);
94+
});
95+
}, 200);
96+
7797
function onSelect(languageCode: string): void {
7898
emit('select', languageCode);
7999
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { mount } from '@vue/test-utils';
2+
import LanguageSelector from '@/Components/LanguageSelector.vue';
3+
import { createI18n } from 'vue-banana-i18n';
4+
5+
const i18n = createI18n({
6+
messages: {},
7+
locale: 'en',
8+
wikilinks: true
9+
});
10+
11+
describe('LanguageSelector.vue', () => {
12+
it('suggests the relevant language upon input', async () => {
13+
const wrapper = mount(LanguageSelector, {
14+
global: {
15+
plugins: [i18n],
16+
}});
17+
18+
const input = wrapper.find('input');
19+
20+
expect(input.exists()).toBe(true);
21+
22+
await input.setValue('deu');
23+
const listItems = await wrapper.findAll('.languageSelector__options-menu__languages-list__item');
24+
25+
expect(listItems.at(0).text()).toContain('Deutsch');
26+
});
27+
28+
it('suggests the relevant language upon RTL input', async () => {
29+
const wrapper = mount(LanguageSelector, {
30+
global: {
31+
plugins: [i18n],
32+
}});
33+
34+
const input = wrapper.find('input');
35+
36+
expect(input.exists()).toBe(true);
37+
38+
await input.setValue('עב');
39+
const listItems = await wrapper.findAll('.languageSelector__options-menu__languages-list__item');
40+
41+
expect(listItems.at(0).text()).toContain('עברית');
42+
});
43+
44+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module.exports = {
2+
process(sourceText, sourcePath) {
3+
const mockComponent = {
4+
name: sourcePath,
5+
template: sourceText
6+
}
7+
8+
return {
9+
code: `module.exports = ${JSON.stringify(mockComponent)};`
10+
}
11+
}
12+
}

0 commit comments

Comments
 (0)