mui-language-picker
Version:
Material UI language picker
477 lines (476 loc) • 24.7 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LanguagePicker = void 0;
var react_1 = __importStar(require("react"));
var material_1 = require("@mui/material");
var Clear_1 = __importDefault(require("@mui/icons-material/Clear"));
var Settings_1 = __importDefault(require("@mui/icons-material/Settings"));
var BorderColor_1 = __importDefault(require("@mui/icons-material/BorderColor"));
var LanguageChoice_1 = __importDefault(require("./LanguageChoice"));
var bcp47_1 = require("./bcp47");
var langTags_1 = require("./langTags");
var useDebounce_1 = __importDefault(require("./useDebounce"));
var GrowingSpacer_1 = require("./GrowingSpacer");
var ChangeName_1 = __importDefault(require("./ChangeName"));
var getDisplayName_1 = require("./getDisplayName");
var rtlScripts_1 = __importDefault(require("./data/rtlScripts"));
var ChangeFeat_1 = __importDefault(require("./ChangeFeat"));
var localization_1 = require("./localization");
// const MAXOPTIONS = 50;
var StyledDialog = (0, material_1.styled)(material_1.Dialog)(function () { return ({
'& .MuiDialog-paperScrollPaper': {
marginBottom: 'auto',
width: '90%',
},
}); });
var LanguagePicker = function (props) {
var _a;
var disabled = props.disabled, offline = props.offline, required = props.required, filter = props.filter, noScript = props.noScript, noFont = props.noFont;
var value = props.value, name = props.name, font = props.font, setCode = props.setCode, setName = props.setName, setFont = props.setFont, setInfo = props.setInfo, setDir = props.setDir, t = props.t;
var feats = props.feats, setFeats = props.setFeats;
var displayName = props.displayName;
var _b = react_1.default.useState(false), open = _b[0], setOpen = _b[1];
var _c = react_1.default.useState(value), curValue = _c[0], setCurValue = _c[1];
var _d = react_1.default.useState(name), curName = _d[0], setCurName = _d[1];
var _e = react_1.default.useState(font), curFont = _e[0], setCurFont = _e[1];
var _f = react_1.default.useState(feats), curFeats = _f[0], setCurFeats = _f[1];
var _g = react_1.default.useState(true), secondary = _g[0], setSecondary = _g[1];
var _h = react_1.default.useState(''), response = _h[0], setResponse = _h[1];
var _j = react_1.default.useState(), tag = _j[0], setTag = _j[1];
var _k = react_1.default.useState(''), defaultScript = _k[0], setDefaultScript = _k[1];
var _l = react_1.default.useState(Array()), fontOpts = _l[0], setFontOpts = _l[1];
var _m = react_1.default.useState(false), newName = _m[0], setNewName = _m[1];
var _o = react_1.default.useState(false), newFeat = _o[0], setNewFeat = _o[1];
var langEl = react_1.default.useRef(null);
var debouncedResponse = (0, useDebounce_1.default)({ value: response, delay: 500 });
var IpaTag = 'fonipa';
if (!langTags_1.scriptName.has(IpaTag))
langTags_1.scriptName.set(IpaTag, t.phonetic);
var respFormat = function (iname, tagVal) { return "".concat(iname, " (").concat(tagVal, ")"); };
var getDefScript = function (val, script) {
return val.indexOf(IpaTag) > 0 ? IpaTag : script;
};
var handleClickOpen = function (e) {
if (disabled)
return;
if ((e === null || e === void 0 ? void 0 : e.key) &&
['Tab', 'Shift', 'Control'].indexOf(e.key) !== -1)
return;
var found = (0, bcp47_1.bcp47Find)(curValue);
if (curValue !== 'und') {
if (found && !Array.isArray(found)) {
found = __assign(__assign({}, found), { tag: curValue });
var tagName = (0, getDisplayName_1.getDisplayName)(curName, found, displayName);
setResponse(respFormat(tagName, curValue));
setTag(found);
selectFont(found);
setDefaultScript(getDefScript(curValue, found.script));
}
else {
var key = curValue !== null && curValue !== void 0 ? curValue : '';
if ((0, langTags_1.hasExact)(key)) {
setResponse(respFormat(curName, curValue));
var langTag = (0, langTags_1.getExact)(key);
if (langTag) {
setTag(langTag);
selectFont(langTag);
setDefaultScript(getDefScript(key, langTag.script));
}
}
else {
handleClear();
}
}
}
setOpen(true);
};
react_1.default.useEffect(function () {
if (open && curValue === 'und') {
setTimeout(function () {
if (langEl.current) {
langEl.current.click();
}
}, 100);
}
}, [open, curValue]);
var handleClear = function () {
setFontOpts([]);
setResponse('');
setTag(undefined);
setDefaultScript('');
if (langEl.current)
langEl.current.click();
};
var handleCancel = function () {
setCurValue(value);
setCurName(name);
setCurFont(font);
setCurFeats(feats);
if (setCode)
setCode(value);
if (setName)
setName(name);
if (setFont)
setFont(font);
setTag(undefined);
setDefaultScript('');
setResponse('');
setOpen(false);
};
var displayTag = function (tagP, val) {
if (tagP && tagP.name) {
var tagName = (0, getDisplayName_1.getDisplayName)(tagP.name, tagP, displayName);
setResponse(respFormat(tagName, tagP.tag));
setCurValue(val || tagP.tag);
setCurName(tagP.name);
}
};
var handleSelect = function () {
if (setCode)
setCode(curValue);
if (setName)
setName(curName);
if (setFont)
setFont(curFont);
if (setFeats)
setFeats(curFeats);
if (setDir)
setDir(rtlScripts_1.default.includes(defaultScript));
if (setInfo && tag)
setInfo(tag);
if (tag) {
displayTag(tag, curValue);
}
else {
setResponse('');
}
setTimeout(function () { return setOpen(false); }, 200);
};
var handleChange = function (e) {
setResponse(e.target.value);
};
var addFontInfo = function (e) {
setCurFont(e.target.value);
};
var safeFonts = [
{ value: 'charissil', label: 'Charis SIL (Recommended)', rtl: false },
{ value: 'annapurnasil', label: 'Annapurna SIL (Indic)', rtl: false },
{ value: 'scheherazadenew', label: 'Scheherazade New (Arabic)', rtl: true },
{ value: 'notosanstc', label: 'Noto Sans TC (Chinese)', rtl: false },
];
var selectDefaultFont = function (iTag, scriptKey) {
var _a;
var fontFamilies = (_a = langTags_1.fontMap.get(iTag)) !== null && _a !== void 0 ? _a : langTags_1.fontMap.get(scriptKey);
if (fontFamilies) {
var familyId = fontFamilies[0];
var fontFamily = (0, langTags_1.getFamily)(familyId);
if (familyId && fontFamily) {
setCurFont(fontFamily.familyid);
setFontOpts(fontFamilies.filter(function (f) { return (0, langTags_1.getFamily)(f); }));
}
}
};
var selectFont = function (tagP) {
var _a, _b;
if (!tagP || tagP.tag === 'und')
return;
var parse = (0, bcp47_1.bcp47Parse)(tagP.tag);
var script = getDefScript(tagP.tag, (_a = parse.script) !== null && _a !== void 0 ? _a : tagP.script);
var region = (_b = parse.region) !== null && _b !== void 0 ? _b : tagP.region;
var key = script;
if (region) {
key = script + '-' + region;
if (!langTags_1.fontMap.has(key)) {
key = script;
}
}
if (!langTags_1.fontMap.has(key)) {
setCurFont(safeFonts[0].value);
setFontOpts(safeFonts.map(function (f) { return f.value; }));
}
else
selectDefaultFont(tagP.tag, key);
};
var hasFonts = (0, react_1.useMemo)(function () { return fontOpts && fontOpts.length > 0; }, [fontOpts]);
var handleNewName = function () {
setNewName(true);
};
var handleCloseName = function () {
setNewName(false);
};
var handleSetName = function (iname) {
setCurName(iname);
var tagName = (0, getDisplayName_1.getDisplayName)(iname, tag, displayName);
if (tag)
setResponse(respFormat(tagName, tag.tag));
};
var handleNewFeat = function () {
setNewFeat(true);
};
var handleCloseFeat = function () {
setNewFeat(false);
};
var handleSetFeat = function (iFeats) {
setCurFeats(iFeats);
};
react_1.default.useEffect(function () {
if (response === '')
handleClear();
}, [response]);
react_1.default.useEffect(function () {
setCurValue(value);
setCurName(name);
setCurFont(font);
setResponse(value !== 'und' ? name + ' (' + value + ')' : '');
}, [value, name, font]);
var handleScriptChange = function (tagP) { return function (e) {
var val = e.target.value;
setDefaultScript(val);
var parse = (0, bcp47_1.bcp47Parse)(curValue);
var script = parse.variant === IpaTag
? IpaTag
: parse.script
? parse.script
: tagP === null || tagP === void 0 ? void 0 : tagP.script;
if (script !== val) {
var newTag = parse.language || 'und';
if (val !== IpaTag)
newTag += '-' + val;
if (parse.region)
newTag += '-' + parse.region;
var found = (0, bcp47_1.bcp47Find)(newTag);
if (found) {
var firstFind = Array.isArray(found) ? found[0] : found;
setTag(firstFind);
var myTag_1 = firstFind.tag;
if (val === IpaTag)
myTag_1 += "-".concat(IpaTag);
else if (parse.variant && parse.variant !== IpaTag)
myTag_1 += '-' + parse.variant;
if (parse.extension)
myTag_1 += '-' + parse.extension;
parse.privateUse.forEach(function (i) {
myTag_1 += '-x-' + i;
});
displayTag(__assign(__assign({}, firstFind), { tag: myTag_1 }));
if (val === IpaTag)
selectDefaultFont('en', 'Latn');
else
selectFont(firstFind);
}
}
}; };
var selectScript = function (tagP) {
var _a;
var tagParts = (0, bcp47_1.bcp47Parse)(tagP.tag);
selectFont(tagP);
setDefaultScript(getDefScript(tagP.tag, (_a = tagParts.script) !== null && _a !== void 0 ? _a : tagP.script));
};
var scriptList = function (tagP) {
if (!tagP)
return [];
return (0, langTags_1.getScripts)(tagP.tag.split('-')[0]).concat(IpaTag);
};
var handleLanguageClick = function () {
if (tag)
selectScript(tag);
setTag(undefined);
};
var handleChoose = function (tagP) {
var newTag = tagP;
var found = (0, bcp47_1.bcp47Find)(response);
var maxMatch = '';
var tagList = [tagP.full, tagP.tag];
if (tagP.iso639_3) {
tagList.push(tagP.iso639_3);
tagList.push(tagP.iso639_3 + '-' + tagP.script);
if (tagP.region) {
tagList.push(tagP.iso639_3 + '-' + tagP.region);
tagList.push(tagP.iso639_3 + '-' + tagP.script + '-' + tagP.region);
}
}
var parse = (0, bcp47_1.bcp47Parse)(response);
if (parse.extlang && parse.language) {
tagList.push(parse.language);
tagList.push(parse.language + '-' + tagP.script);
if (tagP.region) {
tagList.push(parse.language + '-' + tagP.region);
tagList.push(parse.language + '-' + tagP.script + '-' + tagP.region);
}
}
if (tagP.tags) {
tagList = tagList.concat(tagP.tags.map(function (p) { return p; }));
}
tagList.forEach(function (i) {
var tLen = i.length;
if (tLen > maxMatch.length) {
if (i === response.slice(0, tLen)) {
if (response.length === tLen || response[tLen] === '-') {
maxMatch = i;
}
}
}
});
if (maxMatch !== '') {
var newCode = tagP.tag;
if (parse.variant && tagP.tag.indexOf(tagP.script) > 0) {
newCode = tagP.tag.replace("-".concat(tagP.script), '');
}
newTag = __assign(__assign({}, tagP), { tag: newCode + response.slice(maxMatch.length) });
displayTag(newTag);
}
setTag(newTag);
if (maxMatch === '') {
if (found === tagP) {
newTag = __assign(__assign({}, tagP), { tag: response });
}
else if (Array.isArray(found) && found.indexOf(tagP) !== -1) {
newTag = __assign(__assign({}, tagP), { tag: response });
}
}
displayTag(newTag);
selectScript(newTag);
selectFont(newTag);
};
var optList = function () {
if (!tag && debouncedResponse) {
var list = [];
// special case for zh macro language (zh-CN)
var search = debouncedResponse.toLowerCase() === 'zh' ? 'zh-CN' : debouncedResponse;
var tagLookup = (0, langTags_1.getLangTag)(search);
if (tagLookup) {
list.push(tagLookup);
}
// check for a part match
var words = debouncedResponse.split(' ');
var firstWord = words[0];
if ((0, langTags_1.hasPart)(firstWord)) {
var matches = (0, langTags_1.getPart)(firstWord);
if (matches) {
var result_1 = matches.result;
if (list.length > 0) {
var exact_1 = list[0].tag;
result_1 = result_1.filter(function (e) { return e.tag !== exact_1; });
}
if (words.length > 1) {
words.slice(1).forEach(function (word) {
var nextMatches = (0, langTags_1.getPart)(word);
if (nextMatches) {
result_1 = result_1.filter(function (e) { return nextMatches.result.includes(e); });
}
});
}
// put canonical name matches first
var canonical_1 = [];
var nonCanonical_1 = [];
var lcFirst_1 = firstWord.toLowerCase();
result_1.forEach(function (e) {
if (e === null || e === void 0 ? void 0 : e.name) {
// all valid entries have a name
if (e.name.toLowerCase() === lcFirst_1) {
canonical_1.push(e);
}
else {
nonCanonical_1.push(e);
}
}
});
list.push.apply(list, __spreadArray(__spreadArray([], canonical_1, false), nonCanonical_1, false));
}
}
var filtered = list.filter(function (i) { return !filter || filter(i.tag); });
if (filtered.length > 0) {
return (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement(material_1.FormGroup, { row: true, sx: { justifyContent: 'flex-end' } },
react_1.default.createElement(material_1.FormControlLabel, { sx: { flexDirection: 'row-reverse', mr: 0 }, control: react_1.default.createElement(material_1.Checkbox, { checked: secondary, onChange: function (event) { return setSecondary(event.target.checked); }, value: "secondary" }), label: t.details })),
react_1.default.createElement(LanguageChoice_1.default, { list: filtered, secondary: secondary, choose: handleChoose, displayName: displayName, t: t })));
}
}
return react_1.default.createElement(react_1.default.Fragment, null);
};
return (react_1.default.createElement("div", { id: "LangBcp47" },
react_1.default.createElement(material_1.TextField, { variant: "filled", margin: "dense", id: "lang-bcp47", label: t.language, required: required, style: { width: 300 }, value: value !== 'und' ? name + ' (' + value + ')' : '', onClick: handleClickOpen, onKeyDown: handleClickOpen, disabled: disabled !== null && disabled !== void 0 ? disabled : false }),
react_1.default.createElement(StyledDialog, { id: "LanguagePicker", open: open, onClose: handleCancel, "aria-labelledby": "form-dialog-title" },
react_1.default.createElement(material_1.DialogTitle, { id: "form-dialog-title" }, t.selectLanguage),
react_1.default.createElement(material_1.DialogContent, { dividers: true },
react_1.default.createElement(material_1.TextField, { margin: "normal", id: "language", label: t.findALanguage, fullWidth: true, value: response, onChange: handleChange, onClick: handleLanguageClick, variant: "outlined", InputProps: {
ref: langEl,
endAdornment: (react_1.default.createElement(material_1.InputAdornment, { position: "end" },
react_1.default.createElement(material_1.IconButton, { edge: "end", "aria-label": "clear language", onClick: handleClear },
react_1.default.createElement(Clear_1.default, { color: "primary" })))),
} }),
optList(),
!noScript && (react_1.default.createElement(material_1.FormControlLabel, { control: react_1.default.createElement(material_1.TextField, { id: "select-script", "data-testid": "select-script", select: true, sx: { mx: 1 }, fullWidth: true, label: "".concat(t.script, " *"), value: defaultScript, onChange: handleScriptChange(tag), margin: "normal", variant: "filled" }, scriptList(tag)
.map(function (s) { return (react_1.default.createElement(material_1.MenuItem, { key: s, value: s }, langTags_1.scriptName.get(s) + ' - ' + s)); })
.concat(scriptList(tag).includes(defaultScript)
? []
: [
react_1.default.createElement(material_1.MenuItem, { key: defaultScript, value: defaultScript }, defaultScript),
])), label: "", sx: { width: '95%' } })),
!noFont && (react_1.default.createElement(material_1.FormControlLabel, { control: react_1.default.createElement(material_1.Stack, { direction: "row", spacing: 1, sx: { display: 'flex', flexGrow: 1, p: 1 } },
react_1.default.createElement(material_1.TextField, { id: "select-font", "data-testid": "select-font", select: hasFonts, helperText: !hasFonts ? t.noFonts : undefined, sx: { mx: 1 }, fullWidth: true, label: "".concat(t.font).concat(hasFonts ? ' *' : ''), value: fontOpts.includes(curFont) ? curFont : '', onChange: addFontInfo, margin: "normal", variant: "filled" }, fontOpts.map(function (s) { return (react_1.default.createElement(material_1.MenuItem, { key: s, value: s }, (0, langTags_1.displayFamily)(s))); })),
setFeats && (react_1.default.createElement(material_1.IconButton, { onClick: handleNewFeat, "data-testid": "change-features", title: t.changeFeatures || localization_1.languagePickerStrings_en.changeFeatures, disabled: !curFont },
react_1.default.createElement(Settings_1.default, { fontSize: "small" })))), label: "", sx: { width: '95%' } }))),
react_1.default.createElement(material_1.DialogActions, null,
!offline && (react_1.default.createElement("a", { href: "https://www.w3.org/International/questions/qa-choosing-language-tags", target: "_blank", rel: "noopener noreferrer" },
react_1.default.createElement(material_1.Typography, null, t.codeExplained))),
curName !== '' && (react_1.default.createElement(material_1.Tooltip, { title: (_a = t.changeName) !== null && _a !== void 0 ? _a : 'Change name' },
react_1.default.createElement(material_1.IconButton, { color: "primary", size: "small", "data-testid": "change-name", onClick: handleNewName },
react_1.default.createElement(BorderColor_1.default, { fontSize: "small" })))),
react_1.default.createElement(GrowingSpacer_1.GrowingSpacer, null),
react_1.default.createElement(material_1.Button, { onClick: handleCancel, color: "primary" },
react_1.default.createElement(material_1.Typography, null, t.cancel)),
react_1.default.createElement(material_1.Button, { onClick: handleSelect, color: "primary", disabled: required &&
(tag === undefined || (tag === null || tag === void 0 ? void 0 : tag.tag) === 'und' || defaultScript === '') },
react_1.default.createElement(material_1.Typography, null, t.select)))),
newName && (react_1.default.createElement(ChangeName_1.default, { isOpen: newName, onClose: handleCloseName, curName: curName, onNewName: handleSetName, t: t })),
newFeat && (react_1.default.createElement(ChangeFeat_1.default, { isOpen: newFeat, onClose: handleCloseFeat, curFeats: curFeats, onNewFeat: handleSetFeat, offline: offline, t: t }))));
};
exports.LanguagePicker = LanguagePicker;
exports.default = exports.LanguagePicker;