Skip to content

Commit c6e4ecd

Browse files
authored
Merge pull request #4058 from ProjectMirador/manifest-locales-picker
Update the LocalePicker to use labels for languages.
2 parents 01ebfc1 + df014ca commit c6e4ecd

File tree

6 files changed

+139
-13
lines changed

6 files changed

+139
-13
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6+
<meta name="theme-color" content="#000000">
7+
<title>Mirador</title>
8+
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500">
9+
</head>
10+
<body>
11+
<div id="mirador" style="position: absolute; top: 0; bottom: 0; left: 0; right: 0;"></div>
12+
<script type="module">
13+
import Mirador from '../../../src';
14+
import config from './mirador-configs/i18n.js';
15+
Mirador.viewer(config);
16+
</script>
17+
</body>
18+
</html>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export default {
2+
catalog: [
3+
{ manifestId: 'https://iiif.bodleian.ox.ac.uk/iiif/manifest/e32a277e-91e2-4a6d-8ba6-cc4bad230410.json' },
4+
{ manifestId: 'https://iiif.harvardartmuseums.org/manifests/object/299843' },
5+
{ manifestId: 'https://media.nga.gov/public/manifests/nga_highlights.json', provider: 'National Gallery of Art' },
6+
{ manifestId: 'https://data.ucd.ie/api/img/manifests/ucdlib:33064', provider: 'Irish Architectural Archive' },
7+
{ manifestId: 'https://wellcomelibrary.org/iiif/b18035723/manifest', provider: 'Wellcome Library' },
8+
{ manifestId: 'https://demos.biblissima.fr/iiif/metadata/florus-dispersus/manifest.json', provider: 'Biblissima' },
9+
{ manifestId: 'https://www.e-codices.unifr.ch/metadata/iiif/gau-Fragment/manifest.json', provider: 'e-codices - Virtual Manuscript Library of Switzerland' },
10+
{ manifestId: 'https://wellcomelibrary.org/iiif/collection/b18031511', provider: 'Wellcome Library' },
11+
{ manifestId: 'https://gallica.bnf.fr/iiif/ark:/12148/btv1b10022508f/manifest.json', provider: 'Bibliothèque nationale de France' },
12+
{ manifestId: 'https://manifests.britishart.yale.edu/Osbornfa1', provider: 'Beinecke Rare Book and Manuscript Library, Yale University' },
13+
{ manifestId: 'https://iiif.biblissima.fr/chateauroux/B360446201_MS0005/manifest.json', provider: 'Biblissima' },
14+
{ manifestId: 'https://iiif.durham.ac.uk/manifests/trifle/32150/t1/m4/q7/t1m4q77fr328/manifest', provider: 'Durham University Library' },
15+
// { manifestId: "https://iiif.vam.ac.uk/collections/O1023003/manifest.json", provider: "Ocean liners"},
16+
{ manifestId: 'https://zavicajna.digitalna.rs/iiif/iiif/api/presentation/2/4aa44ad1-0b74-4590-ab09-534a38cb7c53%252F00000001%252Fostalo01%252F00000012/manifest', provider: "Библиотека 'Милутин Бојић'" },
17+
],
18+
id: 'mirador',
19+
language: 'fr',
20+
windows: [{
21+
manifestId: 'https://iiif.io/api/cookbook/recipe/0006-text-language/manifest.json',
22+
showLocalePicker: true,
23+
thumbnailNavigationPosition: 'far-bottom',
24+
}],
25+
};

__tests__/src/components/LocalePicker.test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ describe('LocalePicker', () => {
2727
createWrapper({ availableLocales: ['en', 'de'], locale: 'de' });
2828
// The option to expand the dropdown menu is rendered by a CompanionWindow titleControls prop in WindowSideBarInfoPanel, which is a combobox
2929
const dropdownTitle = screen.getByRole('combobox');
30-
expect(dropdownTitle).toHaveTextContent('de');
30+
expect(dropdownTitle).toHaveTextContent('Deutsch');
3131
});
3232

