diff --git a/app/components/edit_channel_info/index.js b/app/components/edit_channel_info/index.js
new file mode 100644
index 000000000..6a04059dd
--- /dev/null
+++ b/app/components/edit_channel_info/index.js
@@ -0,0 +1,423 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React, {PureComponent} from 'react';
+import PropTypes from 'prop-types';
+import {
+ Platform,
+ TouchableWithoutFeedback,
+ View,
+ Text,
+ findNodeHandle
+} from 'react-native';
+import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
+
+import EventEmitter from 'mattermost-redux/utils/event_emitter';
+
+import ErrorText from 'app/components/error_text';
+import FormattedText from 'app/components/formatted_text';
+import Loading from 'app/components/loading';
+import StatusBar from 'app/components/status_bar';
+import TextInputWithLocalizedPlaceholder from 'app/components/text_input_with_localized_placeholder';
+
+import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
+import {General} from 'mattermost-redux/constants';
+import {getShortenedURL} from 'app/utils/url';
+
+export default class EditChannelInfo extends PureComponent {
+ static propTypes = {
+ navigator: PropTypes.object.isRequired,
+ theme: PropTypes.object.isRequired,
+ deviceWidth: PropTypes.number.isRequired,
+ deviceHeight: PropTypes.number.isRequired,
+ channelType: PropTypes.string,
+ enableRightButton: PropTypes.func,
+ saving: PropTypes.bool.isRequired,
+ editing: PropTypes.bool,
+ error: PropTypes.string,
+ displayName: PropTypes.string,
+ currentTeamUrl: PropTypes.string,
+ channelURL: PropTypes.string,
+ purpose: PropTypes.string,
+ header: PropTypes.string,
+ onDisplayNameChange: PropTypes.func,
+ onChannelURLChange: PropTypes.func,
+ onPurposeChange: PropTypes.func,
+ onHeaderChange: PropTypes.func,
+ oldDisplayName: PropTypes.string,
+ oldChannelURL: PropTypes.string,
+ oldHeader: PropTypes.string,
+ oldPurpose: PropTypes.string
+ };
+
+ static defaultProps = {
+ editing: false
+ };
+
+ blur = () => {
+ if (this.nameInput) {
+ this.nameInput.refs.wrappedInstance.blur();
+ }
+
+ // TODO: uncomment below once the channel URL field is added
+ // if (this.urlInput) {
+ // this.urlInput.refs.wrappedInstance.blur();
+ // }
+ if (this.purposeInput) {
+ this.purposeInput.refs.wrappedInstance.blur();
+ }
+ if (this.headerInput) {
+ this.headerInput.refs.wrappedInstance.blur();
+ }
+ if (this.scroll) {
+ this.scroll.scrollToPosition(0, 0, true);
+ }
+ };
+
+ channelNameRef = (ref) => {
+ this.nameInput = ref;
+ };
+
+ channelURLRef = (ref) => {
+ this.urlInput = ref;
+ };
+
+ channelPurposeRef = (ref) => {
+ this.purposeInput = ref;
+ };
+
+ channelHeaderRef = (ref) => {
+ this.headerInput = ref;
+ };
+
+ close = (goBack = false) => {
+ EventEmitter.emit('closing-create-channel', false);
+ if (goBack) {
+ this.props.navigator.pop({animated: true});
+ } else {
+ this.props.navigator.dismissModal({
+ animationType: 'slide-down'
+ });
+ }
+ };
+
+ lastTextRef = (ref) => {
+ this.lastText = ref;
+ };
+
+ canUpdate = (displayName, channelURL, purpose, header) => {
+ const {
+ oldDisplayName,
+ oldChannelURL,
+ oldPurpose,
+ oldHeader
+ } = this.props;
+
+ return displayName !== oldDisplayName || channelURL !== oldChannelURL ||
+ purpose !== oldPurpose || header !== oldHeader;
+ };
+
+ enableRightButton = (enable = false) => {
+ this.props.enableRightButton(enable);
+ };
+
+ onDisplayNameChangeText = (displayName) => {
+ const {editing, onDisplayNameChange} = this.props;
+ onDisplayNameChange(displayName);
+
+ if (editing) {
+ const {channelURL, purpose, header} = this.props;
+ const canUpdate = this.canUpdate(displayName, channelURL, purpose, header);
+ this.enableRightButton(canUpdate);
+ return;
+ }
+
+ const displayNameExists = displayName && displayName.length >= 2;
+ this.props.enableRightButton(displayNameExists);
+ };
+
+ onDisplayURLChangeText = (channelURL) => {
+ const {editing, onChannelURLChange} = this.props;
+ onChannelURLChange(channelURL);
+
+ if (editing) {
+ const {displayName, purpose, header} = this.props;
+ const canUpdate = this.canUpdate(displayName, channelURL, purpose, header);
+ this.enableRightButton(canUpdate);
+ }
+ };
+
+ onPurposeChangeText = (purpose) => {
+ const {editing, onPurposeChange} = this.props;
+ onPurposeChange(purpose);
+
+ if (editing) {
+ const {displayName, channelURL, header} = this.props;
+ const canUpdate = this.canUpdate(displayName, channelURL, purpose, header);
+ this.enableRightButton(canUpdate);
+ }
+ };
+
+ onHeaderChangeText = (header) => {
+ const {editing, onHeaderChange} = this.props;
+ onHeaderChange(header);
+
+ if (editing) {
+ const {displayName, channelURL, purpose} = this.props;
+ const canUpdate = this.canUpdate(displayName, channelURL, purpose, header);
+ this.enableRightButton(canUpdate);
+ }
+ };
+
+ scrollRef = (ref) => {
+ this.scroll = ref;
+ };
+
+ scrollToEnd = () => {
+ if (this.scroll && this.lastText) {
+ this.scroll.scrollToFocusedInput(findNodeHandle(this.lastText));
+ }
+ };
+
+ render() {
+ const {
+ theme,
+ editing,
+ channelType,
+ currentTeamUrl,
+ deviceWidth,
+ deviceHeight,
+ displayName,
+ channelURL,
+ header,
+ purpose
+ } = this.props;
+ const {error, saving} = this.props;
+ const fullUrl = currentTeamUrl + '/channels';
+ const shortUrl = getShortenedURL(fullUrl, 35);
+
+ const style = getStyleSheet(theme);
+
+ const displayHeaderOnly = channelType === General.DM_CHANNEL ||
+ channelType === General.GM_CHANNEL;
+
+ if (saving) {
+ return (
+
+
+
+
+ );
+ }
+
+ let displayError;
+ if (error) {
+ displayError = (
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+ {displayError}
+
+
+ {!displayHeaderOnly && (
+
+
+
+
+
+
+
+
+ )}
+ {/*TODO: Hide channel url field until it's added to CreateChannel */}
+ {false && editing && !displayHeaderOnly && (
+
+
+
+
+ {shortUrl}
+
+
+
+
+
+
+ )}
+ {!displayHeaderOnly && (
+
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+const getStyleSheet = makeStyleSheetFromTheme((theme) => {
+ return {
+ container: {
+ flex: 1,
+ backgroundColor: theme.centerChannelBg
+ },
+ scrollView: {
+ flex: 1,
+ backgroundColor: changeOpacity(theme.centerChannelColor, 0.03),
+ paddingTop: 10
+ },
+ errorContainer: {
+ backgroundColor: changeOpacity(theme.centerChannelColor, 0.03)
+ },
+ errorWrapper: {
+ justifyContent: 'center',
+ alignItems: 'center'
+ },
+ inputContainer: {
+ marginTop: 10,
+ backgroundColor: '#fff'
+ },
+ input: {
+ color: '#333',
+ fontSize: 14,
+ height: 40,
+ paddingHorizontal: 15
+ },
+ titleContainer30: {
+ flexDirection: 'row',
+ marginTop: 30
+ },
+ titleContainer15: {
+ flexDirection: 'row',
+ marginTop: 15
+ },
+ title: {
+ fontSize: 14,
+ color: theme.centerChannelColor,
+ marginLeft: 15
+ },
+ optional: {
+ color: changeOpacity(theme.centerChannelColor, 0.5),
+ fontSize: 14,
+ marginLeft: 5
+ },
+ helpText: {
+ fontSize: 14,
+ color: changeOpacity(theme.centerChannelColor, 0.5),
+ marginTop: 10,
+ marginHorizontal: 15
+ }
+ };
+});
+
diff --git a/app/constants/view.js b/app/constants/view.js
index d5a5ee13f..2ccaa3813 100644
--- a/app/constants/view.js
+++ b/app/constants/view.js
@@ -65,5 +65,7 @@ export default {
...ViewTypes,
POST_VISIBILITY_CHUNK_SIZE: 15,
FEATURE_TOGGLE_PREFIX: 'feature_enabled_',
- EMBED_PREVIEW: 'embed_preview'
+ EMBED_PREVIEW: 'embed_preview',
+ MIN_CHANNELNAME_LENGTH: 2,
+ MAX_CHANNELNAME_LENGTH: 22
};
diff --git a/app/screens/channel_info/channel_info.js b/app/screens/channel_info/channel_info.js
index 8ed5500f7..f65cc5173 100644
--- a/app/screens/channel_info/channel_info.js
+++ b/app/screens/channel_info/channel_info.js
@@ -12,7 +12,7 @@ import {
} from 'react-native';
import StatusBar from 'app/components/status_bar';
-import {preventDoubleTap} from 'app/utils/tap';
+import {wrapWithPreventDoubleTap} from 'app/utils/tap';
import {alertErrorWithFallback} from 'app/utils/general';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
@@ -35,6 +35,7 @@ class ChannelInfo extends PureComponent {
isCurrent: PropTypes.bool.isRequired,
isFavorite: PropTypes.bool.isRequired,
canManageUsers: PropTypes.bool.isRequired,
+ canEditChannel: PropTypes.bool.isRequired,
actions: PropTypes.shape({
closeDMChannel: PropTypes.func.isRequired,
closeGMChannel: PropTypes.func.isRequired,
@@ -74,7 +75,7 @@ class ChannelInfo extends PureComponent {
}
};
- goToChannelAddMembers = () => {
+ goToChannelAddMembers = wrapWithPreventDoubleTap(() => {
const {intl, navigator, theme} = this.props;
navigator.push({
backButtonTitle: '',
@@ -88,9 +89,9 @@ class ChannelInfo extends PureComponent {
screenBackgroundColor: theme.centerChannelBg
}
});
- };
+ });
- goToChannelMembers = () => {
+ goToChannelMembers = wrapWithPreventDoubleTap(() => {
const {canManageUsers, intl, navigator, theme} = this.props;
const id = canManageUsers ? 'channel_header.manageMembers' : 'channel_header.viewMembers';
const defaultMessage = canManageUsers ? 'Manage Members' : 'View Members';
@@ -107,9 +108,36 @@ class ChannelInfo extends PureComponent {
screenBackgroundColor: theme.centerChannelBg
}
});
+ });
+
+ handleChannelEdit = wrapWithPreventDoubleTap(() => {
+ const {intl, navigator, theme} = this.props;
+ const id = 'mobile.channel_info.edit';
+ const defaultMessage = 'Edit Channel';
+
+ navigator.push({
+ backButtonTitle: '',
+ screen: 'EditChannel',
+ title: intl.formatMessage({id, defaultMessage}),
+ animated: true,
+ navigatorStyle: {
+ navBarTextColor: theme.sidebarHeaderTextColor,
+ navBarBackgroundColor: theme.sidebarHeaderBg,
+ navBarButtonColor: theme.sidebarHeaderTextColor,
+ screenBackgroundColor: theme.centerChannelBg
+ }
+ });
+ });
+
+ handleLeave = () => {
+ this.handleDeleteOrLeave('leave');
};
- handleDeleteOrLeave(eventType) {
+ handleDelete = () => {
+ this.handleDeleteOrLeave('delete');
+ };
+
+ handleDeleteOrLeave = wrapWithPreventDoubleTap((eventType) => {
const {formatMessage} = this.props.intl;
const channel = this.props.currentChannel;
const term = channel.type === General.OPEN_CHANNEL ?
@@ -171,9 +199,9 @@ class ChannelInfo extends PureComponent {
onPress: onPressAction
}],
);
- }
+ });
- handleClose = () => {
+ handleClose = wrapWithPreventDoubleTap(() => {
const {currentChannel, isCurrent, isFavorite} = this.props;
const channel = Object.assign({}, currentChannel, {isCurrent}, {isFavorite});
const {closeDMChannel, closeGMChannel} = this.props.actions;
@@ -190,7 +218,7 @@ class ChannelInfo extends PureComponent {
});
break;
}
- };
+ });
handleFavorite = () => {
const {isFavorite, actions, currentChannel} = this.props;
@@ -232,6 +260,7 @@ class ChannelInfo extends PureComponent {
currentChannelCreatorName,
currentChannelMemberCount,
canManageUsers,
+ canEditChannel,
navigator,
status,
theme
@@ -299,7 +328,7 @@ class ChannelInfo extends PureComponent {
preventDoubleTap(this.goToChannelMembers)}
+ action={this.goToChannelMembers}
defaultMessage={canManageUsers ? 'Manage Members' : 'View Members'}
detail={currentChannelMemberCount}
icon='users'
@@ -312,7 +341,7 @@ class ChannelInfo extends PureComponent {
preventDoubleTap(this.goToChannelAddMembers)}
+ action={this.goToChannelAddMembers}
defaultMessage='Add Members'
icon='user-plus'
textId='channel_header.addMembers'
@@ -320,11 +349,23 @@ class ChannelInfo extends PureComponent {
/>
}
+ {canEditChannel && (
+
+
+
+
+ )}
{this.renderLeaveOrDeleteChannelRow() &&
preventDoubleTap(this.handleDeleteOrLeave, this, 'leave')}
+ action={this.handleLeave}
defaultMessage='Leave Channel'
icon='sign-out'
textId='navbar.leave'
@@ -336,7 +377,7 @@ class ChannelInfo extends PureComponent {
{this.renderLeaveOrDeleteChannelRow() && canDeleteChannel &&
preventDoubleTap(this.handleDeleteOrLeave, this, 'delete')}
+ action={this.handleDelete}
defaultMessage='Delete Channel'
icon='trash'
iconColor='#CA3B27'
@@ -349,7 +390,7 @@ class ChannelInfo extends PureComponent {
{this.renderCloseDirect() &&
preventDoubleTap(this.handleClose, this)}
+ action={this.handleClose}
defaultMessage={defaultMessage}
icon='times'
iconColor='#CA3B27'
diff --git a/app/screens/channel_info/index.js b/app/screens/channel_info/index.js
index 59999ed4e..37c6216a5 100644
--- a/app/screens/channel_info/index.js
+++ b/app/screens/channel_info/index.js
@@ -20,7 +20,7 @@ import {
canManageChannelMembers
} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentUserId, getUser, getStatusForUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/entities/users';
-import {getUserIdFromChannelName, showDeleteOption} from 'mattermost-redux/utils/channel_utils';
+import {getUserIdFromChannelName, showDeleteOption, showManagementOptions} from 'mattermost-redux/utils/channel_utils';
import {isAdmin, isChannelAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils';
import ChannelInfo from './channel_info';
@@ -47,6 +47,7 @@ function mapStateToProps(state) {
return {
canDeleteChannel: showDeleteOption(config, license, currentChannel, isAdmin(roles), isSystemAdmin(roles), isChannelAdmin(roles)),
+ canEditChannel: showManagementOptions(config, license, currentChannel, isAdmin(roles), isSystemAdmin(roles), isChannelAdmin(roles)),
currentChannel,
currentChannelCreatorName,
currentChannelMemberCount,
diff --git a/app/screens/create_channel/create_channel.js b/app/screens/create_channel/create_channel.js
index fbc09e46e..d1afc4d22 100644
--- a/app/screens/create_channel/create_channel.js
+++ b/app/screens/create_channel/create_channel.js
@@ -1,36 +1,25 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
+
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
-import {injectIntl, intlShape} from 'react-intl';
+import {intlShape} from 'react-intl';
import {
- Dimensions,
Keyboard,
- InteractionManager,
- Platform,
- TouchableWithoutFeedback,
- View,
- findNodeHandle
+ InteractionManager
} from 'react-native';
-import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
+import EditChannelInfo from 'app/components/edit_channel_info';
import {General, RequestStatus} from 'mattermost-redux/constants';
import EventEmitter from 'mattermost-redux/utils/event_emitter';
-import ErrorText from 'app/components/error_text';
-import FormattedText from 'app/components/formatted_text';
-import Loading from 'app/components/loading';
-import StatusBar from 'app/components/status_bar';
-import TextInputWithLocalizedPlaceholder from 'app/components/text_input_with_localized_placeholder';
-
-import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
-
-class CreateChannel extends PureComponent {
+export default class CreateChannel extends PureComponent {
static propTypes = {
- intl: intlShape.isRequired,
- createChannelRequest: PropTypes.object.isRequired,
- navigator: PropTypes.object,
+ navigator: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
+ deviceWidth: PropTypes.number.isRequired,
+ deviceHeight: PropTypes.number.isRequired,
+ createChannelRequest: PropTypes.object.isRequired,
channelType: PropTypes.string,
closeButton: PropTypes.object,
actions: PropTypes.shape({
@@ -38,6 +27,10 @@ class CreateChannel extends PureComponent {
})
};
+ static contextTypes = {
+ intl: intlShape
+ };
+
static defaultProps = {
channelType: General.OPEN_CHANNEL
};
@@ -52,15 +45,18 @@ class CreateChannel extends PureComponent {
showAsAction: 'always'
};
- constructor(props) {
+ constructor(props, context) {
super(props);
this.state = {
+ error: null,
+ creating: false,
displayName: '',
- header: '',
- purpose: ''
+ purpose: '',
+ header: ''
};
- this.rightButton.title = props.intl.formatMessage({id: 'mobile.create_channel', defaultMessage: 'Create'});
+
+ this.rightButton.title = context.intl.formatMessage({id: 'mobile.create_channel', defaultMessage: 'Create'});
if (props.channelType === General.PRIVATE_CHANNEL) {
this.left = {...this.leftButton, icon: props.closeButton};
@@ -107,25 +103,6 @@ class CreateChannel extends PureComponent {
}
}
- blur = () => {
- this.nameInput.refs.wrappedInstance.blur();
- this.purposeInput.refs.wrappedInstance.blur();
- this.headerInput.refs.wrappedInstance.blur();
- this.scroll.scrollToPosition(0, 0, true);
- };
-
- channelNameRef = (ref) => {
- this.nameInput = ref;
- };
-
- channelPurposeRef = (ref) => {
- this.purposeInput = ref;
- };
-
- channelHeaderRef = (ref) => {
- this.headerInput = ref;
- };
-
close = (goBack = false) => {
EventEmitter.emit('closing-create-channel', false);
if (goBack) {
@@ -161,25 +138,12 @@ class CreateChannel extends PureComponent {
this.props.navigator.setButtons(buttons);
};
- lastTextRef = (ref) => {
- this.lastText = ref;
- };
-
onCreateChannel = () => {
Keyboard.dismiss();
const {displayName, purpose, header} = this.state;
this.props.actions.handleCreateChannel(displayName, purpose, header, this.props.channelType);
};
- onDisplayNameChangeText = (displayName) => {
- this.setState({displayName});
- if (displayName && displayName.length >= 2) {
- this.emitCanCreateChannel(true);
- } else {
- this.emitCanCreateChannel(false);
- }
- };
-
onNavigatorEvent = (event) => {
if (event.type === 'NavBarButtonPress') {
switch (event.id) {
@@ -193,220 +157,50 @@ class CreateChannel extends PureComponent {
}
};
- onPurposeChangeText = (purpose) => {
+ onDisplayNameChange = (displayName) => {
+ this.setState({displayName});
+ };
+
+ onPurposeChange = (purpose) => {
this.setState({purpose});
};
- onHeaderChangeText = (header) => {
+ onHeaderChange = (header) => {
this.setState({header});
};
- scrollRef = (ref) => {
- this.scroll = ref;
- };
-
- scrollToEnd = () => {
- this.scroll.scrollToFocusedInput(findNodeHandle(this.lastText));
- };
-
render() {
- const {theme} = this.props;
- const {creating, displayName, header, purpose, error} = this.state;
- const {height, width} = Dimensions.get('window');
-
- const style = getStyleSheet(theme);
-
- if (creating) {
- return (
-
-
-
-
- );
- }
-
- let displayError;
- if (error) {
- displayError = (
-
-
-
-
-
- );
- }
+ const {
+ navigator,
+ theme,
+ deviceWidth,
+ deviceHeight
+ } = this.props;
+ const {
+ error,
+ creating,
+ displayName,
+ purpose,
+ header
+ } = this.state;
return (
-
-
-
- {displayError}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
);
}
}
-const getStyleSheet = makeStyleSheetFromTheme((theme) => {
- return {
- container: {
- flex: 1,
- backgroundColor: theme.centerChannelBg
- },
- scrollView: {
- flex: 1,
- backgroundColor: changeOpacity(theme.centerChannelColor, 0.03),
- paddingTop: 10
- },
- errorContainer: {
- backgroundColor: changeOpacity(theme.centerChannelColor, 0.03)
- },
- errorWrapper: {
- justifyContent: 'center',
- alignItems: 'center'
- },
- inputContainer: {
- marginTop: 10,
- backgroundColor: '#fff'
- },
- input: {
- color: '#333',
- fontSize: 14,
- height: 40,
- paddingHorizontal: 15
- },
- titleContainer30: {
- flexDirection: 'row',
- marginTop: 30
- },
- titleContainer15: {
- flexDirection: 'row',
- marginTop: 15
- },
- title: {
- fontSize: 14,
- color: theme.centerChannelColor,
- marginLeft: 15
- },
- optional: {
- color: changeOpacity(theme.centerChannelColor, 0.5),
- fontSize: 14,
- marginLeft: 5
- },
- helpText: {
- fontSize: 14,
- color: changeOpacity(theme.centerChannelColor, 0.5),
- marginTop: 10,
- marginHorizontal: 15
- },
- navTitle: {
- ...Platform.select({
- android: {
- fontSize: 18
- },
- ios: {
- fontSize: 15,
- fontWeight: 'bold'
- }
- })
- }
- };
-});
-
-export default injectIntl(CreateChannel);
diff --git a/app/screens/create_channel/index.js b/app/screens/create_channel/index.js
index 71c37913f..90400719a 100644
--- a/app/screens/create_channel/index.js
+++ b/app/screens/create_channel/index.js
@@ -7,16 +7,19 @@ import {connect} from 'react-redux';
import {handleCreateChannel} from 'app/actions/views/create_channel';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
+import {getDimensions} from 'app/selectors/device';
import CreateChannel from './create_channel';
-function mapStateToProps(state, ownProps) {
+function mapStateToProps(state) {
const {createChannel: createChannelRequest} = state.requests.channels;
+ const {deviceWidth, deviceHeight} = getDimensions(state);
return {
createChannelRequest,
- channelType: ownProps.channelType,
- theme: getTheme(state)
+ theme: getTheme(state),
+ deviceWidth,
+ deviceHeight
};
}
diff --git a/app/screens/edit_channel/edit_channel.js b/app/screens/edit_channel/edit_channel.js
new file mode 100644
index 000000000..d208a5d6a
--- /dev/null
+++ b/app/screens/edit_channel/edit_channel.js
@@ -0,0 +1,300 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React, {PureComponent} from 'react';
+import PropTypes from 'prop-types';
+import {intlShape} from 'react-intl';
+import {
+ Keyboard,
+ InteractionManager
+} from 'react-native';
+
+import EditChannelInfo from 'app/components/edit_channel_info';
+import {RequestStatus} from 'mattermost-redux/constants';
+import EventEmitter from 'mattermost-redux/utils/event_emitter';
+import {ViewTypes} from 'app/constants';
+
+import {cleanUpUrlable} from 'app/utils/url';
+
+const messages = {
+ display_name_required: {
+ id: 'mobile.rename_channel.display_name_required',
+ defaultMessage: 'Channel name is required'
+ },
+ display_name_maxLength: {
+ id: 'mobile.rename_channel.display_name_maxLength',
+ defaultMessage: 'Channel name must be less than {maxLength, number} characters'
+ },
+ display_name_minLength: {
+ id: 'mobile.rename_channel.display_name_minLength',
+ defaultMessage: 'Channel name must be {minLength, number} or more characters'
+ },
+ name_required: {
+ id: 'mobile.rename_channel.name_required',
+ defaultMessage: 'URL is required'
+ },
+ name_maxLength: {
+ id: 'mobile.rename_channel.name_maxLength',
+ defaultMessage: 'URL must be less than {maxLength, number} characters'
+ },
+ name_minLength: {
+ id: 'mobile.rename_channel.name_minLength',
+ defaultMessage: 'URL must be {minLength, number} or more characters'
+ },
+ name_lowercase: {
+ id: 'mobile.rename_channel.name_lowercase',
+ defaultMessage: 'URL be lowercase alphanumeric characters'
+ }
+};
+
+export default class EditChannel extends PureComponent {
+ static propTypes = {
+ navigator: PropTypes.object.isRequired,
+ theme: PropTypes.object.isRequired,
+ deviceWidth: PropTypes.number.isRequired,
+ deviceHeight: PropTypes.number.isRequired,
+ channel: PropTypes.object.isRequired,
+ currentTeamUrl: PropTypes.string.isRequired,
+ updateChannelRequest: PropTypes.object.isRequired,
+ closeButton: PropTypes.object,
+ actions: PropTypes.shape({
+ patchChannel: PropTypes.func.isRequired
+ })
+ };
+
+ static contextTypes = {
+ intl: intlShape
+ };
+
+ rightButton = {
+ id: 'edit-channel',
+ disabled: true,
+ showAsAction: 'always'
+ };
+
+ constructor(props, context) {
+ super(props);
+ const {
+ channel: {
+ display_name: displayName,
+ header,
+ purpose,
+ name: channelURL
+ }
+ } = props;
+
+ this.state = {
+ error: null,
+ updating: false,
+ displayName,
+ channelURL,
+ purpose,
+ header
+ };
+
+ this.rightButton.title = context.intl.formatMessage({id: 'mobile.edit_channel', defaultMessage: 'Save'});
+
+ const buttons = {
+ rightButtons: [this.rightButton]
+ };
+
+ props.navigator.setOnNavigatorEvent(this.onNavigatorEvent);
+ props.navigator.setButtons(buttons);
+ }
+
+ componentDidMount() {
+ this.emitCanUpdateChannel(false);
+ }
+
+ componentWillReceiveProps(nextProps) {
+ const {updateChannelRequest} = nextProps;
+
+ if (this.props.updateChannelRequest !== updateChannelRequest) {
+ switch (updateChannelRequest.status) {
+ case RequestStatus.STARTED:
+ this.emitUpdating(true);
+ this.setState({error: null, updating: true});
+ break;
+ case RequestStatus.SUCCESS:
+ EventEmitter.emit('close_channel_drawer');
+ InteractionManager.runAfterInteractions(() => {
+ this.emitUpdating(false);
+ this.setState({error: null, updating: false});
+ this.close();
+ });
+ break;
+ case RequestStatus.FAILURE:
+ this.emitUpdating(false);
+ this.setState({error: updateChannelRequest.error, updating: false});
+ break;
+ }
+ }
+ }
+
+ close = () => {
+ this.props.navigator.pop({animated: true});
+ };
+
+ emitCanUpdateChannel = (enabled) => {
+ const buttons = {
+ rightButtons: [{...this.rightButton, disabled: !enabled}]
+ };
+
+ this.props.navigator.setButtons(buttons);
+ };
+
+ emitUpdating = (loading) => {
+ const buttons = {
+ rightButtons: [{...this.rightButton, disabled: loading}]
+ };
+
+ this.props.navigator.setButtons(buttons);
+ };
+
+ validateDisplayName = (displayName) => {
+ const {formatMessage} = this.context.intl;
+
+ if (!displayName) {
+ return {error: formatMessage(messages.display_name_required)};
+ } else if (displayName.length > ViewTypes.MAX_CHANNELNAME_LENGTH) {
+ return {error: formatMessage(
+ messages.display_name_maxLength,
+ {maxLength: ViewTypes.MAX_CHANNELNAME_LENGTH}
+ )};
+ } else if (displayName.length < ViewTypes.MIN_CHANNELNAME_LENGTH) {
+ return {error: formatMessage(
+ messages.display_name_minLength,
+ {minLength: ViewTypes.MIN_CHANNELNAME_LENGTH}
+ )};
+ }
+
+ return {error: null};
+ };
+
+ validateChannelURL = (channelURL) => {
+ const {formatMessage} = this.context.intl;
+
+ if (!channelURL) {
+ return {error: formatMessage(messages.name_required)};
+ } else if (channelURL.length > ViewTypes.MAX_CHANNELNAME_LENGTH) {
+ return {error: formatMessage(
+ messages.name_maxLength,
+ {maxLength: ViewTypes.MAX_CHANNELNAME_LENGTH}
+ )};
+ }
+
+ const cleanedName = cleanUpUrlable(channelURL);
+ if (cleanedName === channelURL) {
+ return {error: null};
+ }
+
+ return {error: formatMessage(messages.name_lowercase)};
+ };
+
+ onUpdateChannel = () => {
+ Keyboard.dismiss();
+ const {displayName, channelURL, purpose, header} = this.state;
+ const {channel: {id}} = this.props;
+ const channel = {
+ display_name: displayName,
+ name: channelURL,
+ purpose,
+ header
+ };
+
+ let result = this.validateDisplayName(displayName.trim());
+ if (result.error) {
+ this.setState({error: result.error});
+ return;
+ }
+ result = this.validateChannelURL(channelURL.trim());
+ if (result.error) {
+ this.setState({error: result.error});
+ return;
+ }
+
+ this.props.actions.patchChannel(id, channel);
+ };
+
+ onNavigatorEvent = (event) => {
+ if (event.type === 'NavBarButtonPress') {
+ switch (event.id) {
+ case 'close-edit-channel':
+ this.close();
+ break;
+ case 'edit-channel':
+ this.onUpdateChannel();
+ break;
+ }
+ }
+ };
+
+ onDisplayNameChange = (displayName) => {
+ this.setState({displayName});
+ };
+
+ onChannelURLChange = (channelURL) => {
+ this.setState({channelURL});
+ };
+
+ onPurposeChange = (purpose) => {
+ this.setState({purpose});
+ };
+
+ onHeaderChange = (header) => {
+ this.setState({header});
+ };
+
+ render() {
+ const {
+ channel: {
+ display_name: oldDisplayName,
+ name: oldChannelURL,
+ header: oldHeader,
+ purpose: oldPurpose,
+ type
+ },
+ navigator,
+ theme,
+ currentTeamUrl,
+ deviceWidth,
+ deviceHeight
+ } = this.props;
+ const {
+ error,
+ updating,
+ displayName,
+ channelURL,
+ purpose,
+ header
+ } = this.state;
+
+ return (
+
+ );
+ }
+}
+
diff --git a/app/screens/edit_channel/index.js b/app/screens/edit_channel/index.js
new file mode 100644
index 000000000..8076ea471
--- /dev/null
+++ b/app/screens/edit_channel/index.js
@@ -0,0 +1,39 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import {bindActionCreators} from 'redux';
+import {connect} from 'react-redux';
+
+import {getCurrentChannel} from 'mattermost-redux/selectors/entities/channels';
+import {getCurrentTeamUrl} from 'mattermost-redux/selectors/entities/teams';
+import {patchChannel} from 'mattermost-redux/actions/channels';
+
+import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
+import {getDimensions} from 'app/selectors/device';
+
+import EditChannel from './edit_channel';
+
+function mapStateToProps(state) {
+ const {updateChannel: updateChannelRequest} = state.requests.channels;
+ const channel = getCurrentChannel(state);
+ const {deviceWidth, deviceHeight} = getDimensions(state);
+
+ return {
+ channel,
+ currentTeamUrl: getCurrentTeamUrl(state),
+ updateChannelRequest,
+ theme: getTheme(state),
+ deviceWidth,
+ deviceHeight
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators({
+ patchChannel
+ }, dispatch)
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(EditChannel);
diff --git a/app/screens/index.js b/app/screens/index.js
index 5a719352a..fcda5bd0a 100644
--- a/app/screens/index.js
+++ b/app/screens/index.js
@@ -11,6 +11,7 @@ import AdvancedSettings from 'app/screens/settings/advanced_settings';
import Channel from 'app/screens/channel';
import ChannelAddMembers from 'app/screens/channel_add_members';
import ChannelInfo from 'app/screens/channel_info';
+import EditChannel from 'app/screens/edit_channel';
import ChannelMembers from 'app/screens/channel_members';
import ChannelPeek from 'app/screens/channel_peek';
import ClientUpgrade from 'app/screens/client_upgrade';
@@ -63,6 +64,7 @@ export function registerScreens(store, Provider) {
Navigation.registerComponent('Channel', () => wrapWithContextProvider(Channel, false), store, Provider);
Navigation.registerComponent('ChannelAddMembers', () => wrapWithContextProvider(ChannelAddMembers), store, Provider);
Navigation.registerComponent('ChannelInfo', () => wrapWithContextProvider(ChannelInfo), store, Provider);
+ Navigation.registerComponent('EditChannel', () => wrapWithContextProvider(EditChannel), store, Provider);
Navigation.registerComponent('ChannelMembers', () => wrapWithContextProvider(ChannelMembers), store, Provider);
Navigation.registerComponent('ChannelPeek', () => wrapWithContextProvider(ChannelPeek), store, Provider);
Navigation.registerComponent('ClientUpgrade', () => wrapWithContextProvider(ClientUpgrade), store, Provider);
diff --git a/app/utils/latinise.js b/app/utils/latinise.js
new file mode 100644
index 000000000..5c0059ff1
--- /dev/null
+++ b/app/utils/latinise.js
@@ -0,0 +1,1003 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+// Credit to http://semplicewebsites.com/removing-accents-javascript
+
+var latinMap = {
+ Á: 'A', // LATIN CAPITAL LETTER A WITH ACUTE
+ Ă: 'A', // LATIN CAPITAL LETTER A WITH BREVE
+ Ắ: 'A', // LATIN CAPITAL LETTER A WITH BREVE AND ACUTE
+ Ặ: 'A', // LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW
+ Ằ: 'A', // LATIN CAPITAL LETTER A WITH BREVE AND GRAVE
+ Ẳ: 'A', // LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE
+ Ẵ: 'A', // LATIN CAPITAL LETTER A WITH BREVE AND TILDE
+ Ǎ: 'A', // LATIN CAPITAL LETTER A WITH CARON
+ Â: 'A', // LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ Ấ: 'A', // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE
+ Ậ: 'A', // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+ Ầ: 'A', // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE
+ Ẩ: 'A', // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+ Ẫ: 'A', // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE
+ Ä: 'A', // LATIN CAPITAL LETTER A WITH DIAERESIS
+ Ǟ: 'A', // LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON
+ Ȧ: 'A', // LATIN CAPITAL LETTER A WITH DOT ABOVE
+ Ǡ: 'A', // LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON
+ Ạ: 'A', // LATIN CAPITAL LETTER A WITH DOT BELOW
+ Ȁ: 'A', // LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
+ À: 'A', // LATIN CAPITAL LETTER A WITH GRAVE
+ Ả: 'A', // LATIN CAPITAL LETTER A WITH HOOK ABOVE
+ Ȃ: 'A', // LATIN CAPITAL LETTER A WITH INVERTED BREVE
+ Ā: 'A', // LATIN CAPITAL LETTER A WITH MACRON
+ Ą: 'A', // LATIN CAPITAL LETTER A WITH OGONEK
+ Å: 'A', // LATIN CAPITAL LETTER A WITH RING ABOVE
+ Ǻ: 'A', // LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
+ Ḁ: 'A', // LATIN CAPITAL LETTER A WITH RING BELOW
+ Ⱥ: 'A', // LATIN CAPITAL LETTER A WITH STROKE
+ Ã: 'A', // LATIN CAPITAL LETTER A WITH TILDE
+ Ꜳ: 'AA', // LATIN CAPITAL LETTER AA
+ Æ: 'AE', // LATIN CAPITAL LETTER AE
+ Ǽ: 'AE', // LATIN CAPITAL LETTER AE WITH ACUTE
+ Ǣ: 'AE', // LATIN CAPITAL LETTER AE WITH MACRON
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER AFRICAN D' (Ɖ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER ALPHA' (Ɑ)
+ Ꜵ: 'AO', // LATIN CAPITAL LETTER AO
+ Ꜷ: 'AU', // LATIN CAPITAL LETTER AU
+ Ꜹ: 'AV', // LATIN CAPITAL LETTER AV
+ Ꜻ: 'AV', // LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR
+ Ꜽ: 'AY', // LATIN CAPITAL LETTER AY
+ Ḃ: 'B', // LATIN CAPITAL LETTER B WITH DOT ABOVE
+ Ḅ: 'B', // LATIN CAPITAL LETTER B WITH DOT BELOW
+ Ɓ: 'B', // LATIN CAPITAL LETTER B WITH HOOK
+ Ḇ: 'B', // LATIN CAPITAL LETTER B WITH LINE BELOW
+ Ƀ: 'B', // LATIN CAPITAL LETTER B WITH STROKE
+ Ƃ: 'B', // LATIN CAPITAL LETTER B WITH TOPBAR
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER BROKEN L' (Ꝇ)
+ Ć: 'C', // LATIN CAPITAL LETTER C WITH ACUTE
+ Č: 'C', // LATIN CAPITAL LETTER C WITH CARON
+ Ç: 'C', // LATIN CAPITAL LETTER C WITH CEDILLA
+ Ḉ: 'C', // LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE
+ Ĉ: 'C', // LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+ Ċ: 'C', // LATIN CAPITAL LETTER C WITH DOT ABOVE
+ Ƈ: 'C', // LATIN CAPITAL LETTER C WITH HOOK
+ Ȼ: 'C', // LATIN CAPITAL LETTER C WITH STROKE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER CON' (Ꝯ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER CUATRILLO' (Ꜭ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER CUATRILLO WITH COMMA' (Ꜯ)
+ Ď: 'D', // LATIN CAPITAL LETTER D WITH CARON
+ Ḑ: 'D', // LATIN CAPITAL LETTER D WITH CEDILLA
+ Ḓ: 'D', // LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW
+ Ḋ: 'D', // LATIN CAPITAL LETTER D WITH DOT ABOVE
+ Ḍ: 'D', // LATIN CAPITAL LETTER D WITH DOT BELOW
+ Ɗ: 'D', // LATIN CAPITAL LETTER D WITH HOOK
+ Ḏ: 'D', // LATIN CAPITAL LETTER D WITH LINE BELOW
+ Dz: 'D', // LATIN CAPITAL LETTER D WITH SMALL LETTER Z
+ Dž: 'D', // LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
+ Đ: 'D', // LATIN CAPITAL LETTER D WITH STROKE
+ Ƌ: 'D', // LATIN CAPITAL LETTER D WITH TOPBAR
+ DZ: 'DZ', // LATIN CAPITAL LETTER DZ
+ DŽ: 'DZ', // LATIN CAPITAL LETTER DZ WITH CARON
+ É: 'E', // LATIN CAPITAL LETTER E WITH ACUTE
+ Ĕ: 'E', // LATIN CAPITAL LETTER E WITH BREVE
+ Ě: 'E', // LATIN CAPITAL LETTER E WITH CARON
+ Ȩ: 'E', // LATIN CAPITAL LETTER E WITH CEDILLA
+ Ḝ: 'E', // LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE
+ Ê: 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ Ế: 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE
+ Ệ: 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+ Ề: 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE
+ Ể: 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+ Ễ: 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE
+ Ḙ: 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW
+ Ë: 'E', // LATIN CAPITAL LETTER E WITH DIAERESIS
+ Ė: 'E', // LATIN CAPITAL LETTER E WITH DOT ABOVE
+ Ẹ: 'E', // LATIN CAPITAL LETTER E WITH DOT BELOW
+ Ȅ: 'E', // LATIN CAPITAL LETTER E WITH DOUBLE GRAVE
+ È: 'E', // LATIN CAPITAL LETTER E WITH GRAVE
+ Ẻ: 'E', // LATIN CAPITAL LETTER E WITH HOOK ABOVE
+ Ȇ: 'E', // LATIN CAPITAL LETTER E WITH INVERTED BREVE
+ Ē: 'E', // LATIN CAPITAL LETTER E WITH MACRON
+ Ḗ: 'E', // LATIN CAPITAL LETTER E WITH MACRON AND ACUTE
+ Ḕ: 'E', // LATIN CAPITAL LETTER E WITH MACRON AND GRAVE
+ Ę: 'E', // LATIN CAPITAL LETTER E WITH OGONEK
+ Ɇ: 'E', // LATIN CAPITAL LETTER E WITH STROKE
+ Ẽ: 'E', // LATIN CAPITAL LETTER E WITH TILDE
+ Ḛ: 'E', // LATIN CAPITAL LETTER E WITH TILDE BELOW
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER EGYPTOLOGICAL AIN' (Ꜥ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF' (Ꜣ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER ENG' (Ŋ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER ESH' (Ʃ)
+ Ꝫ: 'ET', // LATIN CAPITAL LETTER ET
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER ETH' (Ð)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER EZH' (Ʒ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER EZH REVERSED' (Ƹ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER EZH WITH CARON' (Ǯ)
+ Ḟ: 'F', // LATIN CAPITAL LETTER F WITH DOT ABOVE
+ Ƒ: 'F', // LATIN CAPITAL LETTER F WITH HOOK
+ Ǵ: 'G', // LATIN CAPITAL LETTER G WITH ACUTE
+ Ğ: 'G', // LATIN CAPITAL LETTER G WITH BREVE
+ Ǧ: 'G', // LATIN CAPITAL LETTER G WITH CARON
+ Ģ: 'G', // LATIN CAPITAL LETTER G WITH CEDILLA
+ Ĝ: 'G', // LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+ Ġ: 'G', // LATIN CAPITAL LETTER G WITH DOT ABOVE
+ Ɠ: 'G', // LATIN CAPITAL LETTER G WITH HOOK
+ Ḡ: 'G', // LATIN CAPITAL LETTER G WITH MACRON
+ Ǥ: 'G', // LATIN CAPITAL LETTER G WITH STROKE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER GAMMA' (Ɣ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER GLOTTAL STOP' (Ɂ)
+ Ḫ: 'H', // LATIN CAPITAL LETTER H WITH BREVE BELOW
+ Ȟ: 'H', // LATIN CAPITAL LETTER H WITH CARON
+ Ḩ: 'H', // LATIN CAPITAL LETTER H WITH CEDILLA
+ Ĥ: 'H', // LATIN CAPITAL LETTER H WITH CIRCUMFLEX
+ Ⱨ: 'H', // LATIN CAPITAL LETTER H WITH DESCENDER
+ Ḧ: 'H', // LATIN CAPITAL LETTER H WITH DIAERESIS
+ Ḣ: 'H', // LATIN CAPITAL LETTER H WITH DOT ABOVE
+ Ḥ: 'H', // LATIN CAPITAL LETTER H WITH DOT BELOW
+ Ħ: 'H', // LATIN CAPITAL LETTER H WITH STROKE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER HALF H' (Ⱶ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER HENG' (Ꜧ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER HWAIR' (Ƕ)
+ Í: 'I', // LATIN CAPITAL LETTER I WITH ACUTE
+ Ĭ: 'I', // LATIN CAPITAL LETTER I WITH BREVE
+ Ǐ: 'I', // LATIN CAPITAL LETTER I WITH CARON
+ Î: 'I', // LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ Ï: 'I', // LATIN CAPITAL LETTER I WITH DIAERESIS
+ Ḯ: 'I', // LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE
+ İ: 'I', // LATIN CAPITAL LETTER I WITH DOT ABOVE
+ Ị: 'I', // LATIN CAPITAL LETTER I WITH DOT BELOW
+ Ȉ: 'I', // LATIN CAPITAL LETTER I WITH DOUBLE GRAVE
+ Ì: 'I', // LATIN CAPITAL LETTER I WITH GRAVE
+ Ỉ: 'I', // LATIN CAPITAL LETTER I WITH HOOK ABOVE
+ Ȋ: 'I', // LATIN CAPITAL LETTER I WITH INVERTED BREVE
+ Ī: 'I', // LATIN CAPITAL LETTER I WITH MACRON
+ Į: 'I', // LATIN CAPITAL LETTER I WITH OGONEK
+ Ɨ: 'I', // LATIN CAPITAL LETTER I WITH STROKE
+ Ĩ: 'I', // LATIN CAPITAL LETTER I WITH TILDE
+ Ḭ: 'I', // LATIN CAPITAL LETTER I WITH TILDE BELOW
+ Ꝺ: 'D', // LATIN CAPITAL LETTER INSULAR D
+ Ꝼ: 'F', // LATIN CAPITAL LETTER INSULAR F
+ Ᵹ: 'G', // LATIN CAPITAL LETTER INSULAR G
+ Ꞃ: 'R', // LATIN CAPITAL LETTER INSULAR R
+ Ꞅ: 'S', // LATIN CAPITAL LETTER INSULAR S
+ Ꞇ: 'T', // LATIN CAPITAL LETTER INSULAR T
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER IOTA' (Ɩ)
+ Ꝭ: 'IS', // LATIN CAPITAL LETTER IS
+ Ĵ: 'J', // LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+ Ɉ: 'J', // LATIN CAPITAL LETTER J WITH STROKE
+ Ḱ: 'K', // LATIN CAPITAL LETTER K WITH ACUTE
+ Ǩ: 'K', // LATIN CAPITAL LETTER K WITH CARON
+ Ķ: 'K', // LATIN CAPITAL LETTER K WITH CEDILLA
+ Ⱪ: 'K', // LATIN CAPITAL LETTER K WITH DESCENDER
+ Ꝃ: 'K', // LATIN CAPITAL LETTER K WITH DIAGONAL STROKE
+ Ḳ: 'K', // LATIN CAPITAL LETTER K WITH DOT BELOW
+ Ƙ: 'K', // LATIN CAPITAL LETTER K WITH HOOK
+ Ḵ: 'K', // LATIN CAPITAL LETTER K WITH LINE BELOW
+ Ꝁ: 'K', // LATIN CAPITAL LETTER K WITH STROKE
+ Ꝅ: 'K', // LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE
+ Ĺ: 'L', // LATIN CAPITAL LETTER L WITH ACUTE
+ Ƚ: 'L', // LATIN CAPITAL LETTER L WITH BAR
+ Ľ: 'L', // LATIN CAPITAL LETTER L WITH CARON
+ Ļ: 'L', // LATIN CAPITAL LETTER L WITH CEDILLA
+ Ḽ: 'L', // LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW
+ Ḷ: 'L', // LATIN CAPITAL LETTER L WITH DOT BELOW
+ Ḹ: 'L', // LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON
+ Ⱡ: 'L', // LATIN CAPITAL LETTER L WITH DOUBLE BAR
+ Ꝉ: 'L', // LATIN CAPITAL LETTER L WITH HIGH STROKE
+ Ḻ: 'L', // LATIN CAPITAL LETTER L WITH LINE BELOW
+ Ŀ: 'L', // LATIN CAPITAL LETTER L WITH MIDDLE DOT
+ Ɫ: 'L', // LATIN CAPITAL LETTER L WITH MIDDLE TILDE
+ Lj: 'L', // LATIN CAPITAL LETTER L WITH SMALL LETTER J
+ Ł: 'L', // LATIN CAPITAL LETTER L WITH STROKE
+ LJ: 'LJ', // LATIN CAPITAL LETTER LJ
+ Ḿ: 'M', // LATIN CAPITAL LETTER M WITH ACUTE
+ Ṁ: 'M', // LATIN CAPITAL LETTER M WITH DOT ABOVE
+ Ṃ: 'M', // LATIN CAPITAL LETTER M WITH DOT BELOW
+ Ɱ: 'M', // LATIN CAPITAL LETTER M WITH HOOK
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER MIDDLE-WELSH LL' (Ỻ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER MIDDLE-WELSH V' (Ỽ)
+ Ń: 'N', // LATIN CAPITAL LETTER N WITH ACUTE
+ Ň: 'N', // LATIN CAPITAL LETTER N WITH CARON
+ Ņ: 'N', // LATIN CAPITAL LETTER N WITH CEDILLA
+ Ṋ: 'N', // LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW
+ Ṅ: 'N', // LATIN CAPITAL LETTER N WITH DOT ABOVE
+ Ṇ: 'N', // LATIN CAPITAL LETTER N WITH DOT BELOW
+ Ǹ: 'N', // LATIN CAPITAL LETTER N WITH GRAVE
+ Ɲ: 'N', // LATIN CAPITAL LETTER N WITH LEFT HOOK
+ Ṉ: 'N', // LATIN CAPITAL LETTER N WITH LINE BELOW
+ Ƞ: 'N', // LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
+ Nj: 'N', // LATIN CAPITAL LETTER N WITH SMALL LETTER J
+ Ñ: 'N', // LATIN CAPITAL LETTER N WITH TILDE
+ NJ: 'NJ', // LATIN CAPITAL LETTER NJ
+ Ó: 'O', // LATIN CAPITAL LETTER O WITH ACUTE
+ Ŏ: 'O', // LATIN CAPITAL LETTER O WITH BREVE
+ Ǒ: 'O', // LATIN CAPITAL LETTER O WITH CARON
+ Ô: 'O', // LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ Ố: 'O', // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE
+ Ộ: 'O', // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+ Ồ: 'O', // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE
+ Ổ: 'O', // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+ Ỗ: 'O', // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE
+ Ö: 'O', // LATIN CAPITAL LETTER O WITH DIAERESIS
+ Ȫ: 'O', // LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON
+ Ȯ: 'O', // LATIN CAPITAL LETTER O WITH DOT ABOVE
+ Ȱ: 'O', // LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON
+ Ọ: 'O', // LATIN CAPITAL LETTER O WITH DOT BELOW
+ Ő: 'O', // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+ Ȍ: 'O', // LATIN CAPITAL LETTER O WITH DOUBLE GRAVE
+ Ò: 'O', // LATIN CAPITAL LETTER O WITH GRAVE
+ Ỏ: 'O', // LATIN CAPITAL LETTER O WITH HOOK ABOVE
+ Ơ: 'O', // LATIN CAPITAL LETTER O WITH HORN
+ Ớ: 'O', // LATIN CAPITAL LETTER O WITH HORN AND ACUTE
+ Ợ: 'O', // LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW
+ Ờ: 'O', // LATIN CAPITAL LETTER O WITH HORN AND GRAVE
+ Ở: 'O', // LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE
+ Ỡ: 'O', // LATIN CAPITAL LETTER O WITH HORN AND TILDE
+ Ȏ: 'O', // LATIN CAPITAL LETTER O WITH INVERTED BREVE
+ Ꝋ: 'O', // LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY
+ Ꝍ: 'O', // LATIN CAPITAL LETTER O WITH LOOP
+ Ō: 'O', // LATIN CAPITAL LETTER O WITH MACRON
+ Ṓ: 'O', // LATIN CAPITAL LETTER O WITH MACRON AND ACUTE
+ Ṑ: 'O', // LATIN CAPITAL LETTER O WITH MACRON AND GRAVE
+ Ɵ: 'O', // LATIN CAPITAL LETTER O WITH MIDDLE TILDE
+ Ǫ: 'O', // LATIN CAPITAL LETTER O WITH OGONEK
+ Ǭ: 'O', // LATIN CAPITAL LETTER O WITH OGONEK AND MACRON
+ Ø: 'O', // LATIN CAPITAL LETTER O WITH STROKE
+ Ǿ: 'O', // LATIN CAPITAL LETTER O WITH STROKE AND ACUTE
+ Õ: 'O', // LATIN CAPITAL LETTER O WITH TILDE
+ Ṍ: 'O', // LATIN CAPITAL LETTER O WITH TILDE AND ACUTE
+ Ṏ: 'O', // LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS
+ Ȭ: 'O', // LATIN CAPITAL LETTER O WITH TILDE AND MACRON
+ Ƣ: 'OI', // LATIN CAPITAL LETTER OI
+ Ꝏ: 'OO', // LATIN CAPITAL LETTER OO
+ Ɛ: 'E', // LATIN CAPITAL LETTER OPEN E
+ Ɔ: 'O', // LATIN CAPITAL LETTER OPEN O
+ Ȣ: 'OU', // LATIN CAPITAL LETTER OU
+ Ṕ: 'P', // LATIN CAPITAL LETTER P WITH ACUTE
+ Ṗ: 'P', // LATIN CAPITAL LETTER P WITH DOT ABOVE
+ Ꝓ: 'P', // LATIN CAPITAL LETTER P WITH FLOURISH
+ Ƥ: 'P', // LATIN CAPITAL LETTER P WITH HOOK
+ Ꝕ: 'P', // LATIN CAPITAL LETTER P WITH SQUIRREL TAIL
+ Ᵽ: 'P', // LATIN CAPITAL LETTER P WITH STROKE
+ Ꝑ: 'P', // LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER
+ Ꝙ: 'Q', // LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE
+ Ꝗ: 'Q', // LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER R ROTUNDA' (Ꝛ)
+ Ŕ: 'R', // LATIN CAPITAL LETTER R WITH ACUTE
+ Ř: 'R', // LATIN CAPITAL LETTER R WITH CARON
+ Ŗ: 'R', // LATIN CAPITAL LETTER R WITH CEDILLA
+ Ṙ: 'R', // LATIN CAPITAL LETTER R WITH DOT ABOVE
+ Ṛ: 'R', // LATIN CAPITAL LETTER R WITH DOT BELOW
+ Ṝ: 'R', // LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON
+ Ȑ: 'R', // LATIN CAPITAL LETTER R WITH DOUBLE GRAVE
+ Ȓ: 'R', // LATIN CAPITAL LETTER R WITH INVERTED BREVE
+ Ṟ: 'R', // LATIN CAPITAL LETTER R WITH LINE BELOW
+ Ɍ: 'R', // LATIN CAPITAL LETTER R WITH STROKE
+ Ɽ: 'R', // LATIN CAPITAL LETTER R WITH TAIL
+ Ꜿ: 'C', // LATIN CAPITAL LETTER REVERSED C WITH DOT
+ Ǝ: 'E', // LATIN CAPITAL LETTER REVERSED E
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER RUM ROTUNDA' (Ꝝ)
+ Ś: 'S', // LATIN CAPITAL LETTER S WITH ACUTE
+ Ṥ: 'S', // LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE
+ Š: 'S', // LATIN CAPITAL LETTER S WITH CARON
+ Ṧ: 'S', // LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE
+ Ş: 'S', // LATIN CAPITAL LETTER S WITH CEDILLA
+ Ŝ: 'S', // LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+ Ș: 'S', // LATIN CAPITAL LETTER S WITH COMMA BELOW
+ Ṡ: 'S', // LATIN CAPITAL LETTER S WITH DOT ABOVE
+ Ṣ: 'S', // LATIN CAPITAL LETTER S WITH DOT BELOW
+ Ṩ: 'S', // LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER SALTILLO' (Ꞌ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER SCHWA' (Ə)
+ ẞ: 'SS', // LATIN CAPITAL LETTER SHARP S
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL' (Ɋ)
+ Ť: 'T', // LATIN CAPITAL LETTER T WITH CARON
+ Ţ: 'T', // LATIN CAPITAL LETTER T WITH CEDILLA
+ Ṱ: 'T', // LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW
+ Ț: 'T', // LATIN CAPITAL LETTER T WITH COMMA BELOW
+ Ⱦ: 'T', // LATIN CAPITAL LETTER T WITH DIAGONAL STROKE
+ Ṫ: 'T', // LATIN CAPITAL LETTER T WITH DOT ABOVE
+ Ṭ: 'T', // LATIN CAPITAL LETTER T WITH DOT BELOW
+ Ƭ: 'T', // LATIN CAPITAL LETTER T WITH HOOK
+ Ṯ: 'T', // LATIN CAPITAL LETTER T WITH LINE BELOW
+ Ʈ: 'T', // LATIN CAPITAL LETTER T WITH RETROFLEX HOOK
+ Ŧ: 'T', // LATIN CAPITAL LETTER T WITH STROKE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER THORN' (Þ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER THORN WITH STROKE' (Ꝥ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER' (Ꝧ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER TONE FIVE' (Ƽ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER TONE SIX' (Ƅ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER TONE TWO' (Ƨ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER TRESILLO' (Ꜫ)
+ Ɐ: 'A', // LATIN CAPITAL LETTER TURNED A
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER TURNED INSULAR G' (Ꝿ)
+ Ꞁ: 'L', // LATIN CAPITAL LETTER TURNED L
+ Ɯ: 'M', // LATIN CAPITAL LETTER TURNED M
+ Ʌ: 'V', // LATIN CAPITAL LETTER TURNED V
+ Ꜩ: 'TZ', // LATIN CAPITAL LETTER TZ
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER U BAR' (Ʉ)
+ Ú: 'U', // LATIN CAPITAL LETTER U WITH ACUTE
+ Ŭ: 'U', // LATIN CAPITAL LETTER U WITH BREVE
+ Ǔ: 'U', // LATIN CAPITAL LETTER U WITH CARON
+ Û: 'U', // LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ Ṷ: 'U', // LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW
+ Ü: 'U', // LATIN CAPITAL LETTER U WITH DIAERESIS
+ Ǘ: 'U', // LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
+ Ǚ: 'U', // LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
+ Ǜ: 'U', // LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
+ Ǖ: 'U', // LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
+ Ṳ: 'U', // LATIN CAPITAL LETTER U WITH DIAERESIS BELOW
+ Ụ: 'U', // LATIN CAPITAL LETTER U WITH DOT BELOW
+ Ű: 'U', // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+ Ȕ: 'U', // LATIN CAPITAL LETTER U WITH DOUBLE GRAVE
+ Ù: 'U', // LATIN CAPITAL LETTER U WITH GRAVE
+ Ủ: 'U', // LATIN CAPITAL LETTER U WITH HOOK ABOVE
+ Ư: 'U', // LATIN CAPITAL LETTER U WITH HORN
+ Ứ: 'U', // LATIN CAPITAL LETTER U WITH HORN AND ACUTE
+ Ự: 'U', // LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW
+ Ừ: 'U', // LATIN CAPITAL LETTER U WITH HORN AND GRAVE
+ Ử: 'U', // LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE
+ Ữ: 'U', // LATIN CAPITAL LETTER U WITH HORN AND TILDE
+ Ȗ: 'U', // LATIN CAPITAL LETTER U WITH INVERTED BREVE
+ Ū: 'U', // LATIN CAPITAL LETTER U WITH MACRON
+ Ṻ: 'U', // LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS
+ Ų: 'U', // LATIN CAPITAL LETTER U WITH OGONEK
+ Ů: 'U', // LATIN CAPITAL LETTER U WITH RING ABOVE
+ Ũ: 'U', // LATIN CAPITAL LETTER U WITH TILDE
+ Ṹ: 'U', // LATIN CAPITAL LETTER U WITH TILDE AND ACUTE
+ Ṵ: 'U', // LATIN CAPITAL LETTER U WITH TILDE BELOW
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER UPSILON' (Ʊ)
+ Ꝟ: 'V', // LATIN CAPITAL LETTER V WITH DIAGONAL STROKE
+ Ṿ: 'V', // LATIN CAPITAL LETTER V WITH DOT BELOW
+ Ʋ: 'V', // LATIN CAPITAL LETTER V WITH HOOK
+ Ṽ: 'V', // LATIN CAPITAL LETTER V WITH TILDE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER VEND' (Ꝩ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER VISIGOTHIC Z' (Ꝣ)
+ Ꝡ: 'VY', // LATIN CAPITAL LETTER VY
+ Ẃ: 'W', // LATIN CAPITAL LETTER W WITH ACUTE
+ Ŵ: 'W', // LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+ Ẅ: 'W', // LATIN CAPITAL LETTER W WITH DIAERESIS
+ Ẇ: 'W', // LATIN CAPITAL LETTER W WITH DOT ABOVE
+ Ẉ: 'W', // LATIN CAPITAL LETTER W WITH DOT BELOW
+ Ẁ: 'W', // LATIN CAPITAL LETTER W WITH GRAVE
+ Ⱳ: 'W', // LATIN CAPITAL LETTER W WITH HOOK
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER WYNN' (Ƿ)
+ Ẍ: 'X', // LATIN CAPITAL LETTER X WITH DIAERESIS
+ Ẋ: 'X', // LATIN CAPITAL LETTER X WITH DOT ABOVE
+ Ý: 'Y', // LATIN CAPITAL LETTER Y WITH ACUTE
+ Ŷ: 'Y', // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+ Ÿ: 'Y', // LATIN CAPITAL LETTER Y WITH DIAERESIS
+ Ẏ: 'Y', // LATIN CAPITAL LETTER Y WITH DOT ABOVE
+ Ỵ: 'Y', // LATIN CAPITAL LETTER Y WITH DOT BELOW
+ Ỳ: 'Y', // LATIN CAPITAL LETTER Y WITH GRAVE
+ Ƴ: 'Y', // LATIN CAPITAL LETTER Y WITH HOOK
+ Ỷ: 'Y', // LATIN CAPITAL LETTER Y WITH HOOK ABOVE
+ Ỿ: 'Y', // LATIN CAPITAL LETTER Y WITH LOOP
+ Ȳ: 'Y', // LATIN CAPITAL LETTER Y WITH MACRON
+ Ɏ: 'Y', // LATIN CAPITAL LETTER Y WITH STROKE
+ Ỹ: 'Y', // LATIN CAPITAL LETTER Y WITH TILDE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CAPITAL LETTER YOGH' (Ȝ)
+ Ź: 'Z', // LATIN CAPITAL LETTER Z WITH ACUTE
+ Ž: 'Z', // LATIN CAPITAL LETTER Z WITH CARON
+ Ẑ: 'Z', // LATIN CAPITAL LETTER Z WITH CIRCUMFLEX
+ Ⱬ: 'Z', // LATIN CAPITAL LETTER Z WITH DESCENDER
+ Ż: 'Z', // LATIN CAPITAL LETTER Z WITH DOT ABOVE
+ Ẓ: 'Z', // LATIN CAPITAL LETTER Z WITH DOT BELOW
+ Ȥ: 'Z', // LATIN CAPITAL LETTER Z WITH HOOK
+ Ẕ: 'Z', // LATIN CAPITAL LETTER Z WITH LINE BELOW
+ Ƶ: 'Z', // LATIN CAPITAL LETTER Z WITH STROKE
+ IJ: 'IJ', // LATIN CAPITAL LIGATURE IJ
+ Œ: 'OE', // LATIN CAPITAL LIGATURE OE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN CROSS' (✝)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN EPIGRAPHIC LETTER ARCHAIC M' (ꟿ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN EPIGRAPHIC LETTER I LONGA' (ꟾ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN EPIGRAPHIC LETTER INVERTED M' (ꟽ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN EPIGRAPHIC LETTER REVERSED F' (ꟻ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN EPIGRAPHIC LETTER REVERSED P' (ꟼ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER AIN' (ᴥ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER ALVEOLAR CLICK' (ǂ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER BIDENTAL PERCUSSIVE' (ʭ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER BILABIAL CLICK' (ʘ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER BILABIAL PERCUSSIVE' (ʬ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER DENTAL CLICK' (ǀ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER GLOTTAL STOP' (ʔ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER GLOTTAL STOP WITH STROKE' (ʡ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER INVERTED GLOTTAL STOP' (ʖ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE' (ƾ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER LATERAL CLICK' (ǁ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER PHARYNGEAL VOICED FRICATIVE' (ʕ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER RETROFLEX CLICK' (ǃ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER REVERSED ESH LOOP' (ƪ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE' (ʢ)
+ ᴀ: 'A', // LATIN LETTER SMALL CAPITAL A
+ ᴁ: 'AE', // LATIN LETTER SMALL CAPITAL AE
+ ʙ: 'B', // LATIN LETTER SMALL CAPITAL B
+ ᴃ: 'B', // LATIN LETTER SMALL CAPITAL BARRED B
+ ᴄ: 'C', // LATIN LETTER SMALL CAPITAL C
+ ᴅ: 'D', // LATIN LETTER SMALL CAPITAL D
+ ᴇ: 'E', // LATIN LETTER SMALL CAPITAL E
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER SMALL CAPITAL ETH' (ᴆ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER SMALL CAPITAL EZH' (ᴣ)
+ ꜰ: 'F', // LATIN LETTER SMALL CAPITAL F
+ ɢ: 'G', // LATIN LETTER SMALL CAPITAL G
+ ʛ: 'G', // LATIN LETTER SMALL CAPITAL G WITH HOOK
+ ʜ: 'H', // LATIN LETTER SMALL CAPITAL H
+ ɪ: 'I', // LATIN LETTER SMALL CAPITAL I
+ ʁ: 'R', // LATIN LETTER SMALL CAPITAL INVERTED R
+ ᴊ: 'J', // LATIN LETTER SMALL CAPITAL J
+ ᴋ: 'K', // LATIN LETTER SMALL CAPITAL K
+ ʟ: 'L', // LATIN LETTER SMALL CAPITAL L
+ ᴌ: 'L', // LATIN LETTER SMALL CAPITAL L WITH STROKE
+ ᴍ: 'M', // LATIN LETTER SMALL CAPITAL M
+ ɴ: 'N', // LATIN LETTER SMALL CAPITAL N
+ ᴏ: 'O', // LATIN LETTER SMALL CAPITAL O
+ ɶ: 'OE', // LATIN LETTER SMALL CAPITAL OE
+ ᴐ: 'O', // LATIN LETTER SMALL CAPITAL OPEN O
+ ᴕ: 'OU', // LATIN LETTER SMALL CAPITAL OU
+ ᴘ: 'P', // LATIN LETTER SMALL CAPITAL P
+ ʀ: 'R', // LATIN LETTER SMALL CAPITAL R
+ ᴎ: 'N', // LATIN LETTER SMALL CAPITAL REVERSED N
+ ᴙ: 'R', // LATIN LETTER SMALL CAPITAL REVERSED R
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER SMALL CAPITAL RUM' (ꝶ)
+ ꜱ: 'S', // LATIN LETTER SMALL CAPITAL S
+ ᴛ: 'T', // LATIN LETTER SMALL CAPITAL T
+ ⱻ: 'E', // LATIN LETTER SMALL CAPITAL TURNED E
+ ᴚ: 'R', // LATIN LETTER SMALL CAPITAL TURNED R
+ ᴜ: 'U', // LATIN LETTER SMALL CAPITAL U
+ ᴠ: 'V', // LATIN LETTER SMALL CAPITAL V
+ ᴡ: 'W', // LATIN LETTER SMALL CAPITAL W
+ ʏ: 'Y', // LATIN LETTER SMALL CAPITAL Y
+ ᴢ: 'Z', // LATIN LETTER SMALL CAPITAL Z
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER STRETCHED C' (ʗ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER TWO WITH STROKE' (ƻ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER VOICED LARYNGEAL SPIRANT' (ᴤ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER WYNN' (ƿ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN LETTER YR' (Ʀ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL CAPITAL LETTER I WITH STROKE' (ᵻ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL CAPITAL LETTER U WITH STROKE' (ᵾ)
+ á: 'a', // LATIN SMALL LETTER A WITH ACUTE
+ ă: 'a', // LATIN SMALL LETTER A WITH BREVE
+ ắ: 'a', // LATIN SMALL LETTER A WITH BREVE AND ACUTE
+ ặ: 'a', // LATIN SMALL LETTER A WITH BREVE AND DOT BELOW
+ ằ: 'a', // LATIN SMALL LETTER A WITH BREVE AND GRAVE
+ ẳ: 'a', // LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE
+ ẵ: 'a', // LATIN SMALL LETTER A WITH BREVE AND TILDE
+ ǎ: 'a', // LATIN SMALL LETTER A WITH CARON
+ â: 'a', // LATIN SMALL LETTER A WITH CIRCUMFLEX
+ ấ: 'a', // LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
+ ậ: 'a', // LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+ ầ: 'a', // LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE
+ ẩ: 'a', // LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+ ẫ: 'a', // LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE
+ ä: 'a', // LATIN SMALL LETTER A WITH DIAERESIS
+ ǟ: 'a', // LATIN SMALL LETTER A WITH DIAERESIS AND MACRON
+ ȧ: 'a', // LATIN SMALL LETTER A WITH DOT ABOVE
+ ǡ: 'a', // LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON
+ ạ: 'a', // LATIN SMALL LETTER A WITH DOT BELOW
+ ȁ: 'a', // LATIN SMALL LETTER A WITH DOUBLE GRAVE
+ à: 'a', // LATIN SMALL LETTER A WITH GRAVE
+ ả: 'a', // LATIN SMALL LETTER A WITH HOOK ABOVE
+ ȃ: 'a', // LATIN SMALL LETTER A WITH INVERTED BREVE
+ ā: 'a', // LATIN SMALL LETTER A WITH MACRON
+ ą: 'a', // LATIN SMALL LETTER A WITH OGONEK
+ ᶏ: 'a', // LATIN SMALL LETTER A WITH RETROFLEX HOOK
+ ẚ: 'a', // LATIN SMALL LETTER A WITH RIGHT HALF RING
+ å: 'a', // LATIN SMALL LETTER A WITH RING ABOVE
+ ǻ: 'a', // LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE
+ ḁ: 'a', // LATIN SMALL LETTER A WITH RING BELOW
+ ⱥ: 'a', // LATIN SMALL LETTER A WITH STROKE
+ ã: 'a', // LATIN SMALL LETTER A WITH TILDE
+ ꜳ: 'aa', // LATIN SMALL LETTER AA
+ æ: 'ae', // LATIN SMALL LETTER AE
+ ǽ: 'ae', // LATIN SMALL LETTER AE WITH ACUTE
+ ǣ: 'ae', // LATIN SMALL LETTER AE WITH MACRON
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER ALPHA' (ɑ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK' (ᶐ)
+ ꜵ: 'ao', // LATIN SMALL LETTER AO
+ ꜷ: 'au', // LATIN SMALL LETTER AU
+ ꜹ: 'av', // LATIN SMALL LETTER AV
+ ꜻ: 'av', // LATIN SMALL LETTER AV WITH HORIZONTAL BAR
+ ꜽ: 'ay', // LATIN SMALL LETTER AY
+ ḃ: 'b', // LATIN SMALL LETTER B WITH DOT ABOVE
+ ḅ: 'b', // LATIN SMALL LETTER B WITH DOT BELOW
+ ɓ: 'b', // LATIN SMALL LETTER B WITH HOOK
+ ḇ: 'b', // LATIN SMALL LETTER B WITH LINE BELOW
+ ᵬ: 'b', // LATIN SMALL LETTER B WITH MIDDLE TILDE
+ ᶀ: 'b', // LATIN SMALL LETTER B WITH PALATAL HOOK
+ ƀ: 'b', // LATIN SMALL LETTER B WITH STROKE
+ ƃ: 'b', // LATIN SMALL LETTER B WITH TOPBAR
+ ɵ: 'o', // LATIN SMALL LETTER BARRED O
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER BOTTOM HALF O' (ᴗ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER BROKEN L' (ꝇ)
+ ć: 'c', // LATIN SMALL LETTER C WITH ACUTE
+ č: 'c', // LATIN SMALL LETTER C WITH CARON
+ ç: 'c', // LATIN SMALL LETTER C WITH CEDILLA
+ ḉ: 'c', // LATIN SMALL LETTER C WITH CEDILLA AND ACUTE
+ ĉ: 'c', // LATIN SMALL LETTER C WITH CIRCUMFLEX
+ ɕ: 'c', // LATIN SMALL LETTER C WITH CURL
+ ċ: 'c', // LATIN SMALL LETTER C WITH DOT ABOVE
+ ƈ: 'c', // LATIN SMALL LETTER C WITH HOOK
+ ȼ: 'c', // LATIN SMALL LETTER C WITH STROKE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER CLOSED OMEGA' (ɷ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER CLOSED OPEN E' (ʚ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER CLOSED REVERSED OPEN E' (ɞ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER CON' (ꝯ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER CUATRILLO' (ꜭ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER CUATRILLO WITH COMMA' (ꜯ)
+ ď: 'd', // LATIN SMALL LETTER D WITH CARON
+ ḑ: 'd', // LATIN SMALL LETTER D WITH CEDILLA
+ ḓ: 'd', // LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW
+ ȡ: 'd', // LATIN SMALL LETTER D WITH CURL
+ ḋ: 'd', // LATIN SMALL LETTER D WITH DOT ABOVE
+ ḍ: 'd', // LATIN SMALL LETTER D WITH DOT BELOW
+ ɗ: 'd', // LATIN SMALL LETTER D WITH HOOK
+ ᶑ: 'd', // LATIN SMALL LETTER D WITH HOOK AND TAIL
+ ḏ: 'd', // LATIN SMALL LETTER D WITH LINE BELOW
+ ᵭ: 'd', // LATIN SMALL LETTER D WITH MIDDLE TILDE
+ ᶁ: 'd', // LATIN SMALL LETTER D WITH PALATAL HOOK
+ đ: 'd', // LATIN SMALL LETTER D WITH STROKE
+ ɖ: 'd', // LATIN SMALL LETTER D WITH TAIL
+ ƌ: 'd', // LATIN SMALL LETTER D WITH TOPBAR
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER DB DIGRAPH' (ȸ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER DELTA' (ẟ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER DEZH DIGRAPH' (ʤ)
+ ı: 'i', // LATIN SMALL LETTER DOTLESS I
+ ȷ: 'j', // LATIN SMALL LETTER DOTLESS J
+ ɟ: 'j', // LATIN SMALL LETTER DOTLESS J WITH STROKE
+ ʄ: 'j', // LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER DUM' (ꝱ)
+ dz: 'dz', // LATIN SMALL LETTER DZ
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER DZ DIGRAPH' (ʣ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER DZ DIGRAPH WITH CURL' (ʥ)
+ dž: 'dz', // LATIN SMALL LETTER DZ WITH CARON
+ é: 'e', // LATIN SMALL LETTER E WITH ACUTE
+ ĕ: 'e', // LATIN SMALL LETTER E WITH BREVE
+ ě: 'e', // LATIN SMALL LETTER E WITH CARON
+ ȩ: 'e', // LATIN SMALL LETTER E WITH CEDILLA
+ ḝ: 'e', // LATIN SMALL LETTER E WITH CEDILLA AND BREVE
+ ê: 'e', // LATIN SMALL LETTER E WITH CIRCUMFLEX
+ ế: 'e', // LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE
+ ệ: 'e', // LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+ ề: 'e', // LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE
+ ể: 'e', // LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+ ễ: 'e', // LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE
+ ḙ: 'e', // LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW
+ ë: 'e', // LATIN SMALL LETTER E WITH DIAERESIS
+ ė: 'e', // LATIN SMALL LETTER E WITH DOT ABOVE
+ ẹ: 'e', // LATIN SMALL LETTER E WITH DOT BELOW
+ ȅ: 'e', // LATIN SMALL LETTER E WITH DOUBLE GRAVE
+ è: 'e', // LATIN SMALL LETTER E WITH GRAVE
+ ẻ: 'e', // LATIN SMALL LETTER E WITH HOOK ABOVE
+ ȇ: 'e', // LATIN SMALL LETTER E WITH INVERTED BREVE
+ ē: 'e', // LATIN SMALL LETTER E WITH MACRON
+ ḗ: 'e', // LATIN SMALL LETTER E WITH MACRON AND ACUTE
+ ḕ: 'e', // LATIN SMALL LETTER E WITH MACRON AND GRAVE
+ ⱸ: 'e', // LATIN SMALL LETTER E WITH NOTCH
+ ę: 'e', // LATIN SMALL LETTER E WITH OGONEK
+ ᶒ: 'e', // LATIN SMALL LETTER E WITH RETROFLEX HOOK
+ ɇ: 'e', // LATIN SMALL LETTER E WITH STROKE
+ ẽ: 'e', // LATIN SMALL LETTER E WITH TILDE
+ ḛ: 'e', // LATIN SMALL LETTER E WITH TILDE BELOW
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER EGYPTOLOGICAL AIN' (ꜥ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER EGYPTOLOGICAL ALEF' (ꜣ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER ENG' (ŋ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER ESH' (ʃ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER ESH WITH CURL' (ʆ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER ESH WITH PALATAL HOOK' (ᶋ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER ESH WITH RETROFLEX HOOK' (ᶘ)
+ ꝫ: 'et', // LATIN SMALL LETTER ET
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER ETH' (ð)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER EZH' (ʒ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER EZH REVERSED' (ƹ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER EZH WITH CARON' (ǯ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER EZH WITH CURL' (ʓ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER EZH WITH RETROFLEX HOOK' (ᶚ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER EZH WITH TAIL' (ƺ)
+ ḟ: 'f', // LATIN SMALL LETTER F WITH DOT ABOVE
+ ƒ: 'f', // LATIN SMALL LETTER F WITH HOOK
+ ᵮ: 'f', // LATIN SMALL LETTER F WITH MIDDLE TILDE
+ ᶂ: 'f', // LATIN SMALL LETTER F WITH PALATAL HOOK
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER FENG DIGRAPH' (ʩ)
+ ǵ: 'g', // LATIN SMALL LETTER G WITH ACUTE
+ ğ: 'g', // LATIN SMALL LETTER G WITH BREVE
+ ǧ: 'g', // LATIN SMALL LETTER G WITH CARON
+ ģ: 'g', // LATIN SMALL LETTER G WITH CEDILLA
+ ĝ: 'g', // LATIN SMALL LETTER G WITH CIRCUMFLEX
+ ġ: 'g', // LATIN SMALL LETTER G WITH DOT ABOVE
+ ɠ: 'g', // LATIN SMALL LETTER G WITH HOOK
+ ḡ: 'g', // LATIN SMALL LETTER G WITH MACRON
+ ᶃ: 'g', // LATIN SMALL LETTER G WITH PALATAL HOOK
+ ǥ: 'g', // LATIN SMALL LETTER G WITH STROKE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER GAMMA' (ɣ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER GLOTTAL STOP' (ɂ)
+ ḫ: 'h', // LATIN SMALL LETTER H WITH BREVE BELOW
+ ȟ: 'h', // LATIN SMALL LETTER H WITH CARON
+ ḩ: 'h', // LATIN SMALL LETTER H WITH CEDILLA
+ ĥ: 'h', // LATIN SMALL LETTER H WITH CIRCUMFLEX
+ ⱨ: 'h', // LATIN SMALL LETTER H WITH DESCENDER
+ ḧ: 'h', // LATIN SMALL LETTER H WITH DIAERESIS
+ ḣ: 'h', // LATIN SMALL LETTER H WITH DOT ABOVE
+ ḥ: 'h', // LATIN SMALL LETTER H WITH DOT BELOW
+ ɦ: 'h', // LATIN SMALL LETTER H WITH HOOK
+ ẖ: 'h', // LATIN SMALL LETTER H WITH LINE BELOW
+ ħ: 'h', // LATIN SMALL LETTER H WITH STROKE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER HALF H' (ⱶ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER HENG' (ꜧ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER HENG WITH HOOK' (ɧ)
+ ƕ: 'hv', // LATIN SMALL LETTER HV
+ í: 'i', // LATIN SMALL LETTER I WITH ACUTE
+ ĭ: 'i', // LATIN SMALL LETTER I WITH BREVE
+ ǐ: 'i', // LATIN SMALL LETTER I WITH CARON
+ î: 'i', // LATIN SMALL LETTER I WITH CIRCUMFLEX
+ ï: 'i', // LATIN SMALL LETTER I WITH DIAERESIS
+ ḯ: 'i', // LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE
+ ị: 'i', // LATIN SMALL LETTER I WITH DOT BELOW
+ ȉ: 'i', // LATIN SMALL LETTER I WITH DOUBLE GRAVE
+ ì: 'i', // LATIN SMALL LETTER I WITH GRAVE
+ ỉ: 'i', // LATIN SMALL LETTER I WITH HOOK ABOVE
+ ȋ: 'i', // LATIN SMALL LETTER I WITH INVERTED BREVE
+ ī: 'i', // LATIN SMALL LETTER I WITH MACRON
+ į: 'i', // LATIN SMALL LETTER I WITH OGONEK
+ ᶖ: 'i', // LATIN SMALL LETTER I WITH RETROFLEX HOOK
+ ɨ: 'i', // LATIN SMALL LETTER I WITH STROKE
+ ĩ: 'i', // LATIN SMALL LETTER I WITH TILDE
+ ḭ: 'i', // LATIN SMALL LETTER I WITH TILDE BELOW
+ ꝺ: 'd', // LATIN SMALL LETTER INSULAR D
+ ꝼ: 'f', // LATIN SMALL LETTER INSULAR F
+ ᵹ: 'g', // LATIN SMALL LETTER INSULAR G
+ ꞃ: 'r', // LATIN SMALL LETTER INSULAR R
+ ꞅ: 's', // LATIN SMALL LETTER INSULAR S
+ ꞇ: 't', // LATIN SMALL LETTER INSULAR T
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER IOTA' (ɩ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER IOTA WITH STROKE' (ᵼ)
+ ꝭ: 'is', // LATIN SMALL LETTER IS
+ ǰ: 'j', // LATIN SMALL LETTER J WITH CARON
+ ĵ: 'j', // LATIN SMALL LETTER J WITH CIRCUMFLEX
+ ʝ: 'j', // LATIN SMALL LETTER J WITH CROSSED-TAIL
+ ɉ: 'j', // LATIN SMALL LETTER J WITH STROKE
+ ḱ: 'k', // LATIN SMALL LETTER K WITH ACUTE
+ ǩ: 'k', // LATIN SMALL LETTER K WITH CARON
+ ķ: 'k', // LATIN SMALL LETTER K WITH CEDILLA
+ ⱪ: 'k', // LATIN SMALL LETTER K WITH DESCENDER
+ ꝃ: 'k', // LATIN SMALL LETTER K WITH DIAGONAL STROKE
+ ḳ: 'k', // LATIN SMALL LETTER K WITH DOT BELOW
+ ƙ: 'k', // LATIN SMALL LETTER K WITH HOOK
+ ḵ: 'k', // LATIN SMALL LETTER K WITH LINE BELOW
+ ᶄ: 'k', // LATIN SMALL LETTER K WITH PALATAL HOOK
+ ꝁ: 'k', // LATIN SMALL LETTER K WITH STROKE
+ ꝅ: 'k', // LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER KRA' (ĸ)
+ ĺ: 'l', // LATIN SMALL LETTER L WITH ACUTE
+ ƚ: 'l', // LATIN SMALL LETTER L WITH BAR
+ ɬ: 'l', // LATIN SMALL LETTER L WITH BELT
+ ľ: 'l', // LATIN SMALL LETTER L WITH CARON
+ ļ: 'l', // LATIN SMALL LETTER L WITH CEDILLA
+ ḽ: 'l', // LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW
+ ȴ: 'l', // LATIN SMALL LETTER L WITH CURL
+ ḷ: 'l', // LATIN SMALL LETTER L WITH DOT BELOW
+ ḹ: 'l', // LATIN SMALL LETTER L WITH DOT BELOW AND MACRON
+ ⱡ: 'l', // LATIN SMALL LETTER L WITH DOUBLE BAR
+ ꝉ: 'l', // LATIN SMALL LETTER L WITH HIGH STROKE
+ ḻ: 'l', // LATIN SMALL LETTER L WITH LINE BELOW
+ ŀ: 'l', // LATIN SMALL LETTER L WITH MIDDLE DOT
+ ɫ: 'l', // LATIN SMALL LETTER L WITH MIDDLE TILDE
+ ᶅ: 'l', // LATIN SMALL LETTER L WITH PALATAL HOOK
+ ɭ: 'l', // LATIN SMALL LETTER L WITH RETROFLEX HOOK
+ ł: 'l', // LATIN SMALL LETTER L WITH STROKE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER LAMBDA WITH STROKE' (ƛ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER LEZH' (ɮ)
+ lj: 'lj', // LATIN SMALL LETTER LJ
+ ſ: 's', // LATIN SMALL LETTER LONG S
+ ẜ: 's', // LATIN SMALL LETTER LONG S WITH DIAGONAL STROKE
+ ẛ: 's', // LATIN SMALL LETTER LONG S WITH DOT ABOVE
+ ẝ: 's', // LATIN SMALL LETTER LONG S WITH HIGH STROKE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER LS DIGRAPH' (ʪ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER LUM' (ꝲ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER LZ DIGRAPH' (ʫ)
+ ḿ: 'm', // LATIN SMALL LETTER M WITH ACUTE
+ ṁ: 'm', // LATIN SMALL LETTER M WITH DOT ABOVE
+ ṃ: 'm', // LATIN SMALL LETTER M WITH DOT BELOW
+ ɱ: 'm', // LATIN SMALL LETTER M WITH HOOK
+ ᵯ: 'm', // LATIN SMALL LETTER M WITH MIDDLE TILDE
+ ᶆ: 'm', // LATIN SMALL LETTER M WITH PALATAL HOOK
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER MIDDLE-WELSH LL' (ỻ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER MIDDLE-WELSH V' (ỽ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER MUM' (ꝳ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER N PRECEDED BY APOSTROPHE' (ʼn)
+ ń: 'n', // LATIN SMALL LETTER N WITH ACUTE
+ ň: 'n', // LATIN SMALL LETTER N WITH CARON
+ ņ: 'n', // LATIN SMALL LETTER N WITH CEDILLA
+ ṋ: 'n', // LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW
+ ȵ: 'n', // LATIN SMALL LETTER N WITH CURL
+ ṅ: 'n', // LATIN SMALL LETTER N WITH DOT ABOVE
+ ṇ: 'n', // LATIN SMALL LETTER N WITH DOT BELOW
+ ǹ: 'n', // LATIN SMALL LETTER N WITH GRAVE
+ ɲ: 'n', // LATIN SMALL LETTER N WITH LEFT HOOK
+ ṉ: 'n', // LATIN SMALL LETTER N WITH LINE BELOW
+ ƞ: 'n', // LATIN SMALL LETTER N WITH LONG RIGHT LEG
+ ᵰ: 'n', // LATIN SMALL LETTER N WITH MIDDLE TILDE
+ ᶇ: 'n', // LATIN SMALL LETTER N WITH PALATAL HOOK
+ ɳ: 'n', // LATIN SMALL LETTER N WITH RETROFLEX HOOK
+ ñ: 'n', // LATIN SMALL LETTER N WITH TILDE
+ nj: 'nj', // LATIN SMALL LETTER NJ
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER NUM' (ꝴ)
+ ó: 'o', // LATIN SMALL LETTER O WITH ACUTE
+ ŏ: 'o', // LATIN SMALL LETTER O WITH BREVE
+ ǒ: 'o', // LATIN SMALL LETTER O WITH CARON
+ ô: 'o', // LATIN SMALL LETTER O WITH CIRCUMFLEX
+ ố: 'o', // LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE
+ ộ: 'o', // LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+ ồ: 'o', // LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE
+ ổ: 'o', // LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+ ỗ: 'o', // LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE
+ ö: 'o', // LATIN SMALL LETTER O WITH DIAERESIS
+ ȫ: 'o', // LATIN SMALL LETTER O WITH DIAERESIS AND MACRON
+ ȯ: 'o', // LATIN SMALL LETTER O WITH DOT ABOVE
+ ȱ: 'o', // LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON
+ ọ: 'o', // LATIN SMALL LETTER O WITH DOT BELOW
+ ő: 'o', // LATIN SMALL LETTER O WITH DOUBLE ACUTE
+ ȍ: 'o', // LATIN SMALL LETTER O WITH DOUBLE GRAVE
+ ò: 'o', // LATIN SMALL LETTER O WITH GRAVE
+ ỏ: 'o', // LATIN SMALL LETTER O WITH HOOK ABOVE
+ ơ: 'o', // LATIN SMALL LETTER O WITH HORN
+ ớ: 'o', // LATIN SMALL LETTER O WITH HORN AND ACUTE
+ ợ: 'o', // LATIN SMALL LETTER O WITH HORN AND DOT BELOW
+ ờ: 'o', // LATIN SMALL LETTER O WITH HORN AND GRAVE
+ ở: 'o', // LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE
+ ỡ: 'o', // LATIN SMALL LETTER O WITH HORN AND TILDE
+ ȏ: 'o', // LATIN SMALL LETTER O WITH INVERTED BREVE
+ ꝋ: 'o', // LATIN SMALL LETTER O WITH LONG STROKE OVERLAY
+ ꝍ: 'o', // LATIN SMALL LETTER O WITH LOOP
+ ⱺ: 'o', // LATIN SMALL LETTER O WITH LOW RING INSIDE
+ ō: 'o', // LATIN SMALL LETTER O WITH MACRON
+ ṓ: 'o', // LATIN SMALL LETTER O WITH MACRON AND ACUTE
+ ṑ: 'o', // LATIN SMALL LETTER O WITH MACRON AND GRAVE
+ ǫ: 'o', // LATIN SMALL LETTER O WITH OGONEK
+ ǭ: 'o', // LATIN SMALL LETTER O WITH OGONEK AND MACRON
+ ø: 'o', // LATIN SMALL LETTER O WITH STROKE
+ ǿ: 'o', // LATIN SMALL LETTER O WITH STROKE AND ACUTE
+ õ: 'o', // LATIN SMALL LETTER O WITH TILDE
+ ṍ: 'o', // LATIN SMALL LETTER O WITH TILDE AND ACUTE
+ ṏ: 'o', // LATIN SMALL LETTER O WITH TILDE AND DIAERESIS
+ ȭ: 'o', // LATIN SMALL LETTER O WITH TILDE AND MACRON
+ ƣ: 'oi', // LATIN SMALL LETTER OI
+ ꝏ: 'oo', // LATIN SMALL LETTER OO
+ ɛ: 'e', // LATIN SMALL LETTER OPEN E
+ ᶓ: 'e', // LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK
+ ɔ: 'o', // LATIN SMALL LETTER OPEN O
+ ᶗ: 'o', // LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK
+ ȣ: 'ou', // LATIN SMALL LETTER OU
+ ṕ: 'p', // LATIN SMALL LETTER P WITH ACUTE
+ ṗ: 'p', // LATIN SMALL LETTER P WITH DOT ABOVE
+ ꝓ: 'p', // LATIN SMALL LETTER P WITH FLOURISH
+ ƥ: 'p', // LATIN SMALL LETTER P WITH HOOK
+ ᵱ: 'p', // LATIN SMALL LETTER P WITH MIDDLE TILDE
+ ᶈ: 'p', // LATIN SMALL LETTER P WITH PALATAL HOOK
+ ꝕ: 'p', // LATIN SMALL LETTER P WITH SQUIRREL TAIL
+ ᵽ: 'p', // LATIN SMALL LETTER P WITH STROKE
+ ꝑ: 'p', // LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER PHI' (ɸ)
+ ꝙ: 'q', // LATIN SMALL LETTER Q WITH DIAGONAL STROKE
+ ʠ: 'q', // LATIN SMALL LETTER Q WITH HOOK
+ ɋ: 'q', // LATIN SMALL LETTER Q WITH HOOK TAIL
+ ꝗ: 'q', // LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER QP DIGRAPH' (ȹ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER R ROTUNDA' (ꝛ)
+ ŕ: 'r', // LATIN SMALL LETTER R WITH ACUTE
+ ř: 'r', // LATIN SMALL LETTER R WITH CARON
+ ŗ: 'r', // LATIN SMALL LETTER R WITH CEDILLA
+ ṙ: 'r', // LATIN SMALL LETTER R WITH DOT ABOVE
+ ṛ: 'r', // LATIN SMALL LETTER R WITH DOT BELOW
+ ṝ: 'r', // LATIN SMALL LETTER R WITH DOT BELOW AND MACRON
+ ȑ: 'r', // LATIN SMALL LETTER R WITH DOUBLE GRAVE
+ ɾ: 'r', // LATIN SMALL LETTER R WITH FISHHOOK
+ ᵳ: 'r', // LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE
+ ȓ: 'r', // LATIN SMALL LETTER R WITH INVERTED BREVE
+ ṟ: 'r', // LATIN SMALL LETTER R WITH LINE BELOW
+ ɼ: 'r', // LATIN SMALL LETTER R WITH LONG LEG
+ ᵲ: 'r', // LATIN SMALL LETTER R WITH MIDDLE TILDE
+ ᶉ: 'r', // LATIN SMALL LETTER R WITH PALATAL HOOK
+ ɍ: 'r', // LATIN SMALL LETTER R WITH STROKE
+ ɽ: 'r', // LATIN SMALL LETTER R WITH TAIL
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER RAMS HORN' (ɤ)
+ ↄ: 'c', // LATIN SMALL LETTER REVERSED C
+ ꜿ: 'c', // LATIN SMALL LETTER REVERSED C WITH DOT
+ ɘ: 'e', // LATIN SMALL LETTER REVERSED E
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER REVERSED OPEN E' (ɜ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER REVERSED OPEN E WITH HOOK' (ɝ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK' (ᶔ)
+ ɿ: 'r', // LATIN SMALL LETTER REVERSED R WITH FISHHOOK
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER RUM' (ꝵ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER RUM ROTUNDA' (ꝝ)
+ ś: 's', // LATIN SMALL LETTER S WITH ACUTE
+ ṥ: 's', // LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE
+ š: 's', // LATIN SMALL LETTER S WITH CARON
+ ṧ: 's', // LATIN SMALL LETTER S WITH CARON AND DOT ABOVE
+ ş: 's', // LATIN SMALL LETTER S WITH CEDILLA
+ ŝ: 's', // LATIN SMALL LETTER S WITH CIRCUMFLEX
+ ș: 's', // LATIN SMALL LETTER S WITH COMMA BELOW
+ ṡ: 's', // LATIN SMALL LETTER S WITH DOT ABOVE
+ ṣ: 's', // LATIN SMALL LETTER S WITH DOT BELOW
+ ṩ: 's', // LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE
+ ʂ: 's', // LATIN SMALL LETTER S WITH HOOK
+ ᵴ: 's', // LATIN SMALL LETTER S WITH MIDDLE TILDE
+ ᶊ: 's', // LATIN SMALL LETTER S WITH PALATAL HOOK
+ ȿ: 's', // LATIN SMALL LETTER S WITH SWASH TAIL
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER SALTILLO' (ꞌ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER SCHWA' (ə)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER SCHWA WITH HOOK' (ɚ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK' (ᶕ)
+ ɡ: 'g', // LATIN SMALL LETTER SCRIPT G
+ ß: 'ss', // LATIN SMALL LETTER SHARP S
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER SIDEWAYS DIAERESIZED U' (ᴞ)
+ ᴑ: 'o', // LATIN SMALL LETTER SIDEWAYS O
+ ᴓ: 'o', // LATIN SMALL LETTER SIDEWAYS O WITH STROKE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER SIDEWAYS OPEN O' (ᴒ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER SIDEWAYS TURNED M' (ᴟ)
+ ᴝ: 'u', // LATIN SMALL LETTER SIDEWAYS U
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER SQUAT REVERSED ESH' (ʅ)
+ ť: 't', // LATIN SMALL LETTER T WITH CARON
+ ţ: 't', // LATIN SMALL LETTER T WITH CEDILLA
+ ṱ: 't', // LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW
+ ț: 't', // LATIN SMALL LETTER T WITH COMMA BELOW
+ ȶ: 't', // LATIN SMALL LETTER T WITH CURL
+ ẗ: 't', // LATIN SMALL LETTER T WITH DIAERESIS
+ ⱦ: 't', // LATIN SMALL LETTER T WITH DIAGONAL STROKE
+ ṫ: 't', // LATIN SMALL LETTER T WITH DOT ABOVE
+ ṭ: 't', // LATIN SMALL LETTER T WITH DOT BELOW
+ ƭ: 't', // LATIN SMALL LETTER T WITH HOOK
+ ṯ: 't', // LATIN SMALL LETTER T WITH LINE BELOW
+ ᵵ: 't', // LATIN SMALL LETTER T WITH MIDDLE TILDE
+ ƫ: 't', // LATIN SMALL LETTER T WITH PALATAL HOOK
+ ʈ: 't', // LATIN SMALL LETTER T WITH RETROFLEX HOOK
+ ŧ: 't', // LATIN SMALL LETTER T WITH STROKE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TAILLESS PHI' (ⱷ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TC DIGRAPH WITH CURL' (ʨ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TESH DIGRAPH' (ʧ)
+ ᵺ: 'th', // LATIN SMALL LETTER TH WITH STRIKETHROUGH
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER THORN' (þ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER THORN WITH STROKE' (ꝥ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER' (ꝧ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TONE FIVE' (ƽ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TONE SIX' (ƅ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TONE TWO' (ƨ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TOP HALF O' (ᴖ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TRESILLO' (ꜫ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TS DIGRAPH' (ʦ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TUM' (ꝷ)
+ ɐ: 'a', // LATIN SMALL LETTER TURNED A
+ ᴂ: 'ae', // LATIN SMALL LETTER TURNED AE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TURNED ALPHA' (ɒ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TURNED DELTA' (ƍ)
+ ǝ: 'e', // LATIN SMALL LETTER TURNED E
+ ᵷ: 'g', // LATIN SMALL LETTER TURNED G
+ ɥ: 'h', // LATIN SMALL LETTER TURNED H
+ ʮ: 'h', // LATIN SMALL LETTER TURNED H WITH FISHHOOK
+ ʯ: 'h', // LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+ ᴉ: 'i', // LATIN SMALL LETTER TURNED I
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TURNED INSULAR G' (ꝿ)
+ ʞ: 'k', // LATIN SMALL LETTER TURNED K
+ ꞁ: 'l', // LATIN SMALL LETTER TURNED L
+ ɯ: 'm', // LATIN SMALL LETTER TURNED M
+ ɰ: 'm', // LATIN SMALL LETTER TURNED M WITH LONG LEG
+ ᴔ: 'oe', // LATIN SMALL LETTER TURNED OE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER TURNED OPEN E' (ᴈ)
+ ɹ: 'r', // LATIN SMALL LETTER TURNED R
+ ɻ: 'r', // LATIN SMALL LETTER TURNED R WITH HOOK
+ ɺ: 'r', // LATIN SMALL LETTER TURNED R WITH LONG LEG
+ ⱹ: 'r', // LATIN SMALL LETTER TURNED R WITH TAIL
+ ʇ: 't', // LATIN SMALL LETTER TURNED T
+ ʌ: 'v', // LATIN SMALL LETTER TURNED V
+ ʍ: 'w', // LATIN SMALL LETTER TURNED W
+ ʎ: 'y', // LATIN SMALL LETTER TURNED Y
+ ꜩ: 'tz', // LATIN SMALL LETTER TZ
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER U BAR' (ʉ)
+ ú: 'u', // LATIN SMALL LETTER U WITH ACUTE
+ ŭ: 'u', // LATIN SMALL LETTER U WITH BREVE
+ ǔ: 'u', // LATIN SMALL LETTER U WITH CARON
+ û: 'u', // LATIN SMALL LETTER U WITH CIRCUMFLEX
+ ṷ: 'u', // LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW
+ ü: 'u', // LATIN SMALL LETTER U WITH DIAERESIS
+ ǘ: 'u', // LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE
+ ǚ: 'u', // LATIN SMALL LETTER U WITH DIAERESIS AND CARON
+ ǜ: 'u', // LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE
+ ǖ: 'u', // LATIN SMALL LETTER U WITH DIAERESIS AND MACRON
+ ṳ: 'u', // LATIN SMALL LETTER U WITH DIAERESIS BELOW
+ ụ: 'u', // LATIN SMALL LETTER U WITH DOT BELOW
+ ű: 'u', // LATIN SMALL LETTER U WITH DOUBLE ACUTE
+ ȕ: 'u', // LATIN SMALL LETTER U WITH DOUBLE GRAVE
+ ù: 'u', // LATIN SMALL LETTER U WITH GRAVE
+ ủ: 'u', // LATIN SMALL LETTER U WITH HOOK ABOVE
+ ư: 'u', // LATIN SMALL LETTER U WITH HORN
+ ứ: 'u', // LATIN SMALL LETTER U WITH HORN AND ACUTE
+ ự: 'u', // LATIN SMALL LETTER U WITH HORN AND DOT BELOW
+ ừ: 'u', // LATIN SMALL LETTER U WITH HORN AND GRAVE
+ ử: 'u', // LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE
+ ữ: 'u', // LATIN SMALL LETTER U WITH HORN AND TILDE
+ ȗ: 'u', // LATIN SMALL LETTER U WITH INVERTED BREVE
+ ū: 'u', // LATIN SMALL LETTER U WITH MACRON
+ ṻ: 'u', // LATIN SMALL LETTER U WITH MACRON AND DIAERESIS
+ ų: 'u', // LATIN SMALL LETTER U WITH OGONEK
+ ᶙ: 'u', // LATIN SMALL LETTER U WITH RETROFLEX HOOK
+ ů: 'u', // LATIN SMALL LETTER U WITH RING ABOVE
+ ũ: 'u', // LATIN SMALL LETTER U WITH TILDE
+ ṹ: 'u', // LATIN SMALL LETTER U WITH TILDE AND ACUTE
+ ṵ: 'u', // LATIN SMALL LETTER U WITH TILDE BELOW
+ ᵫ: 'ue', // LATIN SMALL LETTER UE
+ ꝸ: 'um', // LATIN SMALL LETTER UM
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER UPSILON' (ʊ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER UPSILON WITH STROKE' (ᵿ)
+ ⱴ: 'v', // LATIN SMALL LETTER V WITH CURL
+ ꝟ: 'v', // LATIN SMALL LETTER V WITH DIAGONAL STROKE
+ ṿ: 'v', // LATIN SMALL LETTER V WITH DOT BELOW
+ ʋ: 'v', // LATIN SMALL LETTER V WITH HOOK
+ ᶌ: 'v', // LATIN SMALL LETTER V WITH PALATAL HOOK
+ ⱱ: 'v', // LATIN SMALL LETTER V WITH RIGHT HOOK
+ ṽ: 'v', // LATIN SMALL LETTER V WITH TILDE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER VEND' (ꝩ)
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER VISIGOTHIC Z' (ꝣ)
+ ꝡ: 'vy', // LATIN SMALL LETTER VY
+ ẃ: 'w', // LATIN SMALL LETTER W WITH ACUTE
+ ŵ: 'w', // LATIN SMALL LETTER W WITH CIRCUMFLEX
+ ẅ: 'w', // LATIN SMALL LETTER W WITH DIAERESIS
+ ẇ: 'w', // LATIN SMALL LETTER W WITH DOT ABOVE
+ ẉ: 'w', // LATIN SMALL LETTER W WITH DOT BELOW
+ ẁ: 'w', // LATIN SMALL LETTER W WITH GRAVE
+ ⱳ: 'w', // LATIN SMALL LETTER W WITH HOOK
+ ẘ: 'w', // LATIN SMALL LETTER W WITH RING ABOVE
+ ẍ: 'x', // LATIN SMALL LETTER X WITH DIAERESIS
+ ẋ: 'x', // LATIN SMALL LETTER X WITH DOT ABOVE
+ ᶍ: 'x', // LATIN SMALL LETTER X WITH PALATAL HOOK
+ ý: 'y', // LATIN SMALL LETTER Y WITH ACUTE
+ ŷ: 'y', // LATIN SMALL LETTER Y WITH CIRCUMFLEX
+ ÿ: 'y', // LATIN SMALL LETTER Y WITH DIAERESIS
+ ẏ: 'y', // LATIN SMALL LETTER Y WITH DOT ABOVE
+ ỵ: 'y', // LATIN SMALL LETTER Y WITH DOT BELOW
+ ỳ: 'y', // LATIN SMALL LETTER Y WITH GRAVE
+ ƴ: 'y', // LATIN SMALL LETTER Y WITH HOOK
+ ỷ: 'y', // LATIN SMALL LETTER Y WITH HOOK ABOVE
+ ỿ: 'y', // LATIN SMALL LETTER Y WITH LOOP
+ ȳ: 'y', // LATIN SMALL LETTER Y WITH MACRON
+ ẙ: 'y', // LATIN SMALL LETTER Y WITH RING ABOVE
+ ɏ: 'y', // LATIN SMALL LETTER Y WITH STROKE
+ ỹ: 'y', // LATIN SMALL LETTER Y WITH TILDE
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LETTER YOGH' (ȝ)
+ ź: 'z', // LATIN SMALL LETTER Z WITH ACUTE
+ ž: 'z', // LATIN SMALL LETTER Z WITH CARON
+ ẑ: 'z', // LATIN SMALL LETTER Z WITH CIRCUMFLEX
+ ʑ: 'z', // LATIN SMALL LETTER Z WITH CURL
+ ⱬ: 'z', // LATIN SMALL LETTER Z WITH DESCENDER
+ ż: 'z', // LATIN SMALL LETTER Z WITH DOT ABOVE
+ ẓ: 'z', // LATIN SMALL LETTER Z WITH DOT BELOW
+ ȥ: 'z', // LATIN SMALL LETTER Z WITH HOOK
+ ẕ: 'z', // LATIN SMALL LETTER Z WITH LINE BELOW
+ ᵶ: 'z', // LATIN SMALL LETTER Z WITH MIDDLE TILDE
+ ᶎ: 'z', // LATIN SMALL LETTER Z WITH PALATAL HOOK
+ ʐ: 'z', // LATIN SMALL LETTER Z WITH RETROFLEX HOOK
+ ƶ: 'z', // LATIN SMALL LETTER Z WITH STROKE
+ ɀ: 'z', // LATIN SMALL LETTER Z WITH SWASH TAIL
+ ff: 'ff', // LATIN SMALL LIGATURE FF
+ ffi: 'ffi', // LATIN SMALL LIGATURE FFI
+ ffl: 'ffl', // LATIN SMALL LIGATURE FFL
+ fi: 'fi', // LATIN SMALL LIGATURE FI
+ fl: 'fl', // LATIN SMALL LIGATURE FL
+ ij: 'ij', // LATIN SMALL LIGATURE IJ
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SMALL LIGATURE LONG S T' (ſt)
+ œ: 'oe', // LATIN SMALL LIGATURE OE
+ st: 'st', // LATIN SMALL LIGATURE ST
+ ₐ: 'a', // LATIN SUBSCRIPT SMALL LETTER A
+ ₑ: 'e', // LATIN SUBSCRIPT SMALL LETTER E
+ ᵢ: 'i', // LATIN SUBSCRIPT SMALL LETTER I
+ ⱼ: 'j', // LATIN SUBSCRIPT SMALL LETTER J
+ ₒ: 'o', // LATIN SUBSCRIPT SMALL LETTER O
+ ᵣ: 'r', // LATIN SUBSCRIPT SMALL LETTER R
+ // CANNOT FIND APPROXIMATION FOR 'LATIN SUBSCRIPT SMALL LETTER SCHWA' (ₔ)
+ ᵤ: 'u', // LATIN SUBSCRIPT SMALL LETTER U
+ ᵥ: 'v', // LATIN SUBSCRIPT SMALL LETTER V
+ ₓ: 'x' // LATIN SUBSCRIPT SMALL LETTER X
+};
+
+export function map(x) {
+ return latinMap[x] || x;
+}
+
+export function latinise(input) {
+ return input.replace(/[^A-Za-z0-9]/g, map);
+}
diff --git a/app/utils/url.js b/app/utils/url.js
index dd684024e..7199ef27e 100644
--- a/app/utils/url.js
+++ b/app/utils/url.js
@@ -1,6 +1,8 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
+import {latinise} from './latinise.js';
+
const ytRegex = /(?:http|https):\/\/(?:www\.|m\.)?(?:(?:youtube\.com\/(?:(?:v\/)|(?:(?:watch|embed\/watch)(?:\/|.*v=))|(?:embed\/)|(?:user\/[^/]+\/u\/[0-9]\/)))|(?:youtu\.be\/))([^#&?]*)/;
const imgRegex = /.+\/(.+\.(?:jpg|gif|bmp|png|jpeg))(?:\?.*)?$/i;
@@ -56,3 +58,20 @@ export function normalizeProtocol(url) {
const protocol = url.substring(0, index);
return protocol.toLowerCase() + url.substring(index);
}
+
+export function getShortenedURL(url = '', getLength = 27) {
+ if (url.length > 35) {
+ const subLength = getLength - 14;
+ return url.substring(0, 10) + '...' + url.substring(url.length - subLength, url.length) + '/';
+ }
+ return url + '/';
+}
+
+export function cleanUpUrlable(input) {
+ var cleaned = latinise(input);
+ cleaned = cleaned.trim().replace(/-/g, ' ').replace(/[^\w\s]/gi, '').toLowerCase().replace(/\s/g, '-');
+ cleaned = cleaned.replace(/-{2,}/, '-');
+ cleaned = cleaned.replace(/^-+/, '');
+ cleaned = cleaned.replace(/-+$/, '');
+ return cleaned;
+}
diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json
index 3c1c5f326..7002c9fe3 100644
--- a/assets/base/i18n/en.json
+++ b/assets/base/i18n/en.json
@@ -1918,6 +1918,7 @@
"mobile.channel_info.delete_failed": "We couldn't delete the channel {displayName}. Please check your connection and try again.",
"mobile.channel_info.privateChannel": "Private Channel",
"mobile.channel_info.publicChannel": "Public Channel",
+ "mobile.channel_info.edit": "Edit Channel",
"mobile.channel_list.alertMessageLeaveChannel": "Are you sure you want to leave the {term} {name}?",
"mobile.channel_list.alertNo": "No",
"mobile.channel_list.alertTitleLeaveChannel": "Leave {term}",
@@ -1954,6 +1955,7 @@
"mobile.components.select_server_view.enterServerUrl": "Enter Server URL",
"mobile.components.select_server_view.proceed": "Proceed",
"mobile.components.select_server_view.siteUrlPlaceholder": "https://mattermost.example.com",
+ "mobile.edit_channel": "Save",
"mobile.create_channel": "Create",
"mobile.create_channel.private": "New Private Channel",
"mobile.create_channel.public": "New Public Channel",
@@ -2061,6 +2063,13 @@
"mobile.post.retry": "Refresh",
"mobile.post_info.add_reaction": "Add Reaction",
"mobile.post_info.copy_post": "Copy Post",
+ "mobile.rename_channel.display_name_required": "Channel name is required",
+ "mobile.rename_channel.display_name_maxLength": "Channel name must be less than {maxLength, number} characters",
+ "mobile.rename_channel.display_name_minLength": "Channel name must be {minLength, number} or more characters",
+ "mobile.rename_channel.name_required": "URL is required",
+ "mobile.rename_channel.name_maxLength": "URL must be less than {maxLength, number} characters",
+ "mobile.rename_channel.name_minLength": "URL must be {minLength, number} or more characters",
+ "mobile.rename_channel.name_lowercase": "URL be lowercase alphanumeric characters",
"mobile.request.invalid_response": "Received invalid response from the server.",
"mobile.retry_message": "Refreshing messages failed. Pull up to try again.",
"mobile.routes.channelInfo": "Info",