Files
mediawiki-extensions-Univer…/lib/jquery.ime/jquery.ime.js
Amir E. Aharoni 6d8bda5553 Update jquery.ime and jquery.uls from upstream
jquery.ime
* Add layouts for Nyanja/Chichewa (ny) and Tumbuka (tum).
* Fix layout name for Bura (bwr)
* Add macron to the Ewe (ee) keyboard
Updating to:
fa2fb33e12

jquery.uls
* Localization updates
Updating to:
5ad9937ac6

Change-Id: Id599d7ce882ae6c2a744a15691a9e56059d7dac9
2022-06-27 13:25:58 +03:00

3162 lines
77 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*! jquery.ime - v0.2.0+20220627
* https://github.com/wikimedia/jquery.ime
* Copyright (c) 2022 Santhosh Thottingal; License: (GPL-2.0-or-later OR MIT) */
( function ( $ ) {
'use strict';
var TextEntryFactory, TextEntry, FormWidgetEntry, ContentEditableEntry,
defaultInputMethod;
/**
* private function for debugging
*
* @param {jQuery} [$obj]
*/
function debug( $obj ) {
if ( window.console && window.console.log ) {
window.console.log( $obj );
}
}
/**
* Just initializes an empty static object.
* Similar to initClass in https://www.mediawiki.org/wiki/OOjs
*
* @param {Function} fn
*/
function initClass( fn ) {
fn.static = fn.static || {};
}
/**
* Inheritance. Uses pattern similar to OOjs (https://www.mediawiki.org/wiki/OOjs).
* Extend prototype and static methods and properties of child constructor from
* a parent constructor.
*
* @param {Function} targetFn
* @param {Function} originFn
*/
function inheritClass( targetFn, originFn ) {
targetFn.parent = originFn;
targetFn.prototype = $.extend( {}, originFn.prototype );
targetFn.prototype.constructor = originFn.constructor;
targetFn.static = $.extend( {}, originFn.static );
}
/**
* IME Class
*
* @class IME
* @constructor
* @param {HTMLElement} element Element on which to listen for events
* @param {TextEntry} textEntry Text entry object to use to get/set text
* @param {Object} [options]
* @param {Function} [options.helpHandler] Called for each input method row in the selector
* @param {Object} [options.helpHandler.imeSelector]
* @param {string} [options.helpHandler.ime] Id of the input method
*/
function IME( element, textEntry, options ) {
this.$element = $( element );
this.textEntry = textEntry;
// This needs to be delayed here since extending language list happens at DOM ready
$.ime.defaults.languages = Object.keys( $.ime.languages );
this.options = $.extend( {}, $.ime.defaults, options );
if ( this.options.imePath ) {
// Set the global IME path from the one specified to the instance
// TODO: remove this functionality and force clients to set the global
// IME path
$.ime.path = this.options.imePath;
}
this.active = false;
this.shifted = false;
this.inputmethod = null;
this.language = null;
this.context = '';
if ( this.options.showSelector ) {
this.options.selectorInside = options.selectorInside !== undefined ?
options.selectorInside :
// eslint-disable-next-line no-jquery/no-class-state
this.$element.hasClass( 'ime-position-inside' );
this.selector = this.$element.imeselector( this.options );
}
this.listen();
}
IME.prototype = {
constructor: IME,
/**
* Listen for events and bind to handlers
*/
listen: function () {
this.$element.on( {
'keypress.ime': this.keypress.bind( this ),
'keyup.ime': this.keyup.bind( this ),
'keydown.ime': this.keydown.bind( this ),
'destroy.ime': this.destroy.bind( this ),
'enable.ime': this.enable.bind( this ),
'disable.ime': this.disable.bind( this )
} );
},
/**
* Return a list of available language codes
*
* @return {string[]} Available language codes
*/
getLanguageCodes: function () {
return $.ime.defaults.languages;
},
/**
* Return the autonym for a language code
*
* @param {string} languageCode The language code
* @return {string|undefined} The autonym, if known
*/
getAutonym: function ( languageCode ) {
var info = $.ime.languages[ languageCode ];
return info && info.autonym;
},
/**
* Return a list of available input method ids for a language
*
* @param {string} languageCode A language code
* @return {string[]} Available input method ids for that language
*/
getInputMethodIds: function ( languageCode ) {
var info = $.ime.languages[ languageCode ];
return ( info && info.inputmethods ) || [];
},
/**
* Return the name of an input method
*
* @param {string} inputMethodId The id of an input method
* @return {string} The input method's name
* @see IME#load
*/
getInputMethodName: function ( inputMethodId ) {
return $.ime.sources[ inputMethodId ].name;
},
/**
* Return a list of input method info { id: ..., name: ... } for a language.
*
* @param {string} languageCode A language code
* @return {Object[]} Info object for each available input method
*/
getInputMethods: function ( languageCode ) {
return this.getInputMethodIds( languageCode ).map( function ( inputMethodId ) {
return {
id: inputMethodId,
name: $.ime.sources[ inputMethodId ].name
};
} );
},
/**
* Transliterate a given string input based on context and input method definition.
* If there are no matching rules defined, returns the original string.
*
* @param {string} input
* @param {string} context
* @param {boolean} altGr whether altGr key is pressed or not
* @return {Object} Transliteration object
* @return {boolean} return.noop Whether to consider input processed or passed through.
* @return {string} return.output The transliterated input or input unmodified.
*/
transliterate: function ( input, context, altGr ) {
var patterns, regex, rule, replacement, i, retval;
if ( altGr ) {
patterns = this.inputmethod.patterns_x || [];
} else {
patterns = this.inputmethod.patterns || [];
}
if ( this.shifted ) {
// if shift is pressed give priority for the patterns_shift
// if exists.
// Example: Shift+space where shift does not alter the keycode
patterns = ( this.inputmethod.patterns_shift || [] )
.concat( patterns );
}
if ( typeof patterns === 'function' ) {
// For backwards compatibility, allow the rule functions to return plain
// string. Determine noop by checking whether input is different from
// output. If the rule function returns object, just return it as-is.
retval = patterns.call( this, input, context );
if ( typeof retval === 'string' ) {
return { noop: input === retval, output: retval };
}
return retval;
}
for ( i = 0; i < patterns.length; i++ ) {
rule = patterns[ i ];
regex = new RegExp( rule[ 0 ] + '$' );
// Last item in the rules.
// It can also be a function, because the replace
// method can have a function as the second argument.
replacement = rule.slice( -1 )[ 0 ];
// Input string match test
if ( regex.test( input ) ) {
// Context test required?
if ( rule.length === 3 ) {
if ( new RegExp( rule[ 1 ] + '$' ).test( context ) ) {
return { noop: false, output: input.replace( regex, replacement ) };
}
} else {
return { noop: false, output: input.replace( regex, replacement ) };
}
}
}
// No matches, return the input
return { noop: true, output: input };
},
keyup: function ( e ) {
if ( e.which === 16 ) { // shift key
this.shifted = false;
}
},
keydown: function ( e ) {
if ( e.which === 16 ) { // shift key
this.shifted = true;
}
},
/**
* Keypress handler
*
* @param {jQuery.Event} e Event
* @return {boolean}
*/
keypress: function ( e ) {
var altGr = false,
c, input, replacement;
if ( !this.active ) {
return true;
}
if ( !this.inputmethod ) {
return true;
}
// handle backspace
if ( e.which === 8 ) {
// Blank the context
this.context = '';
return true;
}
if ( e.altKey || e.altGraphKey ) {
altGr = true;
}
// Don't process ASCII control characters except linefeed,
// as well as anything involving Ctrl, Meta and Alt,
// but do process extended keymaps
if ( ( e.which < 32 && e.which !== 13 && !altGr ) || e.ctrlKey || e.metaKey ) {
// Blank the context
this.context = '';
return true;
}
c = String.fromCharCode( e.which );
// Append the character being typed to the preceding few characters,
// to provide context for the transliteration regexes.
input = this.textEntry.getTextBeforeSelection( this.inputmethod.maxKeyLength );
replacement = this.transliterate( input + c, this.context, altGr );
// Update the context
this.context += c;
if ( this.context.length > this.inputmethod.contextLength ) {
// The buffer is longer than needed, truncate it at the front
this.context = this.context.substring(
this.context.length - this.inputmethod.contextLength
);
}
// Allow rules to explicitly define whether we match something.
// Otherwise we cannot distinguish between no matching rule and
// rule that provides identical output but consumes the event
// to prevent normal behavior. See Udmurt layout which uses
// altgr rules to allow typing the original character.
if ( replacement.noop ) {
return true;
}
this.textEntry.replaceTextAtSelection( input.length, replacement.output );
e.stopPropagation();
return false;
},
/**
* Check whether the input method is active or not
*
* @return {boolean}
*/
isActive: function () {
return this.active;
},
/**
* Disable the input method
*/
disable: function () {
this.active = false;
$.ime.preferences.setIM( 'system' );
},
/**
* Enable the input method
*/
enable: function () {
this.active = true;
},
/**
* Toggle the active state of input method
*/
toggle: function () {
this.active = !this.active;
},
/**
* Destroy the binding of ime to the editable element
*/
destroy: function () {
$( document.body ).off( '.ime' );
this.$element.off( '.ime' ).removeData( 'ime' ).removeData( 'imeselector' );
},
/**
* Get the current input method
*
* @return {string} Current input method id
*/
getIM: function () {
return this.inputmethod;
},
/**
* Set the current input method
*
* @param {string} inputmethodId
* @fires imeLanguageChange
*/
setIM: function ( inputmethodId ) {
this.inputmethod = $.ime.inputmethods[ inputmethodId ];
$.ime.preferences.setIM( inputmethodId );
this.$element.trigger( 'imeMethodChange' );
},
/**
* Set the current Language
*
* @param {string} languageCode
* @fires imeLanguageChange
* @return {boolean}
*/
setLanguage: function ( languageCode ) {
if ( !$.ime.languages[ languageCode ] ) {
debug( 'Language ' + languageCode + ' is not known to jquery.ime.' );
return false;
}
this.language = languageCode;
$.ime.preferences.setLanguage( languageCode );
this.$element.trigger( 'imeLanguageChange' );
return true;
},
/**
* Get current language
*
* @return {string}
*/
getLanguage: function () {
return this.language;
},
/**
* load an input method by given id
*
* @param {string} inputmethodId
* @return {jQuery.Promise}
*/
load: function ( inputmethodId ) {
return $.ime.load( inputmethodId );
}
};
/**
* TextEntry factory
*
* @class TextEntryFactory
* @constructor
*/
TextEntryFactory = function IMETextEntryFactory() {
this.TextEntryClasses = [];
};
/* Inheritance */
initClass( TextEntryFactory );
/* Methods */
/**
* Register a TextEntry class, with priority over previous registrations
*
* @param {TextEntry} TextEntryClass Class to register
*/
TextEntryFactory.prototype.register = function ( TextEntryClass ) {
this.TextEntryClasses.unshift( TextEntryClass );
};
/**
* Wrap an editable element with the appropriate TextEntry class
*
* @param {jQuery} $element The element to wrap
* @return {TextEntry|null} A TextEntry, or null if no match
*/
TextEntryFactory.prototype.wrap = function ( $element ) {
var i, len, TextEntryClass;
// eslint-disable-next-line no-jquery/no-class-state
if ( $element.hasClass( 'noime' ) ) {
return null;
}
for ( i = 0, len = this.TextEntryClasses.length; i < len; i++ ) {
TextEntryClass = this.TextEntryClasses[ i ];
if ( TextEntryClass.static.canWrap( $element ) ) {
return new TextEntryClass( $element );
}
}
return null;
};
/* Initialization */
TextEntryFactory.static.singleton = new TextEntryFactory();
/**
* Generic text entry
*
* @class TextEntry
* @abstract
*/
TextEntry = function IMETextEntry() {
};
/* Inheritance */
initClass( TextEntry );
/* Static methods */
/**
* Test whether can wrap this type of element
*
* @param {jQuery} $element The element to wrap
* @return {boolean} Whether the element can be wrapped
*/
TextEntry.static.canWrap = function () {
return false;
};
/* Abstract methods */
/**
* Get text immediately before the current selection start.
*
* This SHOULD return the empty string for non-collapsed selections.
*
* @param {number} maxLength Maximum number of chars (code units) to return
* @return {string} Up to maxLength of text
*/
TextEntry.prototype.getTextBeforeSelection = null;
/**
* Replace the currently selected text and/or text before the selection
*
* @param {number} precedingCharCount Number of chars before selection to replace
* @param {string} newText Replacement text
*/
TextEntry.prototype.replaceTextAtSelection = null;
/**
* TextEntry class for input/textarea widgets
*
* @class FormWidgetEntry
* @constructor
* @param {jQuery} $element The element to wrap
*/
FormWidgetEntry = function IMEFormWidgetEntry( $element ) {
this.$element = $element;
};
/* Inheritance */
inheritClass( FormWidgetEntry, TextEntry );
/* Static methods */
/**
* @inheritdoc TextEntry
*/
FormWidgetEntry.static.canWrap = function ( $element ) {
return $element.is( 'input:not([type]), input[type=text], input[type=search], textarea' ) &&
!$element.prop( 'readonly' ) &&
!$element.prop( 'disabled' );
};
/* Instance methods */
/**
* @inheritdoc TextEntry
*/
FormWidgetEntry.prototype.getTextBeforeSelection = function ( maxLength ) {
var element = this.$element.get( 0 );
return this.$element.val().substring(
Math.max( 0, element.selectionStart - maxLength ),
element.selectionStart
);
};
/**
* @inheritdoc TextEntry
*/
FormWidgetEntry.prototype.replaceTextAtSelection = function ( precedingCharCount, newText ) {
var element = this.$element.get( 0 ),
start = element.selectionStart,
scrollTop = element.scrollTop;
// Replace the whole text of the text area:
// text before + newText + text after.
// This could be made better if range selection worked on browsers.
// But for complex scripts, browsers place cursor in unexpected places
// and it's not possible to fix cursor programmatically.
// Ref Bug https://bugs.webkit.org/show_bug.cgi?id=66630
element.value = element.value.substring( 0, start - precedingCharCount ) +
newText +
element.value.substring( element.selectionEnd, element.value.length );
// restore scroll
element.scrollTop = scrollTop;
// set selection
element.selectionStart = element.selectionEnd = start - precedingCharCount + newText.length;
};
TextEntryFactory.static.singleton.register( FormWidgetEntry );
/**
* TextEntry class for ContentEditable
*
* @class ContentEditableEntry
* @constructor
* @param {jQuery} $element The element to wrap
*/
ContentEditableEntry = function IMEContentEditableEntry( $element ) {
this.$element = $element;
};
/* Inheritance */
inheritClass( ContentEditableEntry, TextEntry );
/* Static methods */
/**
* @inheritdoc TextEntry
*/
ContentEditableEntry.static.canWrap = function ( $element ) {
return $element.is( '[contenteditable]' );
};
/* Instance methods */
/**
* @inheritdoc TextEntry
*/
ContentEditableEntry.prototype.getTextBeforeSelection = function ( maxLength ) {
var range = this.getSelectedRange();
if ( !range || !range.collapsed || range.startContainer.nodeType !== Node.TEXT_NODE ) {
return '';
}
return range.startContainer.nodeValue.substring(
Math.max( 0, range.startOffset - maxLength ),
range.startOffset
);
};
/**
* @inheritdoc SelectionWrapper
*/
ContentEditableEntry.prototype.replaceTextAtSelection = function (
precedingCharCount,
newText
) {
var textNode, textOffset, newOffset, newRange,
sel = window.getSelection(),
range = this.getSelectedRange();
if ( !range ) {
return;
}
// Trigger any externally registered jQuery compositionstart event listeners.
// TODO: Try node.dispatchEvent( new CompositionEvent(...) ) so listeners not
// registered using jQuery will also get triggered, then fallback gracefully for
// browsers that do not support it.
this.$element.trigger( 'compositionstart' );
if ( !range.collapsed ) {
range.deleteContents();
}
newRange = document.createRange();
if ( range.startContainer.nodeType === Node.TEXT_NODE ) {
// Alter this text node's content and move the cursor
textNode = range.startContainer;
textOffset = range.startOffset;
textNode.nodeValue =
textNode.nodeValue.substr( 0, textOffset - precedingCharCount ) +
newText +
textNode.nodeValue.substr( textOffset );
newOffset = textOffset - precedingCharCount + newText.length;
newRange.setStart( range.startContainer, newOffset );
newRange.setEnd( range.startContainer, newOffset );
} else {
// XXX assert precedingCharCount === 0
// Insert a new text node with the new text
textNode = document.createTextNode( newText );
range.startContainer.insertBefore(
textNode,
range.startContainer.childNodes[ range.startOffset ]
);
newRange.setStart( textNode, textNode.length );
newRange.setEnd( textNode, textNode.length );
}
sel.removeAllRanges();
sel.addRange( newRange );
// Trigger any externally registered jQuery compositionend / input event listeners.
// TODO: Try node.dispatchEvent( new CompositionEvent(...) ) so listeners not
// registered using jQuery will also get triggered, then fallback gracefully for
// browsers that do not support it.
this.$element.trigger( 'compositionend' );
this.$element.trigger( 'input' );
};
/**
* Get the selection range inside the wrapped element, or null
*
* @return {Range|null} The selection range
*/
ContentEditableEntry.prototype.getSelectedRange = function () {
var range,
sel = window.getSelection();
if ( sel.rangeCount === 0 ) {
return null;
}
range = sel.getRangeAt( 0 );
if ( !this.$element[ 0 ].contains( range.commonAncestorContainer ) ) {
return null;
}
return range;
};
TextEntryFactory.static.singleton.register( ContentEditableEntry );
/* Exports */
/**
* jQuery plugin ime
*
* @param {Object} option
* @return {jQuery}
*/
$.fn.ime = function ( option ) {
return this.each( function () {
var data, textEntry,
$this = $( this ),
options = typeof option === 'object' && option;
data = $this.data( 'ime' );
if ( !data ) {
textEntry = TextEntryFactory.static.singleton.wrap( $this );
if ( !textEntry ) {
return;
}
data = new IME( this, textEntry, options );
$this.data( 'ime', data );
}
if ( typeof option === 'string' ) {
data[ option ]();
}
} );
};
$.ime = {};
$.ime.inputmethods = {};
$.ime.sources = {};
$.ime.preferences = {};
$.ime.languages = {};
/**
* @property {string} Relative or absolute path for the rules folder of jquery.ime
*/
$.ime.path = '../';
$.ime.textEntryFactory = TextEntryFactory.static.singleton;
$.ime.TextEntry = TextEntry;
$.ime.inheritClass = inheritClass;
defaultInputMethod = {
contextLength: 0,
maxKeyLength: 1
};
/**
* load an input method by given id
*
* @param {string} inputmethodId
* @return {jQuery.Promise}
*/
$.ime.load = function ( inputmethodId ) {
var dependency,
deferred = $.Deferred();
if ( $.ime.inputmethods[ inputmethodId ] ) {
return deferred.resolve();
}
// Validate the input method id.
if ( !$.ime.sources[ inputmethodId ] ) {
return deferred.reject();
}
dependency = $.ime.sources[ inputmethodId ].depends;
if ( dependency && !$.ime.inputmethods[ dependency ] ) {
$.ime.load( dependency ).done( function () {
$.ime.load( inputmethodId ).done( function () {
deferred.resolve();
} );
} );
return deferred;
}
debug( 'Loading ' + inputmethodId );
deferred = $.ajax( {
url: $.ime.path + $.ime.sources[ inputmethodId ].source,
dataType: 'script',
cache: true
} ).done( function () {
debug( inputmethodId + ' loaded' );
} ).fail( function ( jqxhr, settings, exception ) {
debug( 'Error in loading inputmethod ' + inputmethodId + ' Exception: ' + exception );
} );
return deferred.promise();
};
$.ime.register = function ( inputMethod ) {
$.ime.inputmethods[ inputMethod.id ] = $.extend( {}, defaultInputMethod, inputMethod );
};
/**
* Set the relative/absolute path to rules/ (for loading input methods)
*
* @param {string} path The relative/absolute path in which rules/ lies
*/
$.ime.setPath = function ( path ) {
$.ime.path = path;
};
// default options
$.ime.defaults = {
languages: [], // Languages to be used- by default all languages
helpHandler: null, // Called for each ime option in the menu
showSelector: true,
selectorInside: undefined // If not set will check if '.ime-position-inside' class is preset
};
}( jQuery ) );
( function ( $ ) {
'use strict';
var selectorTemplate, MutationObserver;
function IMESelector( element, options ) {
this.$element = $( element );
this.options = $.extend( {}, IMESelector.defaults, options );
this.active = false;
this.$imeSetting = null;
this.$menu = null;
this.inputmethod = null;
this.timer = null;
this.init();
this.listen();
}
function languageListTitle() {
return $( '<h3>' )
.addClass( 'ime-lang-title' )
.attr( 'data-i18n', 'jquery-ime-other-languages' )
.text( 'Other languages' );
}
function imeList() {
return $( '<ul>' ).addClass( 'ime-list' );
}
function imeListTitle() {
return $( '<h3>' ).addClass( 'ime-list-title autonym' );
}
function toggleMenuItem() {
return $( '<div>' ).addClass( 'ime-disable selectable-row' ).append(
$( '<span>' )
.addClass( 'ime-disable-link' )
.addClass( 'ime-checked' )
.attr( 'data-i18n', 'jquery-ime-disable-text' )
.text( 'System input method' ),
$( '<span>' )
.addClass( 'ime-disable-shortcut' )
.text( 'CTRL+M' )
);
}
/**
* Check whether a keypress event corresponds to the shortcut key
*
* @param {event} event
* @return {boolean} true if the key is a shortcut key
*/
function isShortcutKey( event ) {
// 77 - The letter M, for Ctrl-M
return event.ctrlKey && !event.altKey && ( event.which === 77 );
}
IMESelector.prototype = {
constructor: IMESelector,
init: function () {
this.prepareSelectorMenu();
this.position();
this.$imeSetting.hide();
},
prepareSelectorMenu: function () {
// TODO: In this approach there is a menu for each editable area.
// With correct event mapping we can probably reduce it to one menu.
this.$imeSetting = $( selectorTemplate );
this.$menu = $( '<div>' ).addClass( 'imeselector-menu' ).attr( 'role', 'menu' );
this.$menu.append(
imeListTitle(),
imeList(),
toggleMenuItem(),
languageListTitle()
);
this.prepareLanguageList();
this.$menu.append( this.helpLink() );
if ( $.i18n ) {
this.$menu.i18n();
}
this.$imeSetting.append( this.$menu );
$( document.body ).append( this.$imeSetting );
},
stopTimer: function () {
if ( this.timer ) {
clearTimeout( this.timer );
this.timer = null;
}
this.$imeSetting.stop( true, true );
},
resetTimer: function () {
var imeselector = this;
this.stopTimer();
this.timer = setTimeout(
function () {
// TODO: Use CSS transitions
// eslint-disable-next-line no-jquery/no-animate
imeselector.$imeSetting.animate( {
opacity: 0,
marginTop: '-20px'
}, 500, function () {
imeselector.$imeSetting.hide();
// Restore properties for the next time it becomes visible:
imeselector.$imeSetting.css( 'opacity', 1 );
imeselector.$imeSetting.css( 'margin-top', 0 );
} );
}, this.options.timeout
);
},
focus: function () {
// Hide all other IME settings and collapse open menus
// eslint-disable-next-line no-jquery/no-global-selector
$( 'div.imeselector' ).hide();
// eslint-disable-next-line no-jquery/no-global-selector
$( 'div.imeselector-menu' ).removeClass( 'ime-open' );
this.afterKeydown();
},
afterKeydown: function () {
this.$imeSetting.show();
this.resetTimer();
},
show: function () {
this.$menu.addClass( 'ime-open' );
this.stopTimer();
this.$imeSetting.show();
return false;
},
hide: function () {
this.$menu.removeClass( 'ime-open' );
this.resetTimer();
return false;
},
toggle: function () {
// eslint-disable-next-line no-jquery/no-class-state
if ( this.$menu.hasClass( 'ime-open' ) ) {
this.hide();
} else {
this.show();
}
},
/**
* Bind the events and listen
*/
listen: function () {
var imeselector = this;
imeselector.$imeSetting.on( 'click.ime', function ( e ) {
var $t = $( e.target );
// eslint-disable-next-line no-jquery/no-class-state
if ( $t.hasClass( 'imeselector-toggle' ) ) {
imeselector.toggle();
}
return false;
} );
imeselector.$element.on( 'blur.ime', function () {
// eslint-disable-next-line no-jquery/no-class-state
if ( !imeselector.$imeSetting.hasClass( 'ime-onfocus' ) ) {
imeselector.$imeSetting.hide();
imeselector.hide();
}
} );
// Hide the menu when clicked outside
$( document.body ).on( 'click', function () {
imeselector.hide();
} );
// ... but when clicked on window do not propagate it.
this.$menu.on( 'click', function ( event ) {
event.stopPropagation();
} );
imeselector.$imeSetting.on( 'mouseenter', function () {
// We don't want the selector to disappear
// while the user is trying to click it
imeselector.stopTimer();
imeselector.$imeSetting.addClass( 'ime-onfocus' );
} ).on( 'mouseleave', function () {
imeselector.resetTimer();
imeselector.$imeSetting.removeClass( 'ime-onfocus' );
} );
imeselector.$menu.on( 'click.ime', 'li', function () {
imeselector.$element.trigger( 'focus' );
return false;
} );
imeselector.$menu.on( 'click.ime', 'li.ime-im', function () {
imeselector.selectIM( $( this ).data( 'ime-inputmethod' ) );
imeselector.$element.trigger( 'setim.ime', $( this ).data( 'ime-inputmethod' ) );
return false;
} );
imeselector.$menu.on( 'click.ime', 'li.ime-lang', function () {
var im = imeselector.selectLanguage( $( this ).attr( 'lang' ) );
imeselector.$element.trigger( 'setim.ime', im );
return false;
} );
imeselector.$menu.on( 'click.ime', 'div.ime-disable', function () {
imeselector.disableIM();
return false;
} );
// Just make it work as a regular link
imeselector.$menu.on( 'click.ime', '.ime-help-link', function ( e ) {
e.stopPropagation();
} );
imeselector.$element.on( 'focus.ime', function ( e ) {
imeselector.selectLanguage( imeselector.decideLanguage() );
imeselector.focus();
e.stopPropagation();
} );
imeselector.$element.attrchange( function () {
// eslint-disable-next-line no-jquery/no-sizzle
if ( imeselector.$element.is( ':hidden' ) ) {
imeselector.$imeSetting.hide();
}
} );
// Possible resize of textarea
imeselector.$element.on( {
'mouseup.ime': this.position.bind( this ),
'keydown.ime': this.keydown.bind( this )
} );
// Update IM selector position when the window is resized
// or the browser window is zoomed in or zoomed out
$( window ).on( 'resize', function () {
imeselector.position();
} );
},
/**
* Keydown event handler. Handles shortcut key presses
*
* @this HTMLElement
* @param {jQuery.Event} e
* @return {boolean}
*/
keydown: function ( e ) {
var ime = $( e.target ).data( 'ime' ),
firstInputmethod,
previousInputMethods,
languageCode;
this.afterKeydown(); // shows the trigger in case it is hidden
if ( isShortcutKey( e ) ) {
if ( ime.isActive() ) {
this.disableIM();
this.$element.trigger( 'setim.ime', 'system' );
} else {
if ( this.inputmethod !== null ) {
this.selectIM( this.inputmethod.id );
this.$element.trigger( 'setim.ime', this.inputmethod.id );
} else {
languageCode = this.decideLanguage();
this.selectLanguage( languageCode );
if ( !ime.isActive() && $.ime.languages[ languageCode ] ) {
// Even after pressing toggle shortcut again, it is still disabled
// Check if there is a previously used input method.
previousInputMethods = $.ime.preferences.getPreviousInputMethods();
if ( previousInputMethods[ 0 ] ) {
this.selectIM( previousInputMethods[ 0 ] );
} else {
// Provide the default input method in this case.
firstInputmethod =
$.ime.languages[ languageCode ].inputmethods[ 0 ];
this.selectIM( firstInputmethod );
}
}
}
}
e.preventDefault();
e.stopPropagation();
return false;
}
return true;
},
/**
* Position the im selector relative to the edit area
*/
position: function () {
var menuWidth, menuTop, menuLeft, elementPosition,
top, left, cssTop, cssLeft, verticalRoom, overflowsOnRight,
imeSelector = this,
rtlElement = this.$element.css( 'direction' ) === 'rtl',
$window = $( window );
this.focus(); // shows the trigger in case it is hidden
elementPosition = this.$element.offset();
top = elementPosition.top + this.$element.outerHeight();
left = elementPosition.left;
// RTL element position fix
if ( !rtlElement ) {
left = elementPosition.left + this.$element.outerWidth() -
this.$imeSetting.outerWidth();
}
if ( this.options.selectorInside ) {
top -= this.$imeSetting.outerHeight();
}
// While determining whether to place the selector above or below the input box,
// take into account the value of scrollTop, to avoid the selector from always
// getting placed above the input box since window.height would be less than top
// if the page has been scrolled.
verticalRoom = $window.height() + $( document ).scrollTop() - top;
if ( verticalRoom < this.$imeSetting.outerHeight() ) {
top = elementPosition.top - this.$imeSetting.outerHeight();
if ( this.options.selectorInside ) {
top += this.$imeSetting.outerHeight();
}
menuTop = this.$menu.outerHeight() +
this.$imeSetting.outerHeight();
// Flip the menu to the top only if it can fit in the space there
if ( menuTop < top ) {
this.$menu
.addClass( 'ime-position-top' )
.css( 'top', -menuTop );
}
}
cssTop = top;
cssLeft = left;
this.$element.parents().each( function () {
if ( $( this ).css( 'position' ) === 'fixed' ) {
imeSelector.$imeSetting.css( 'position', 'fixed' );
cssTop -= $( document ).scrollTop();
cssLeft -= $( document ).scrollLeft();
return false;
}
} );
this.$imeSetting.css( {
top: cssTop,
left: cssLeft
} );
menuWidth = this.$menu.width();
overflowsOnRight = ( left - $( document ).scrollLeft() + menuWidth ) > $window.width();
// Adjust horizontal position if there's
// not enough space on any side
if ( menuWidth > left ||
rtlElement && overflowsOnRight
) {
if ( rtlElement ) {
if ( overflowsOnRight ) {
this.$menu.addClass( 'ime-right' );
menuLeft = this.$imeSetting.outerWidth() - menuWidth;
} else {
menuLeft = 0;
}
} else {
this.$menu.addClass( 'ime-right' );
menuLeft = elementPosition.left;
}
this.$menu.css( 'left', menuLeft );
}
},
/**
* Select a language
*
* @param {string} languageCode
* @return {string|boolean} Selected input method id or false
*/
selectLanguage: function ( languageCode ) {
var ime, imePref, language;
// consider language codes case insensitive
languageCode = languageCode && languageCode.toLowerCase();
ime = this.$element.data( 'ime' );
imePref = $.ime.preferences.getIM( languageCode );
language = $.ime.languages[ languageCode ];
this.setMenuTitle( this.getAutonym( languageCode ) );
if ( !language ) {
return false;
}
if ( ime.getLanguage() === languageCode ) {
// Nothing to do. It is same as the current language,
// but check whether the input method changed.
if ( ime.inputmethod && ime.inputmethod.id !== imePref ) {
this.selectIM( $.ime.preferences.getIM( languageCode ) );
}
return $.ime.preferences.getIM( languageCode );
}
this.$menu.find( 'li.ime-lang' ).show();
this.$menu.find( 'li[lang=' + languageCode + ']' ).hide();
this.prepareInputMethods( languageCode );
this.hide();
// And select the default inputmethod
ime.setLanguage( languageCode );
this.inputmethod = null;
this.selectIM( $.ime.preferences.getIM( languageCode ) );
return $.ime.preferences.getIM( languageCode );
},
/**
* Get the autonym by language code.
*
* @param {string} languageCode
* @return {string} The autonym
*/
getAutonym: function ( languageCode ) {
return $.ime.languages[ languageCode ] &&
$.ime.languages[ languageCode ].autonym;
},
/**
* Set the title of the selector menu.
*
* @param {string} title
*/
setMenuTitle: function ( title ) {
this.$menu.find( '.ime-list-title' ).text( title );
},
/**
* Decide on initial language to select
*
* @return {string}
*/
decideLanguage: function () {
if ( $.ime.preferences.getLanguage() ) {
// There has been an override by the user,
// so return the language selected by user
return $.ime.preferences.getLanguage();
}
if ( this.$element.attr( 'lang' ) &&
$.ime.languages[ this.$element.attr( 'lang' ) ]
) {
return this.$element.attr( 'lang' );
}
// There is either no IMs for the given language attr
// or there is no lang attr at all.
return $.ime.preferences.getDefaultLanguage();
},
/**
* Select an input method
*
* @param {string} inputmethodId
*/
selectIM: function ( inputmethodId ) {
var imeselector = this,
ime;
if ( !inputmethodId ) {
return;
}
this.$menu.find( '.ime-checked' ).removeClass( 'ime-checked' );
this.$menu.find( 'li[data-ime-inputmethod=' + inputmethodId + ']' )
.addClass( 'ime-checked' );
ime = this.$element.data( 'ime' );
if ( inputmethodId === 'system' ) {
this.disableIM();
return;
}
ime.load( inputmethodId ).done( function () {
imeselector.inputmethod = $.ime.inputmethods[ inputmethodId ];
imeselector.hide();
ime.enable();
ime.setIM( inputmethodId );
imeselector.$imeSetting.find( 'a.ime-name' ).text(
$.ime.sources[ inputmethodId ].name
);
imeselector.position();
// Save this preference
$.ime.preferences.save();
} );
},
/**
* Disable the inputmethods (Use the system input method)
*/
disableIM: function () {
this.$menu.find( '.ime-checked' ).removeClass( 'ime-checked' );
this.$menu.find( 'div.ime-disable' ).addClass( 'ime-checked' );
this.$element.data( 'ime' ).disable();
this.$imeSetting.find( 'a.ime-name' ).text( '' );
this.hide();
this.position();
// Save this preference
$.ime.preferences.save();
},
/**
* Prepare language list
*/
prepareLanguageList: function () {
var languageCodeIndex,
$languageListWrapper,
$languageList,
languageList,
$languageItem,
$language,
languageCode,
language;
// Language list can be very long, so we use a container with
// overflow auto
$languageListWrapper = $( '<div>' ).addClass( 'ime-language-list-wrapper' );
$languageList = $( '<ul>' ).addClass( 'ime-language-list' );
if ( typeof this.options.languages === 'function' ) {
languageList = this.options.languages();
} else {
languageList = this.options.languages;
}
for ( languageCodeIndex in languageList ) {
languageCode = languageList[ languageCodeIndex ];
language = $.ime.languages[ languageCode ];
if ( !language ) {
continue;
}
$languageItem = $( '<a>' )
.attr( 'href', '#' )
.text( this.getAutonym( languageCode ) )
.addClass( 'selectable-row-item autonym' );
$language = $( '<li>' ).addClass( 'ime-lang selectable-row' ).attr( 'lang', languageCode );
$language.append( $languageItem );
$languageList.append( $language );
}
$languageListWrapper.append( $languageList );
this.$menu.append( $languageListWrapper );
if ( this.options.languageSelector ) {
this.$menu.append( this.options.languageSelector() );
}
},
/**
* Prepare input methods in menu for the given language code
*
* @param {string} languageCode
*/
prepareInputMethods: function ( languageCode ) {
var language = $.ime.languages[ languageCode ],
$imeList = this.$menu.find( '.ime-list' ),
imeSelector = this;
$imeList.empty();
language.inputmethods.forEach( function ( inputmethod ) {
var $imeItem, $inputMethod, source, name;
source = $.ime.sources[ inputmethod ];
if ( !source ) {
return;
}
name = source.name;
$imeItem = $( '<a>' )
.attr( 'href', '#' )
.text( name )
.addClass( 'selectable-row-item' );
$inputMethod = $( '<li>' )
.attr( 'data-ime-inputmethod', inputmethod )
.addClass( 'ime-im selectable-row' )
.append(
$( '<span>' ).addClass( 'ime-im-check' ),
$imeItem
);
if ( imeSelector.options.helpHandler ) {
$inputMethod.append(
imeSelector.options.helpHandler.call( imeSelector, inputmethod )
);
}
$imeList.append( $inputMethod );
} );
},
/**
* Create a help link element.
*
* @return {jQuery}
*/
helpLink: function () {
return $( '<div>' ).addClass( 'ime-help-link selectable-row' )
.append( $( '<a>' ).text( 'Help' )
.addClass( 'selectable-row-item' )
.attr( {
href: 'http://github.com/wikimedia/jquery.ime',
target: '_blank',
'data-i18n': 'jquery-ime-help'
} )
);
}
};
IMESelector.defaults = {
defaultLanguage: 'en',
timeout: 2500 // Milliseconds after which IME widget hides itself.
};
/*
* imeselector PLUGIN DEFINITION
*/
$.fn.imeselector = function ( options ) {
return this.each( function () {
var $this = $( this ),
data = $this.data( 'imeselector' );
if ( !data ) {
$this.data( 'imeselector', ( data = new IMESelector( this, options ) ) );
}
if ( typeof options === 'string' ) {
data[ options ].call( $this );
}
} );
};
$.fn.imeselector.Constructor = IMESelector;
selectorTemplate = '<div class="imeselector imeselector-toggle">' +
'<a class="ime-name imeselector-toggle" href="#"></a>' +
'<b class="ime-setting-caret imeselector-toggle"></b></div>';
MutationObserver = window.MutationObserver ||
window.WebKitMutationObserver ||
window.MozMutationObserver;
function isDOMAttrModifiedSupported() {
var p = document.createElement( 'p' ),
flag = false;
if ( p.addEventListener ) {
p.addEventListener( 'DOMAttrModified', function () {
flag = true;
}, false );
} else if ( p.attachEvent ) {
p.attachEvent( 'onDOMAttrModified', function () {
flag = true;
} );
} else {
return false;
}
p.setAttribute( 'id', 'target' );
return flag;
}
$.fn.attrchange = function ( callback ) {
var observer;
if ( MutationObserver ) {
observer = new MutationObserver( function ( mutations ) {
mutations.forEach( function ( e ) {
callback.call( e.target, e.attributeName );
} );
} );
return this.each( function () {
observer.observe( this, {
subtree: false,
attributes: true
} );
} );
} else if ( isDOMAttrModifiedSupported() ) {
return this.on( 'DOMAttrModified', function ( e ) {
callback.call( this, e.originalEvent.attrName );
} );
} else if ( 'onpropertychange' in document.body ) {
return this.on( 'propertychange', function () {
callback.call( this, window.event.propertyName );
} );
}
};
}( jQuery ) );
( function ( $ ) {
'use strict';
$.extend( $.ime.preferences, {
registry: {
isDirty: false,
language: null,
previousLanguages: [], // array of previous languages
previousInputMethods: [], // array of previous inputmethods
imes: {
en: 'system'
}
},
setLanguage: function ( language ) {
// Do nothing if there's no actual change
if ( language === this.registry.language ) {
return;
}
this.registry.language = language;
this.registry.isDirty = true;
if ( !this.registry.previousLanguages ) {
this.registry.previousLanguages = [];
}
// Add to the previous languages, but avoid duplicates.
if ( this.registry.previousLanguages.indexOf( language ) === -1 ) {
this.registry.previousLanguages.unshift( language );
this.registry.previousLanguages = this.registry.previousLanguages.slice( 0, 5 );
}
},
getLanguage: function () {
return this.registry.language;
},
getDefaultLanguage: function () {
return 'en';
},
getPreviousLanguages: function () {
return this.registry.previousLanguages;
},
getPreviousInputMethods: function () {
return this.registry.previousInputMethods || [];
},
// Set the given IM as the last used for the language
setIM: function ( inputMethod ) {
if ( !this.registry.imes ) {
this.registry.imes = {};
}
// Do nothing if there's no actual change
if ( inputMethod === this.registry.imes[ this.registry.language ] ) {
return;
}
this.registry.imes[ this.getLanguage() ] = inputMethod;
this.registry.isDirty = true;
if ( !this.registry.previousInputMethods ) {
this.registry.previousInputMethods = [];
}
// Add to the previous languages,
if ( inputMethod !== 'system' ) {
this.registry.previousInputMethods.unshift( inputMethod );
this.registry.previousInputMethods =
this.registry.previousInputMethods.slice( 0, 5 );
}
},
// Return the last used or the default IM for language
getIM: function ( language ) {
if ( !this.registry.imes ) {
this.registry.imes = {};
}
return this.registry.imes[ language ] || 'system';
},
save: function () {
// save registry in cookies or localstorage
},
load: function () {
// load registry from cookies or localstorage
}
} );
}( jQuery ) );
( function ( $ ) {
'use strict';
// All keys have quotes for consistency
/* eslint-disable quote-props */
$.extend( $.ime.sources, {
'af-tilde': {
name: 'Afrikaans tilde',
source: 'rules/af/af-tilde.js'
},
'ajg-tilde': {
name: 'Aja tilde',
source: 'rules/ajg/ajg-tilde.js'
},
'ak-qx': {
name: 'Akan QX replacement',
source: 'rules/ak/ak-qx.js'
},
'ak-tilde': {
name: 'Akan tilde',
source: 'rules/ak/ak-tilde.js'
},
'am-transliteration': {
name: 'ትራንስልተራትዖን',
source: 'rules/am/am-transliteration.js'
},
'ann-tilde': {
name: 'Obolo tilde',
source: 'rules/ann/ann-tilde.js'
},
'ar-kbd': {
name: 'لوحة المفاتيح العربية',
source: 'rules/ar/ar-kbd.js'
},
'as-avro': {
name: 'অভ্ৰ',
source: 'rules/as/as-avro.js'
},
'as-bornona': {
name: 'বৰ্ণনা',
source: 'rules/as/as-bornona.js'
},
'as-inscript': {
name: 'ইনস্ক্ৰিপ্ট',
source: 'rules/as/as-inscript.js'
},
'as-inscript2': {
name: 'ইনস্ক্ৰিপ্ট ২',
source: 'rules/as/as-inscript2.js'
},
'as-phonetic': {
name: 'ফনেটিক',
source: 'rules/as/as-phonetic.js'
},
'as-rodali': {
name: 'ৰ\'দালি',
source: 'rules/as/as-rodali.js'
},
'as-transliteration': {
name: 'প্ৰতিৰূপান্তৰণ',
source: 'rules/as/as-transliteration.js'
},
'azb-kbd': {
name: 'تۆرکجه',
source: 'rules/azb/azb-kbd.js'
},
'bas-tilde': {
name: 'Ɓasaá tilde',
source: 'rules/bas/bas-tilde.js'
},
'batak-qwerty': {
name: 'Batak QWERTY',
source: 'rules/bbc/batak-qwerty.js'
},
'bci-tilde': {
name: 'Baoulé tilde keyboard',
source: 'rules/bci/bci-tilde.js'
},
'be-kbd': {
name: 'Стандартная',
source: 'rules/be/be-kbd.js'
},
'be-latin': {
name: 'Łacinka',
source: 'rules/be/be-latin.js'
},
'be-transliteration': {
name: 'Транслітэрацыя',
source: 'rules/be/be-transliteration.js'
},
'ber-tfng': {
name: 'Tifinagh',
source: 'rules/ber/ber-tfng.js'
},
'bgn-kbd': {
name: 'روچ کپتین بلوچی',
source: 'rules/bgn/bgn-kbd.js'
},
'bkm-tilde': {
name: 'Kom tilde',
source: 'rules/bkm/bkm-tilde.js'
},
'bm-alt': {
name: 'Bamanankan Alt',
source: 'rules/bm/bm-alt.js'
},
'bm-tilde': {
name: 'Bamanankan tilde',
source: 'rules/bm/bm-tilde.js'
},
'bn-avro': {
name: 'অভ্র',
source: 'rules/bn/bn-avro.js'
},
'bn-inscript': {
name: 'ইনস্ক্ৰিপ্ট',
source: 'rules/bn/bn-inscript.js'
},
'bn-inscript2': {
name: 'ইনস্ক্ৰিপ্ট ২',
source: 'rules/bn/bn-inscript2.js'
},
'bn-nkb': {
name: 'জাতীয় কিবোর্ড',
source: 'rules/bn/bn-nkb.js'
},
'bn-probhat': {
name: 'প্রভাত',
source: 'rules/bn/bn-probhat.js'
},
'bo-ewts': {
name: 'Tibetan EWTS',
source: 'rules/bo/bo-ewts.js'
},
'bo-sambhota': {
name: 'Tibetan Sambhota',
source: 'rules/bo/bo-sambhota.js'
},
'brx-inscript': {
name: 'इनस्क्रिप्ट',
source: 'rules/brx/brx-inscript.js'
},
'brx-inscript2': {
name: 'इनस्क्रिप्ट २',
source: 'rules/brx/brx-inscript2.js'
},
'bwr-tilde': {
name: 'Bura tilde',
source: 'rules/bwr/bwr-tilde.js'
},
'byn-geezim': {
name: 'ብሊን',
source: 'rules/byn/byn-geezim.js'
},
'ckb-transliteration-arkbd': {
name: 'باشووری',
source: 'rules/ckb/ckb-transliteration-arkbd.js'
},
'ckb-transliteration-fakbd': {
name: 'ڕۆژھەڵاتی',
source: 'rules/ckb/ckb-transliteration-fakbd.js'
},
'ckb-transliteration-lakbd': {
name: 'لاتینی',
source: 'rules/ckb/ckb-transliteration-lakbd.js'
},
'cv-cyr-altgr': {
name: 'Чăвашла (AltGr)',
source: 'rules/cv/cv-cyr-altgr.js'
},
'cv-cyr-numbers': {
name: 'Чăвашла (цифрилисем)',
source: 'rules/cv/cv-cyr-numbers.js'
},
'cv-lat-altgr': {
name: 'Căvašla (AltGr)',
source: 'rules/cv/cv-lat-altgr.js'
},
'cyrl-palochka': {
name: 'Palochka',
source: 'rules/cyrl/cyrl-palochka.js'
},
'da-normforms': {
name: 'Brug translitteration',
source: 'rules/da/da-normforms.js'
},
'dag-alt': {
name: 'Dagbani Alt',
source: 'rules/dag/dag-alt.js'
},
'dag-tilde': {
name: 'Dagbani tilde',
source: 'rules/dag/dag-tilde.js'
},
'de-transliteration': {
name: 'Deutsch Tilde',
source: 'rules/de/de-transliteration.js'
},
'din-fqsx': {
name: 'Dinka FQSX',
source: 'rules/din/din-fqsx.js'
},
'din-tilde': {
name: 'Dinka tilde',
source: 'rules/din/din-tilde.js'
},
'doi-inscript2': {
name: 'इनस्क्रिप्ट २',
source: 'rules/doi/doi-inscript2.js'
},
'ee-tilde': {
name: 'Ewe Tilde',
source: 'rules/ee/ee-tilde.js'
},
'efi-tilde': {
name: 'Efik - tilde',
source: 'rules/efi/efi-tilde.js'
},
'el-kbd': {
name: 'Τυπική πληκτρολόγιο',
source: 'rules/el/el-kbd.js'
},
'eo-h': {
name: 'Esperanto h',
source: 'rules/eo/eo-h.js'
},
'eo-h-f': {
name: 'Esperanto h fundamente',
source: 'rules/eo/eo-h-f.js'
},
'eo-plena': {
name: 'Esperanto plena',
source: 'rules/eo/eo-plena.js'
},
'eo-q': {
name: 'Esperanto q sistemo',
source: 'rules/eo/eo-q.js'
},
'eo-transliteration': {
name: 'transliterigo',
source: 'rules/eo/eo-transliteration.js'
},
'eo-vi': {
name: 'Esperanto vi sistemo',
source: 'rules/eo/eo-vi.js'
},
'eo-x': {
name: 'Esperanto x sistemo',
source: 'rules/eo/eo-x.js'
},
'fa-kbd': {
name: 'فارسی',
source: 'rules/fa/fa-kbd.js'
},
'ff-alt': {
name: 'Fulfulde alt',
source: 'rules/ff/ff-alt.js'
},
'ff-tilde': {
name: 'Fulfulde tilde',
source: 'rules/ff/ff-tilde.js'
},
'fi-transliteration': {
name: 'translitterointi',
source: 'rules/fi/fi-transliteration.js'
},
'fo-normforms': {
name: 'Føroyskt',
source: 'rules/fo/fo-normforms.js'
},
'fon-tilde': {
name: 'Fon Tilde',
source: 'rules/fon/fon-tilde.js'
},
'gaa-cqx': {
name: 'Ga CQX replacement',
source: 'rules/gaa/gaa-cqx.js'
},
'gaa-tilde': {
name: 'Ga tilde',
source: 'rules/gaa/gaa-tilde.js'
},
'gom-inscript2': {
name: 'इनस्क्रिप्ट २',
source: 'rules/gom/gom-inscript2.js'
},
'got-standard': {
name: '𐌲𐌿𐍄𐌹𐍃𐌺𐌰 𐍂𐌰𐌶𐌳𐌰',
source: 'rules/got/got-standard.js'
},
'gu-inscript': {
name: 'ઇનસ્ક્રિપ્ટ',
source: 'rules/gu/gu-inscript.js'
},
'gu-inscript2': {
name: 'ઇનસ્ક્રિપ્ટ ૨',
source: 'rules/gu/gu-inscript2.js'
},
'gu-phonetic': {
name: 'ફોનૅટિક',
source: 'rules/gu/gu-phonetic.js'
},
'gu-transliteration': {
name: 'લિપ્યંતરણ',
source: 'rules/gu/gu-transliteration.js'
},
'gur-tilde': {
name: 'Farefare tilde',
source: 'rules/gur/gur-tilde.js'
},
'ha-tilde': {
name: 'Hausa - tilde',
source: 'rules/ha/ha-tilde.js'
},
'he-standard-2012': {
name: 'עברית עם ניקוד על בסיס אנגלית',
source: 'rules/he/he-standard-2012.js'
},
'he-standard-2012-extonly': {
name: 'עברית עם ניקוד',
source: 'rules/he/he-standard-2012-extonly.js'
},
'hi-bolnagri': {
name: 'बोलनागरी',
source: 'rules/hi/hi-bolnagri.js'
},
'hi-inscript': {
name: 'इनस्क्रिप्ट',
source: 'rules/hi/hi-inscript.js'
},
'hi-inscript2': {
name: 'इनस्क्रिप्ट २',
source: 'rules/hi/hi-inscript2.js'
},
'hi-phonetic': {
name: 'फोनेटिक',
source: 'rules/hi/hi-phonetic.js'
},
'hi-transliteration': {
name: 'लिप्यंतरण',
source: 'rules/hi/hi-transliteration.js'
},
'hoc-transliteration': {
name: 'Ho transliteration',
source: 'rules/hoc/hoc-transliteration.js'
},
'hr-kbd': {
name: 'Croatian kbd',
source: 'rules/hr/hr-kbd.js'
},
'hy-emslegacy': {
name: 'Մայքրոսոֆթի հին արևելահայերեն',
source: 'rules/hy/hy-emslegacy.js'
},
'hy-ephonetic': {
name: 'Հնչյունային դասավորություն',
source: 'rules/hy/hy-ephonetic.js'
},
'hy-ephoneticalt': {
name: 'Հնչյունային նոր (R→Ր, F→Թ)',
source: 'rules/hy/hy-ephoneticalt.js'
},
'hy-typewriter': {
name: 'Գրամեքենայի դասավորություն',
source: 'rules/hy/hy-typewriter.js'
},
'hy-wmslegacy': {
name: 'Մայքրոսոֆթի հին արևմտահայերեն',
source: 'rules/hy/hy-wmslegacy.js'
},
'ig-tilde': {
name: 'Igbo - tilde',
source: 'rules/ig/ig-tilde.js'
},
'ipa-sil': {
name: 'International Phonetic Alphabet - SIL',
source: 'rules/fonipa/ipa-sil.js'
},
'ipa-x-sampa': {
name: 'International Phonetic Alphabet - X-SAMPA',
source: 'rules/fonipa/ipa-x-sampa.js'
},
'is-normforms': {
name: 'Venjuleg eyðublöð',
source: 'rules/is/is-normforms.js'
},
'jv-transliteration': {
name: 'Transliteration',
source: 'rules/jv/jv-transliteration.js'
},
'ka-kbd': {
name: 'სტანდარტული კლავიატურის',
source: 'rules/ka/ka-kbd.js'
},
'ka-transliteration': {
name: 'ტრანსლიტერაცია',
source: 'rules/ka/ka-transliteration.js'
},
'kab-tilde': {
name: 'Taqbaylit Alatin tilde',
source: 'rules/kab/kab-tilde.js'
},
'kbp-tilde': {
name: 'Kabɩyɛ tilde',
source: 'rules/kbp/kbp-tilde.js'
},
'kcg-tilde': {
name: 'Tyap tilde',
source: 'rules/kcg/kcg-tilde.js'
},
'ki-tilde': {
name: 'Gĩkũyũ',
source: 'rules/ki/ki-tilde.js'
},
'kk-arabic': {
name: 'Kazakh Arabic transliteration',
source: 'rules/kk/kk-arabic.js'
},
'kk-kbd': {
name: 'Кирил',
source: 'rules/kk/kk-kbd.js'
},
'km-nidakyk': {
name: 'ក្តារ​ចុច​យូនីកូដ​ខ្មែរ (NiDA)',
source: 'rules/km/km-nidakyk.js'
},
'kn-inscript': {
name: 'ಇನ್ಸ್ಕ್ರಿಪ್ಟ್',
source: 'rules/kn/kn-inscript.js'
},
'kn-inscript2': {
name: 'ಇನ್\u200cಸ್ಕ್ರಿಪ್ಟ್ ೨',
source: 'rules/kn/kn-inscript2.js'
},
'kn-kgp': {
name: 'KGP/Nudi/KP Rao',
source: 'rules/kn/kn-kgp.js'
},
'kn-transliteration': {
name: 'ಲಿಪ್ಯಂತರಣ',
source: 'rules/kn/kn-transliteration.js'
},
'kr-tilde': {
name: 'Kanuri tilde',
source: 'rules/kr/kr-tilde.js'
},
'ky-cyrl-alt': {
name: 'Кыргыз Alt',
source: 'rules/ky/ky-cyrl-alt.js'
},
'ks-inscript': {
name: 'इनस्क्रिप्ट',
source: 'rules/ks/ks-inscript.js'
},
'ks-kbd': {
name: 'Kashmiri Arabic',
source: 'rules/ks/ks-kbd.js'
},
'ku-h': {
name: 'Kurdî-h',
source: 'rules/ku/ku-h.js'
},
'ku-tr': {
name: 'Kurdî-tr',
source: 'rules/ku/ku-tr.js'
},
'lg-tilde': {
name: 'Luganda tilde',
source: 'rules/lg/lg-tilde.js'
},
'ln-tilde': {
name: 'Lingála tilde',
source: 'rules/ln/ln-tilde.js'
},
'lo-kbd': {
name: 'າຶກ',
source: 'rules/lo/lo-kbd.js'
},
'lrc-kbd': {
name: 'لۊری شومالی',
source: 'rules/lrc/lrc-kbd.js'
},
'lud-transliteration': {
name: 'lud',
source: 'rules/lud/lud-transliteration.js'
},
'lut-tulalip': {
name: 'Lushootseed Tulalip',
source: 'rules/lut/lut-tulalip.js'
},
'mad-tilde': {
name: 'Madhurâ tilde',
source: 'rules/mad/mad-tilde.js'
},
'mai-inscript': {
name: 'इनस्क्रिप्ट',
source: 'rules/mai/mai-inscript.js',
depends: 'hi-inscript'
},
'mai-inscript2': {
name: 'इनस्क्रिप्ट २',
source: 'rules/mai/mai-inscript2.js',
depends: 'hi-inscript2'
},
'mg-tilde': {
name: 'Malagasy tilde',
source: 'rules/mg/mg-tilde.js'
},
'mh': {
name: 'Kajin M̧ajeļ',
source: 'rules/mh/mh.js'
},
'ml-inscript': {
name: 'ഇൻസ്ക്രിപ്റ്റ്',
source: 'rules/ml/ml-inscript.js'
},
'ml-inscript2': {
name: 'ഇൻസ്ക്രിപ്റ്റ് 2',
source: 'rules/ml/ml-inscript2.js'
},
'ml-transliteration': {
name: 'ലിപ്യന്തരണം',
source: 'rules/ml/ml-transliteration.js'
},
'mn-cyrl': {
name: 'Кирилл',
source: 'rules/mn/mn-cyrl.js'
},
'mn-todo': {
name: 'ᡐᡆᡑᡆ ᡋᡅᡔᡅᡎ᠌',
source: 'rules/mn/mn-todo.js'
},
'mn-todoali': {
name: 'Todo Mongolian Ali-gali',
source: 'rules/mn/mn-todoali.js'
},
'mn-trad': {
name: 'ᠮᠣᠩᠭᠣᠯ ᠪᠢᠴᠢᠭ᠌',
source: 'rules/mn/mn-trad.js'
},
'mn-tradali': {
name: 'Traditional Mongolian Ali-gali',
source: 'rules/mn/mn-tradali.js'
},
'mnc': {
name: 'ᠮᠠᠨᠵᡠ',
source: 'rules/mnc/mnc.js'
},
'mnc-ali': {
name: 'Manchu Ali-gali',
source: 'rules/mnc/mnc-ali.js'
},
'mni-inscript2': {
name: 'ইনস্ক্ৰিপ্ট ২',
source: 'rules/mni/mni-inscript2.js'
},
'mnw-simplified-anonta': {
name: 'Mon Simplified Anonta',
source: 'rules/mnw/mnw-simplified-anonta.js'
},
'mr-inscript': {
name: 'मराठी लिपी',
source: 'rules/mr/mr-inscript.js'
},
'mr-inscript2': {
name: 'मराठी इनस्क्रिप्ट २',
source: 'rules/mr/mr-inscript2.js'
},
'mr-phonetic': {
name: 'फोनेटिक',
source: 'rules/mr/mr-phonetic.js'
},
'mr-transliteration': {
name: 'अक्षरांतरण',
source: 'rules/mr/mr-transliteration.js'
},
'mul-bf': {
name: 'Burkina Faso tilde keyboard',
source: 'rules/mul-bf/mul-bf.js'
},
'mul-cm': {
name: 'General Alphabet of Cameroon Languages tilde keyboard',
source: 'rules/mul-cm/mul-cm.js'
},
'my-mm3': {
name: 'မြန်မာ၃ လက်ကွက်',
source: 'rules/my/my-mm3.js'
},
'my-xkb': {
name: 'မြန်မာဘာသာ xkb',
source: 'rules/my/my-xkb.js'
},
'nb-normforms': {
name: 'Normal transliterasjon',
source: 'rules/nb/nb-normforms.js'
},
'nb-tildeforms': {
name: 'Tildemerket transliterasjon',
source: 'rules/nb/nb-tildeforms.js'
},
'ne-inscript': {
name: 'इनस्क्रिप्ट',
source: 'rules/ne/ne-inscript.js'
},
'ne-inscript2': {
name: 'इनस्क्रिप्ट २',
source: 'rules/ne/ne-inscript2.js'
},
'ne-rom': {
name: 'Romanized',
source: 'rules/ne/ne-rom.js'
},
'ne-trad': {
name: 'Traditional',
source: 'rules/ne/ne-trad.js'
},
'ne-transliteration': {
name: 'ट्रांस्लितेरेशन',
source: 'rules/ne/ne-transliteration.js'
},
'nia-tilde': {
name: 'Li Niha tilde',
source: 'rules/nia/nia-tilde.js'
},
'nmz-tilde': {
name: 'Nawdm tilde',
source: 'rules/nmz/nmz-tilde.js'
},
'nqo-standard-qwerty': {
name: "N'Ko standard QWERTY",
source: 'rules/nqo/nqo-standard-qwerty.js'
},
'nqo-transliteration': {
name: "N'Ko transliteration",
source: 'rules/nqo/nqo-transliteration.js'
},
'nso-tilde': {
name: 'Sesotho sa Leboa tilde',
source: 'rules/nso/nso-tilde.js'
},
'nus-tilde': {
name: 'Thok Naath tilde',
source: 'rules/nus/nus-tilde.js'
},
'ny-tilde': {
name: 'Chichewa / Nyanja tilde',
source: 'rules/ny/ny-tilde.js'
},
'or-inscript': {
name: 'ଇନସ୍କ୍ରିପ୍ଟ',
source: 'rules/or/or-inscript.js'
},
'or-inscript2': {
name: 'ଇନସ୍କ୍ରିପ୍ଟ2',
source: 'rules/or/or-inscript2.js'
},
'or-lekhani': {
name: 'ଲେଖନୀ',
source: 'rules/or/or-lekhani.js'
},
'or-OdiScript': {
name: 'ଓଡ଼ିସ୍କ୍ରିପ୍ଟ',
source: 'rules/or/or-OdiScript.js'
},
'or-phonetic': {
name: 'ଫୋନେଟିକ',
source: 'rules/or/or-phonetic.js'
},
'or-transliteration': {
name: 'ଟ୍ରାନ୍ସଲିଟରେସନ',
source: 'rules/or/or-transliteration.js'
},
'pa-inscript': {
name: 'ਇਨਸਕ੍ਰਿਪਟ',
source: 'rules/pa/pa-inscript.js'
},
'pa-inscript2': {
name: 'ਇਨਸਕ੍ਰਿਪਟ2',
source: 'rules/pa/pa-inscript2.js'
},
'pa-jhelum': {
name: 'ਜੇਹਲਮ',
source: 'rules/pa/pa-jhelum.js'
},
'pa-transliteration': {
name: 'ਲਿਪਾਂਤਰਨ',
source: 'rules/pa/pa-transliteration.js'
},
'pa-phonetic': {
name: 'ਫੋਨੇਟਿਕ',
source: 'rules/pa/pa-phonetic.js'
},
'phagspa': {
name: 'PhagsPa',
source: 'rules/mn/phagspa.js'
},
'pms': {
name: 'Piemontèis',
source: 'rules/pms/pms.js'
},
'roa-tara-GVU': {
name: 'Tarandine',
source: 'rules/roa-tara/roa-tara.js'
},
'ru-jcuken': {
name: 'ЙЦУКЕН',
source: 'rules/ru/ru-jcuken.js'
},
'ru-kbd': {
name: 'кбд',
source: 'rules/ru/ru-kbd.js'
},
'ru-phonetic': {
name: 'фонетический',
source: 'rules/ru/ru-phonetic.js'
},
'ru-yawerty': {
name: 'yawerty',
source: 'rules/ru/ru-yawerty.js'
},
'sa-iast': {
name: 'Romanized',
source: 'rules/sa/sa-iast.js'
},
'sa-inscript': {
name: 'इनस्क्रिप्ट',
source: 'rules/sa/sa-inscript.js'
},
'sa-inscript2': {
name: 'इनस्क्रिप्ट २',
source: 'rules/sa/sa-inscript2.js'
},
'sa-transliteration': {
name: 'लिप्यन्तरणम्',
source: 'rules/sa/sa-transliteration.js'
},
'sah-transliteration': {
name: 'Transliteration',
source: 'rules/sah/sah-transliteration.js'
},
'sat-inscript2': {
name: 'इनस्क्रिप्ट २',
source: 'rules/sat/sat-inscript2.js'
},
'sat-inscript2-ol-chiki': {
name: 'inscript2 ᱚᱞ ᱪᱤᱠᱤ',
source: 'rules/sat/sat-inscript2-ol-chiki.js'
},
'sat-sarjom-baha': {
name: 'sarjom baha',
source: 'rules/sat/sat-sarjom-baha.js'
},
'sd-inscript2': {
name: 'इनस्क्रिप्ट २',
source: 'rules/sd/sd-inscript2.js'
},
'sdh-kbd': {
name: 'کوردی خوارگ',
source: 'rules/sdh/sdh-kbd.js'
},
'se-normforms': {
name: 'Normal forms',
source: 'rules/se/se-normforms.js'
},
'ses-tilde': {
name: 'Koyraboro Senni tilde',
source: 'rules/ses/ses-tilde.js'
},
'sg-tilde': {
name: 'Sängö',
source: 'rules/sg/sg-tilde.js'
},
'si-singlish': {
name: 'සිංග්ලිෂ්',
source: 'rules/si/si-singlish.js'
},
'si-wijesekara': {
name: 'විජේසේකර',
source: 'rules/si/si-wijesekara.js'
},
'sjo': {
name: 'ᠰᡞᠪᡝ',
source: 'rules/sjo/sjo.js'
},
'sk-kbd': {
name: 'Štandardná',
source: 'rules/sk/sk-kbd.js'
},
'sr-kbd': {
name: 'Стандардна',
source: 'rules/sr/sr-kbd.js'
},
'st-tilde': {
name: 'Sesotho tilde',
source: 'rules/st/st-tilde.js'
},
'sv-normforms': {
name: 'Normal forms',
source: 'rules/sv/sv-normforms.js'
},
'ta-99': {
name: 'தமிழ்99',
source: 'rules/ta/ta-99.js'
},
'ta-bamini': {
name: 'பாமினி',
source: 'rules/ta/ta-bamini.js'
},
'ta-inscript': {
name: 'இன்ஸ்கிரிப்ட்',
source: 'rules/ta/ta-inscript.js'
},
'ta-inscript2': {
name: 'இன்ஸ்கிரிப்ட் 2',
source: 'rules/ta/ta-inscript2.js'
},
'ta-transliteration': {
name: 'எழுத்துப்பெயர்ப்பு',
source: 'rules/ta/ta-transliteration.js'
},
'te-apple': {
name: 'ఆపిల్',
source: 'rules/te/te-apple.js'
},
'te-inscript': {
name: 'ఇన్\u200dస్క్రిప్ట్',
source: 'rules/te/te-inscript.js'
},
'te-inscript2': {
name: 'ఇన్\u200dస్క్రిప్ట్ 2',
source: 'rules/te/te-inscript2.js'
},
'te-modular': {
name: 'మాడ్యులర్',
source: 'rules/te/te-modular.js'
},
'te-transliteration': {
name: 'లిప్యంతరీకరణ',
source: 'rules/te/te-transliteration.js'
},
'th-kedmanee': {
name: 'เกษมณี',
source: 'rules/th/th-kedmanee.js'
},
'th-pattachote': {
name: 'ปัตตะโชติ',
source: 'rules/th/th-pattachote.js'
},
'ti-geezim': {
name: 'ትግርኛ',
source: 'rules/ti/ti-geezim.js'
},
'tig-geezim': {
name: 'ትግረ',
source: 'rules/tig/tig-geezim.js'
},
'tum-tilde': {
name: 'ChiTumbuka tilde',
source: 'rules/tum/tum-tilde.js'
},
'udm-alt': {
name: 'Удмурт ALT',
source: 'rules/udm/udm-alt.js'
},
'ug-kbd': {
name: 'Uyghur kbd',
source: 'rules/ug/ug-kbd.js'
},
'uk-kbd': {
name: 'кбд',
source: 'rules/uk/uk-kbd.js'
},
'ur-phonetic': {
name: 'صوتی',
source: 'rules/ur/ur-phonetic.js'
},
'ur-transliteration': {
name: 'ٹرانسلٹریشن',
source: 'rules/ur/ur-transliteration.js'
},
'uz-kbd': {
name: 'Uzbek kbd',
source: 'rules/uz/uz-kbd.js'
},
've-tilde': {
name: 'TshiVenḓa tilde',
source: 'rules/ve/ve-tilde.js'
},
'vai-transliteration': {
name: 'Vai transliteration',
source: 'rules/vai/vai-transliteration.js'
},
'vec-GVU': {
name: 'Vèneto',
source: 'rules/vec/vec-GVU.js'
},
'wo-alt': {
name: 'Wolof Alt',
source: 'rules/wo/wo-alt.js'
},
'wo-tilde': {
name: 'Wolof tilde',
source: 'rules/wo/wo-tilde.js'
},
'yo-alt': {
name: 'Yorùbá Alt',
source: 'rules/yo/yo-alt.js'
},
'yo-tilde': {
name: 'Yorùbá tilde',
source: 'rules/yo/yo-tilde.js'
},
'zh-pinyin-transliteration': {
name: '拼音符号输入法',
source: 'rules/zh/zh-pinyin-transliteration.js'
}
} );
/* eslint-disable quote-props */
$.extend( $.ime.languages, {
ady: {
autonym: 'адыгэбзэ',
inputmethods: [ 'cyrl-palochka' ]
},
af: {
autonym: 'Afrikaans',
inputmethods: [ 'af-tilde' ]
},
ahr: {
autonym: 'अहिराणी',
inputmethods: [ 'mr-transliteration', 'mr-inscript' ]
},
ajg: {
autonym: 'ajagbe',
inputmethods: [ 'ajg-tilde' ]
},
ak: {
autonym: 'Akan',
inputmethods: [ 'ak-qx', 'ak-tilde' ]
},
am: {
autonym: 'አማርኛ',
inputmethods: [ 'am-transliteration' ]
},
ann: {
autonym: 'Obolo',
inputmethods: [ 'ann-tilde' ]
},
ar: {
autonym: 'العربية',
inputmethods: [ 'ar-kbd' ]
},
as: {
autonym: 'অসমীয়া',
inputmethods: [ 'as-transliteration', 'as-avro', 'as-bornona', 'as-inscript', 'as-phonetic', 'as-inscript2', 'as-rodali' ]
},
av: {
autonym: 'авар',
inputmethods: [ 'cyrl-palochka' ]
},
azb: {
autonym: 'تۆرکجه',
inputmethods: [ 'azb-kbd' ]
},
bas: {
autonym: 'ɓasaá',
inputmethods: [ 'bas-tilde', 'mul-cm' ]
},
bbc: {
autonym: 'Batak',
inputmethods: [ 'batak-qwerty' ]
},
bci: {
autonym: 'wawle',
inputmethods: [ 'bci-tilde' ]
},
be: {
autonym: 'беларуская',
inputmethods: [ 'be-transliteration', 'be-latin', 'be-kbd' ]
},
'be-tarask': {
autonym: 'беларуская (тарашкевіца)',
inputmethods: [ 'be-transliteration', 'be-latin' ]
},
bh: {
autonym: 'भोजपुरी',
inputmethods: [ 'hi-transliteration' ]
},
bgn: {
autonym: 'روچ کپتین بلوچی',
inputmethods: [ 'bgn-kbd' ]
},
bho: {
autonym: 'भोजपुरी',
inputmethods: [ 'hi-transliteration' ]
},
bkm: {
autonym: 'Itaŋikom',
inputmethods: [ 'bkm-tilde', 'mul-cm' ]
},
bm: {
autonym: 'Bamanankan',
inputmethods: [ 'bm-alt', 'bm-tilde' ]
},
bn: {
autonym: 'বাংলা',
inputmethods: [ 'bn-avro', 'bn-inscript', 'bn-nkb', 'bn-probhat', 'bn-inscript2' ]
},
bo: {
autonym: 'བོད་ཡིག།',
inputmethods: [ 'bo-ewts', 'bo-sambhota' ]
},
brx: {
autonym: 'बोड़ो',
inputmethods: [ 'brx-inscript', 'brx-inscript2' ]
},
bum: {
autonym: 'bulu',
inputmethods: [ 'mul-cm' ]
},
bwr: {
autonym: 'bura',
inputmethods: [ 'bwr-tilde' ]
},
byn: {
autonym: 'ብሊን',
inputmethods: [ 'byn-geezim' ]
},
ce: {
autonym: 'нохчийн',
inputmethods: [ 'cyrl-palochka' ]
},
ckb: {
autonym: 'کوردی',
inputmethods: [ 'ckb-transliteration-arkbd', 'ckb-transliteration-fakbd', 'ckb-transliteration-lakbd' ]
},
cv: {
autonym: 'Чăвашла',
inputmethods: [ 'cv-cyr-altgr', 'cv-lat-altgr', 'cv-cyr-numbers' ]
},
da: {
autonym: 'Dansk',
inputmethods: [ 'da-normforms' ]
},
dag: {
autonym: 'Dagbani',
inputmethods: [ 'dag-alt', 'dag-tilde' ]
},
dar: {
autonym: 'дарган',
inputmethods: [ 'cyrl-palochka' ]
},
de: {
autonym: 'Deutsch',
inputmethods: [ 'de-transliteration' ]
},
din: {
autonym: 'Thuɔŋjäŋ',
inputmethods: [ 'din-fqsx', 'din-tilde' ]
},
diq: {
autonym: 'Kirdkî',
inputmethods: [ 'ku-h', 'ku-tr' ]
},
doi: {
autonym: 'डोगरी',
inputmethods: [ 'doi-inscript2' ]
},
en: {
autonym: 'English',
inputmethods: [ 'ipa-sil', 'ipa-x-sampa' ]
},
ee: {
autonym: ʋegbe',
inputmethods: [ 'ee-tilde' ]
},
efi: {
autonym: 'efịk',
inputmethods: [ 'efi-tilde' ]
},
el: {
autonym: 'Ελληνικά',
inputmethods: [ 'el-kbd' ]
},
eo: {
autonym: 'Esperanto',
inputmethods: [ 'eo-transliteration', 'eo-h', 'eo-h-f', 'eo-plena', 'eo-q', 'eo-vi', 'eo-x' ]
},
fa: {
autonym: 'فارسی',
inputmethods: [ 'fa-kbd' ]
},
fat: {
autonym: 'mfantse',
inputmethods: [ 'ak-qx', 'ak-tilde' ]
},
ff: {
autonym: 'Fulfulde',
inputmethods: [ 'ff-alt', 'ff-tilde' ]
},
fi: {
autonym: 'Suomi',
inputmethods: [ 'fi-transliteration' ]
},
fo: {
autonym: 'Føroyskt',
inputmethods: [ 'fo-normforms' ]
},
fon: {
autonym: 'Fon',
inputmethods: [ 'fon-tilde' ]
},
fonipa: {
autonym: 'International Phonetic Alphabet',
inputmethods: [ 'ipa-sil', 'ipa-x-sampa' ]
},
gaa: {
autonym: 'Ga',
inputmethods: [ 'gaa-cqx', 'gaa-tilde' ]
},
got: {
autonym: '𐌲𐌿𐍄𐌹𐍃𐌺𐌰 𐍂𐌰𐌶𐌳𐌰',
inputmethods: [ 'got-standard' ]
},
ha: {
autonym: 'Hausa',
inputmethods: [ 'ha-tilde' ]
},
ig: {
autonym: 'Igbo',
inputmethods: [ 'ig-tilde' ]
},
gom: {
autonym: 'गोंयची कोंकणी / Gõychi Konknni',
inputmethods: [ 'hi-transliteration', 'hi-inscript', 'gom-inscript2' ]
},
gu: {
autonym: 'ગુજરાતી',
inputmethods: [ 'gu-transliteration', 'gu-inscript', 'gu-inscript2', 'gu-phonetic' ]
},
gur: {
autonym: 'farefare',
inputmethods: [ 'gur-tilde' ]
},
he: {
autonym: 'עברית',
inputmethods: [ 'he-standard-2012-extonly', 'he-standard-2012' ]
},
hi: {
autonym: 'हिन्दी',
inputmethods: [ 'hi-transliteration', 'hi-inscript', 'hi-bolnagri', 'hi-phonetic', 'hi-inscript2' ]
},
hne: {
autonym: 'छत्तीसगढ़ी',
inputmethods: [ 'hi-transliteration' ]
},
hoc: {
autonym: '𑢹𑣉𑣉',
inputmethods: [ 'hoc-transliteration' ]
},
hr: {
autonym: 'Hrvatski',
inputmethods: [ 'hr-kbd' ]
},
hy: {
autonym: 'հայերեն',
inputmethods: [ 'hy-ephonetic', 'hy-typewriter', 'hy-ephoneticalt', 'hy-emslegacy', 'hy-wmslegacy' ]
},
inh: {
autonym: 'гӀалгӀай',
inputmethods: [ 'cyrl-palochka' ]
},
is: {
autonym: 'Íslenska',
inputmethods: [ 'is-normforms' ]
},
jv: {
autonym: 'ꦧꦱꦗꦮ',
inputmethods: [ 'jv-transliteration' ]
},
ka: {
autonym: 'ქართული ენა',
inputmethods: [ 'ka-transliteration', 'ka-kbd' ]
},
kab: {
autonym: 'Taqbaylit / ⵜⴰⵇⴱⴰⵢⵍⵉⵜ',
inputmethods: [ 'kab-tilde', 'ber-tfng' ]
},
kbd: {
autonym: 'адыгэбзэ (къэбэрдеибзэ)',
inputmethods: [ 'cyrl-palochka' ]
},
kbp: {
autonym: 'Kabɩyɛ',
inputmethods: [ 'kbp-tilde' ]
},
kcg: {
autonym: 'Tyap',
inputmethods: [ 'kcg-tilde' ]
},
ken: {
autonym: 'kɛ́nyáŋ',
inputmethods: [ 'mul-cm' ]
},
ki: {
autonym: 'Gĩkũyũ',
inputmethods: [ 'ki-tilde' ]
},
kk: {
autonym: 'Қазақша',
inputmethods: [ 'kk-kbd', 'kk-arabic' ]
},
km: {
autonym: 'ភាសា​ខ្មែរ',
inputmethods: [ 'km-nidakyk' ]
},
kn: {
autonym: 'ಕನ್ನಡ',
inputmethods: [ 'kn-transliteration', 'kn-inscript', 'kn-kgp', 'kn-inscript2' ]
},
kr: {
autonym: 'kanuri',
inputmethods: [ 'kr-tilde' ]
},
ks: {
autonym: 'कॉशुर / کٲشُر',
inputmethods: [ 'ks-inscript', 'ks-kbd' ]
},
ky: {
autonym: 'Кыргыз',
inputmethods: [ 'ky-cyrl-alt' ]
},
ku: {
autonym: 'Kurdî',
inputmethods: [ 'ku-h', 'ku-tr' ]
},
lbe: {
autonym: 'лакку',
inputmethods: [ 'cyrl-palochka' ]
},
lez: {
autonym: 'лезги',
inputmethods: [ 'cyrl-palochka' ]
},
lg: {
autonym: 'Luganda',
inputmethods: [ 'lg-tilde' ]
},
ln: {
autonym: 'Lingála',
inputmethods: [ 'ln-tilde' ]
},
lo: {
autonym: 'ລາວ',
inputmethods: [ 'lo-kbd' ]
},
lrc: {
autonym: 'لۊری شومالی',
inputmethods: [ 'lrc-kbd' ]
},
lud: {
autonym: 'lüüdi',
inputmethods: [ 'lud-transliteration' ]
},
lut: {
autonym: 'dxʷləšucid',
inputmethods: [ 'lut-tulalip' ]
},
mai: {
autonym: 'मैथिली',
inputmethods: [ 'mai-inscript', 'mai-inscript2' ]
},
mad: {
autonym: 'madhurâ',
inputmethods: [ 'mad-tilde' ]
},
mg: {
autonym: 'Malagasy',
inputmethods: [ 'mg-tilde' ]
},
mh: {
autonym: 'Kajin M̧ajeļ',
inputmethods: [ 'mh' ]
},
ml: {
autonym: 'മലയാളം',
inputmethods: [ 'ml-transliteration', 'ml-inscript', 'ml-inscript2' ]
},
mn: {
autonym: 'Монгол',
inputmethods: [ 'mn-cyrl', 'mn-trad', 'mn-todo', 'mn-tradali', 'mn-todoali', 'phagspa' ]
},
mnc: {
autonym: 'ᠮᠠᠨᠵᡠ',
inputmethods: [ 'mnc', 'mnc-ali' ]
},
mni: {
autonym: 'Manipuri',
inputmethods: [ 'mni-inscript2' ]
},
mnw: {
autonym: 'ဘာသာ မန်',
inputmethods: [ 'mnw-simplified-anonta' ]
},
mos: {
autonym: 'moore',
inputmethods: [ 'mul-bf' ]
},
mr: {
autonym: 'मराठी',
inputmethods: [ 'mr-transliteration', 'mr-inscript2', 'mr-inscript', 'mr-phonetic' ]
},
my: {
autonym: 'မြန်မာ',
inputmethods: [ 'my-mm3', 'my-xkb' ]
},
nb: {
autonym: 'Norsk (bokmål)',
inputmethods: [ 'nb-normforms', 'nb-tildeforms' ]
},
ne: {
autonym: 'नेपाली',
inputmethods: [ 'ne-transliteration', 'ne-inscript2', 'ne-inscript', 'ne-rom', 'ne-trad' ]
},
'new': {
autonym: 'नेपाल भाषा',
inputmethods: [ 'hi-transliteration', 'hi-inscript' ]
},
nia: {
autonym: 'li niha',
inputmethods: [ 'nia-tilde' ]
},
nmz: {
autonym: 'nawdm',
inputmethods: [ 'nmz-tilde' ]
},
nn: {
autonym: 'Norsk (nynorsk)',
inputmethods: [ 'nb-normforms', 'nb-tildeforms' ]
},
nqo: {
autonym: 'ߒߞߏ',
inputmethods: [ 'nqo-standard-qwerty', 'nqo-transliteration' ]
},
nso: {
autonym: 'Sesotho sa Leboa',
inputmethods: [ 'nso-tilde' ]
},
nus: {
autonym: 'Thok Naath',
inputmethods: [ 'nus-tilde' ]
},
ny: {
autonym: 'Chichewa',
inputmethods: [ 'ny-tilde' ]
},
or: {
autonym: 'ଓଡ଼ିଆ',
inputmethods: [ 'or-phonetic', 'or-transliteration', 'or-inscript', 'or-inscript2', 'or-lekhani', 'or-OdiScript' ]
},
pa: {
autonym: 'ਪੰਜਾਬੀ',
inputmethods: [ 'pa-transliteration', 'pa-inscript', 'pa-phonetic', 'pa-inscript2', 'pa-jhelum' ]
},
pms: {
autonym: 'Piemontèis',
inputmethods: [ 'pms' ]
},
rif: {
autonym: 'ⵜⴰⵔⵉⴼⵉⵜ',
inputmethods: [ 'ber-tfng' ]
},
'roa-tara': {
autonym: 'Tarandine',
inputmethods: [ 'roa-tara-GVU' ]
},
ru: {
autonym: 'русский',
inputmethods: [ 'ru-jcuken', 'ru-kbd', 'ru-phonetic', 'ru-yawerty' ]
},
sa: {
autonym: 'संस्कृत',
inputmethods: [ 'sa-transliteration', 'sa-inscript2', 'sa-inscript', 'sa-iast' ]
},
sah: {
autonym: 'саха тыла',
inputmethods: [ 'sah-transliteration' ]
},
sat: {
autonym: 'ᱥᱟᱱᱛᱟᱞᱤ (संताली)',
inputmethods: [ 'sat-inscript2', 'sat-inscript2-ol-chiki', 'sat-sarjom-baha' ]
},
sd: {
autonym: 'सिंधी',
inputmethods: [ 'sd-inscript2' ]
},
sdh: {
autonym: 'کوردی خوارگ',
inputmethods: [ 'sdh-kbd' ]
},
se: {
autonym: 'Davvisámegiella',
inputmethods: [ 'se-normforms' ]
},
ses: {
autonym: 'Koyraboro Senni',
inputmethods: [ 'ses-tilde' ]
},
sg: {
autonym: 'Sängö',
inputmethods: [ 'sg-tilde' ]
},
shi: {
autonym: 'ⵜⴰⵛⵍⵃⵉⵜ',
inputmethods: [ 'ber-tfng' ]
},
si: {
autonym: 'සිංහල',
inputmethods: [ 'si-singlish', 'si-wijesekara' ]
},
sjo: {
autonym: 'ᠰᡞᠪᡝ',
inputmethods: [ 'sjo' ]
},
sk: {
autonym: 'Slovenčina',
inputmethods: [ 'sk-kbd' ]
},
sr: {
autonym: 'Српски / srpski',
inputmethods: [ 'sr-kbd' ]
},
st: {
autonym: 'Sesotho',
inputmethods: [ 'st-tilde' ]
},
sv: {
autonym: 'Svenska',
inputmethods: [ 'sv-normforms' ]
},
ta: {
autonym: 'தமிழ்',
inputmethods: [ 'ta-transliteration', 'ta-99', 'ta-inscript', 'ta-bamini', 'ta-inscript2' ]
},
tcy: {
autonym: 'ತುಳು',
inputmethods: [ 'kn-transliteration', 'kn-inscript', 'kn-kgp', 'kn-inscript2' ]
},
te: {
autonym: 'తెలుగు',
inputmethods: [ 'te-transliteration', 'te-inscript', 'te-inscript2', 'te-apple', 'te-modular' ]
},
th: {
autonym: 'ไทย',
inputmethods: [ 'th-kedmanee', 'th-pattachote' ]
},
ti: {
autonym: 'ትግርኛ',
inputmethods: [ 'ti-geezim' ]
},
tig: {
autonym: 'ትግረ',
inputmethods: [ 'tig-geezim' ]
},
tkr: {
autonym: 'цӀаӀхна миз',
inputmethods: [ 'cyrl-palochka' ]
},
tum: {
autonym: 'ChiTumbuka',
inputmethods: [ 'tum-tilde' ]
},
tw: {
autonym: 'Twi',
inputmethods: [ 'ak-qx', 'ak-tilde' ]
},
tzm: {
autonym: 'ⵜⴰⵎⴰⵣⵉⵖⵜ',
inputmethods: [ 'ber-tfng' ]
},
udm: {
autonym: 'удмурт',
inputmethods: [ 'udm-alt' ]
},
uk: {
autonym: 'Українська',
inputmethods: [ 'uk-kbd' ]
},
ug: {
autonym: 'ئۇيغۇرچە / Uyghurche',
inputmethods: [ 'ug-kbd' ]
},
ur: {
autonym: 'اردو',
inputmethods: [ 'ur-transliteration', 'ur-phonetic' ]
},
uz: {
autonym: 'Oʻzbekcha',
inputmethods: [ 'uz-kbd' ]
},
vai: {
autonym: 'ꕙꔤ',
inputmethods: [ 'vai-transliteration' ]
},
ve: {
autonym: 'TshiVenḓa',
inputmethods: [ 've-tilde' ]
},
vec: {
autonym: 'Vèneto',
inputmethods: [ 'vec-GVU' ]
},
wo: {
autonym: 'Wolof',
inputmethods: [ 'wo-alt', 'wo-tilde' ]
},
yo: {
autonym: 'Yorùbá',
inputmethods: [ 'yo-alt', 'yo-tilde' ]
},
zh: {
autonym: '中文',
inputmethods: [ 'zh-pinyin-transliteration' ]
}
} );
}( jQuery ) );