3333
it('renders a select with both options and sets the current value', async () => {
@@ -41,10 +41,10 @@ describe('LocalePicker', () => {
4141
// Assert that the menu element has 2 children (2 options)
4242
expect(menu.children).toHaveLength(2); // eslint-disable-line testing-library/no-node-access
4343
// Verify that the select element has the correct value ('de')
44-
const deOption = screen.getByRole('option', { name: 'de' });
44+
const deOption = screen.getByRole('option', { name: 'Deutsch' });
4545
expect(deOption).toHaveAttribute('aria-selected', 'true');
4646
// Verify en is also an option
47-
expect(screen.getByRole('option', { name: 'en' })).toBeInTheDocument();
47+
expect(screen.getByRole('option', { name: 'English' })).toBeInTheDocument();
4848
});
4949

5050
it('triggers setLocale prop when clicking a list item', async () => {
@@ -59,7 +59,7 @@ describe('LocalePicker', () => {
5959
// Open the Select component
6060
await user.click(dropdownTitle);
6161
// Change the locale to 'de'
62-
await user.click(screen.getByRole('option', { name: 'de' }));
62+
await user.click(screen.getByRole('option', { name: 'Deutsch' }));
6363
expect(setLocale).toHaveBeenCalledTimes(1);
6464
expect(setLocale).toHaveBeenCalledWith('de');
6565
});

__tests__/src/selectors/manifests.test.js

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ describe('getManifestLocale', () => {
370370
});
371371

372372
describe('getMetadataLocales', () => {
373-
it('gets the locales preseent in the manifest metadata', () => {
373+
it('gets the locales preseent in the IIIF v2 manifest metadata', () => {
374374
const manifest = {
375375
'@context': 'http://iiif.io/api/presentation/2/context.json',
376376
'@id':
@@ -403,6 +403,59 @@ describe('getMetadataLocales', () => {
403403
const received = getMetadataLocales(state, { manifestId: 'x' });
404404
expect(received).toEqual(['de-label', 'en-label', 'en-value', 'de-value', 'one-value']);
405405
});
406+
it('gets the locales preseent in the IIIF v3 manifest metadata', () => {
407+
const manifest = {
408+
'@context': 'http://iiif.io/api/presentation/3/context.json',
409+
id: 'https://iiif.io/api/cookbook/recipe/0006-text-language/manifest.json',
410+
label: {
411+
en: [
412+
"Whistler's Mother",
413+
],
414+
fr: [
415+
'La Mère de Whistler',
416+
],
417+
},
418+
metadata: [
419+
{
420+
label: {
421+
en: [
422+
'Creator',
423+
],
424+
fr: [
425+
'Auteur',
426+
],
427+
},
428+
value: {
429+
none: [
430+
'Whistler, James Abbott McNeill',
431+
],
432+
},
433+
},
434+
{
435+
label: {
436+
en: [
437+
'Subject',
438+
],
439+
fr: [
440+
'Sujet',
441+
],
442+
},
443+
value: {
444+
en: [
445+
'McNeill Anna Matilda, mother of Whistler (1804-1881)',
446+
],
447+
fr: [
448+
'McNeill Anna Matilda, mère de Whistler (1804-1881)',
449+
],
450+
},
451+
},
452+
],
453+
type: 'Manifest',
454+
};
455+
const state = { manifests: { x: { json: manifest } } };
456+
const received = getMetadataLocales(state, { manifestId: 'x' });
457+
expect(received).toEqual(['en', 'fr', 'none']);
458+
});
406459
});
407460

408461
describe('getRequiredStatement', () => {

src/components/LocalePicker.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,45 @@
11
import PropTypes from 'prop-types';
2+
import keyBy from 'lodash/keyBy';
23
import MenuItem from '@mui/material/MenuItem';
4+
import InputLabel from '@mui/material/InputLabel';
35
import FormControl from '@mui/material/FormControl';
46
import Select from '@mui/material/Select';
57
import Typography from '@mui/material/Typography';
8+
import { useSelector } from 'react-redux';
9+
import { useTranslation } from 'react-i18next';
10+
import { getLanguagesFromConfigWithCurrent } from '../state/selectors/config';
611

712
/**
813
* Provide a locale picker
914
*/
1015
export function LocalePicker({ availableLocales = [], locale = '', setLocale = undefined }) {
16+
const languages = useSelector(state => getLanguagesFromConfigWithCurrent(state));
17+
const { t } = useTranslation();
18+
1119
if (!setLocale || availableLocales.length < 2) return null;
1220

21+
const selectedLocale = availableLocales.indexOf(locale) >= 0 ? locale : availableLocales[0];
22+
const labels = keyBy(languages, o => o.locale);
23+
1324
return (
14-
<FormControl>
25+
<FormControl variant="standard">
26+
<InputLabel>{t('language')}</InputLabel>
1527
<Select
1628
MenuProps={{
1729
anchorOrigin: {
1830
horizontal: 'left',
1931
vertical: 'bottom',
2032
},
2133
}}
34+
autoWidth
2235
displayEmpty
23-
value={locale}
36+
value={selectedLocale}
2437
onChange={(e) => { setLocale(e.target.value); }}
2538
name="locale"
2639
>
2740
{
2841
availableLocales.map(l => (
29-
<MenuItem key={l} value={l}><Typography variant="body2">{ l }</Typography></MenuItem>
42+
<MenuItem key={l} value={l}><Typography variant="body2">{ labels[l]?.label || l }</Typography></MenuItem>
3043
))
3144
}
3245
</Select>

src/state/selectors/manifests.js

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -415,14 +415,31 @@ export const getManifestMetadata = createSelector(
415415

416416
/** */
417417
function getLocalesForStructure(item) {
418-
const languages = [];
418+
const languages = new Set([]);
419+
420+
/** Extract language indicators from IIIF v2 or v3 manifests */
421+
const extractLanguage = (i) => {
422+
if (!(i && typeof i === 'object')) return;
423+
424+
// IIIF v2 pattern
425+
if (i['@language'] && i['@value']) {
426+
languages.add(i['@language']);
427+
return;
428+
}
429+
430+
// IIIF v3 pattern
431+
Object.keys(i).forEach((key) => {
432+
languages.add(key);
433+
});
434+
};
419435

420436
if (Array.isArray(item)) {
421-
languages.push(...item.filter(i => (typeof i === 'object' && i['@language'])).map(i => i['@language']));
422-
} else if (item && typeof item === 'object') {
423-
if (item['@language']) languages.push(item['@language']);
437+
item.forEach(i => extractLanguage(i));
438+
} else {
439+
extractLanguage(item);
424440
}
425-
return languages;
441+
442+
return [...languages];
426443
}
427444

428445
/** */

0 commit comments

Comments
 (0)