chromium/chrome/browser/resources/ash/settings/os_languages_page/input_method_util.ts

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview constants related to input method options.
 */

import {assert, assertNotReached} from 'chrome://resources/js/assert.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';

import {assertExhaustive} from '../assert_extras.js';
import {Route, routes} from '../router.js';

import {getInputMethodSettings, SettingsContext, SettingsType} from './input_method_settings.js';
import {JapaneseInputMode, JapaneseKeymapStyle, JapanesePunctuationStyle, JapaneseSectionShortcut, JapaneseShiftKeyModeStyle, JapaneseSpaceInputStyle, JapaneseSymbolStyle} from './input_method_types.js';

/**
 * The prefix string shared by all first party input method ID.
 */
export const FIRST_PARTY_INPUT_METHOD_ID_PREFIX =
    '_comp_ime_jkghodnilhceideoidjikpgommlajknk';

/**
 * The preference string used to indicate a user has autocorrect enabled by
 * default for a particular engine. See the following for more details
 * https://crsrc.org/chrome/browser/ash/input_method/autocorrect_prefs.cc
 */
export const PHYSICAL_KEYBOARD_AUTOCORRECT_ENABLED_BY_DEFAULT =
    'physicalKeyboardAutoCorrectionEnabledByDefault';

/**
 * All possible keyboard layouts. Should match Google3.
 */
enum KeyboardLayout {
  STANDARD = 'Default',
  GINYIEH = 'Gin Yieh',
  ETEN = 'Eten',
  IBM = 'IBM',
  HSU = 'Hsu',
  ETEN26 = 'Eten 26',
  SET2 = '2 Set / 두벌식',
  SET2Y = '2 Set (Old Hangul) / 두벌식 (옛글)',
  SET390 = '3 Set (390) / 세벌식 (390)',
  SET3_FINAL = '3 Set (Final) / 세벌식 (최종)',
  SET3_SUN = '3 Set (No Shift) / 세벌식 (순아래)',
  SET3_YET = '3 Set (Old Hangul) / 세벌식 (옛글)',
  XKB_US = 'US',
  XKB_DVORAK = 'Dvorak',
  XKB_COLEMAK = 'Colemak',
}

/**
 * All possible options on options pages. Should match Gooogle3.
 */
export enum OptionType {
  EDIT_USER_DICT = 'editUserDict',
  ENABLE_COMPLETION = 'enableCompletion',
  ENABLE_DOUBLE_SPACE_PERIOD = 'enableDoubleSpacePeriod',
  ENABLE_GESTURE_TYPING = 'enableGestureTyping',
  ENABLE_PREDICTION = 'enablePrediction',
  ENABLE_SOUND_ON_KEYPRESS = 'enableSoundOnKeypress',
  PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL =
      'physicalKeyboardAutoCorrectionLevel',
  PHYSICAL_KEYBOARD_ENABLE_CAPITALIZATION =
      'physicalKeyboardEnableCapitalization',
  PHYSICAL_KEYBOARD_ENABLE_PREDICTIVE_WRITING =
      'physicalKeyboardEnablePredictiveWriting',
  VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL = 'virtualKeyboardAutoCorrectionLevel',
  VIRTUAL_KEYBOARD_ENABLE_CAPITALIZATION =
      'virtualKeyboardEnableCapitalization',
  XKB_LAYOUT = 'xkbLayout',
  // Options for Japanese input method.
  // LINT.IfChange(JpOptionCategories)
  JAPANESE_AUTOMATICALLY_SWITCH_TO_HALFWIDTH = 'AutomaticallySwitchToHalfwidth',
  JAPANESE_SHIFT_KEY_MODE_STYLE = 'ShiftKeyModeStyle',
  JAPANESE_USE_INPUT_HISTORY = 'UseInputHistory',
  JAPANESE_USE_SYSTEM_DICTIONARY = 'UseSystemDictionary',
  JAPANESE_NUMBER_OF_SUGGESTIONS = 'numberOfSuggestions',
  JAPANESE_INPUT_MODE = 'JapaneseInputMode',
  JAPANESE_PUNCTUATION_STYLE = 'JapanesePunctuationStyle',
  JAPANESE_SYMBOL_STYLE = 'JapaneseSymbolStyle',
  JAPANESE_SPACE_INPUT_STYLE = 'JapaneseSpaceInputStyle',
  JAPANESE_SECTION_SHORTCUT = 'JapaneseSectionShortcut',
  JAPANESE_KEYMAP_STYLE = 'JapaneseKeymapStyle',
  JAPANESE_MANAGE_USER_DICTIONARY = 'JapaneseManageUserDictionary',
  JAPANESE_DELETE_PERSONALIZATION_DATA = 'JapaneseClearPersonalizationData',
  JAPANESE_DISABLE_PERSONALIZED_SUGGESTIONS = 'JapaneseDisableSuggestions',
  JAPANESE_AUTOMATICALLY_SEND_STATISTICS_TO_GOOGLE =
      'AutomaticallySendStatisticsToGoogle',
  // LINT.ThenChange(/chrome/browser/ash/input_method/japanese/japanese_prefs_constants.h:JpOptionCategories)
  // Options for Korean input method.
  KOREAN_ENABLE_SYLLABLE_INPUT = 'koreanEnableSyllableInput',
  KOREAN_KEYBOARD_LAYOUT = 'koreanKeyboardLayout',
  // Options for pinyin input method.
  PINYIN_CHINESE_PUNCTUATION = 'pinyinChinesePunctuation',
  PINYIN_DEFAULT_CHINESE = 'pinyinDefaultChinese',
  PINYIN_ENABLE_FUZZY = 'pinyinEnableFuzzy',
  PINYIN_ENABLE_LOWER_PAGING = 'pinyinEnableLowerPaging',
  PINYIN_ENABLE_UPPER_PAGING = 'pinyinEnableUpperPaging',
  PINYIN_FULL_WIDTH_CHARACTER = 'pinyinFullWidthCharacter',
  PINYIN_FUZZY_CONFIG = 'pinyinFuzzyConfig',
  PINYIN_EN_ENG = 'en:eng',
  PINYIN_AN_ANG = 'an:ang',
  PINYIN_IAN_IANG = 'ian:iang',
  PINYIN_K_G = 'k:g',
  PINYIN_R_L = 'r:l',
  PINYIN_UAN_UANG = 'uan:uang',
  PINYIN_C_CH = 'c:ch',
  PINYIN_F_H = 'f:h',
  PINYIN_IN_ING = 'in:ing',
  PINYIN_L_N = 'l:n',
  PINYIN_S_SH = 's:sh',
  PINYIN_Z_ZH = 'z:zh',
  // Options for zhuyin input method.
  ZHUYIN_KEYBOARD_LAYOUT = 'zhuyinKeyboardLayout',
  ZHUYIN_PAGE_SIZE = 'zhuyinPageSize',
  ZHUYIN_SELECT_KEYS = 'zhuyinSelectKeys',
  // Options for Vietnamese VNI input method
  VIETNAMESE_VNI_ALLOW_FLEXIBLE_DIACRITICS =
      'vietnameseVniAllowFlexibleDiacritics',
  VIETNAMESE_VNI_NEW_STYLE_TONE_MARK_PLACEMENT =
      'vietnameseVniNewStyleToneMarkPlacement',
  VIETNAMESE_VNI_INSERT_DOUBLE_HORN_ON_UO = 'vietnameseVniInsertDoubleHornOnUo',
  VIETNAMESE_VNI_SHOW_UNDERLINE = 'vietnameseVniShowUnderline',
  VIETNAMESE_TELEX_ALLOW_FLEXIBLE_DIACRITICS =
      'vietnameseTelexAllowFlexibleDiacritics',
  VIETNAMESE_TELEX_NEW_STYLE_TONE_MARK_PLACEMENT =
      'vietnameseTelexNewStyleToneMarkPlacement',
  VIETNAMESE_TELEX_INSERT_DOUBLE_HORN_ON_UO =
      'vietnameseTelexInsertDoubleHornOnUo',
  VIETNAMESE_TELEX_INSERT_U_HORN_ON_W = 'vietnameseTelexInsertUHornOnW',
  VIETNAMESE_TELEX_SHOW_UNDERLINE = 'vietnameseTelexShowUnderline',
}

/**
 * Default values for each option type.
 *
 * WARNING: Keep this in sync with corresponding Google3 file for extension.
 */
export const OPTION_DEFAULT = {
  [OptionType.ENABLE_COMPLETION]: false,
  [OptionType.ENABLE_DOUBLE_SPACE_PERIOD]: true,
  [OptionType.ENABLE_GESTURE_TYPING]: true,
  [OptionType.ENABLE_PREDICTION]: false,
  [OptionType.ENABLE_SOUND_ON_KEYPRESS]: false,
  [OptionType.JAPANESE_NUMBER_OF_SUGGESTIONS]: 3,
  [OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL]: 0,
  [OptionType.PHYSICAL_KEYBOARD_ENABLE_CAPITALIZATION]: true,
  [OptionType.PHYSICAL_KEYBOARD_ENABLE_PREDICTIVE_WRITING]: true,
  [OptionType.VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL]: 1,
  [OptionType.VIRTUAL_KEYBOARD_ENABLE_CAPITALIZATION]: true,
  [OptionType.XKB_LAYOUT]: 'US',
  // Options for Japanese input methods.
  // LINT.IfChange(JpPrefDefaults)
  [OptionType.JAPANESE_AUTOMATICALLY_SWITCH_TO_HALFWIDTH]: true,
  [OptionType.JAPANESE_SHIFT_KEY_MODE_STYLE]:
      JapaneseShiftKeyModeStyle.ALPHANUMERIC,
  [OptionType.JAPANESE_USE_INPUT_HISTORY]: true,
  [OptionType.JAPANESE_USE_SYSTEM_DICTIONARY]: true,
  [OptionType.JAPANESE_INPUT_MODE]: JapaneseInputMode.ROMAJI,
  [OptionType.JAPANESE_PUNCTUATION_STYLE]:
      JapanesePunctuationStyle.KUTEN_TOUTEN,
  [OptionType.JAPANESE_SYMBOL_STYLE]:
      JapaneseSymbolStyle.CORNER_BRACKET_MIDDLE_DOT,
  [OptionType.JAPANESE_SPACE_INPUT_STYLE]: JapaneseSpaceInputStyle.INPUT_MODE,
  [OptionType.JAPANESE_SECTION_SHORTCUT]:
      JapaneseSectionShortcut.DIGITS_123456789,
  [OptionType.JAPANESE_KEYMAP_STYLE]: JapaneseKeymapStyle.CUSTOM,
  [OptionType.JAPANESE_DISABLE_PERSONALIZED_SUGGESTIONS]: true,
  [OptionType.JAPANESE_AUTOMATICALLY_SEND_STATISTICS_TO_GOOGLE]: true,
  // LINT.ThenChange(/chrome/browser/ash/input_method/japanese/japanese_settings.cc:JpPrefDefaults)

  // Options for Korean input method.
  [OptionType.KOREAN_ENABLE_SYLLABLE_INPUT]: true,
  [OptionType.KOREAN_KEYBOARD_LAYOUT]: KeyboardLayout.SET2,
  // Options for pinyin input method.
  [OptionType.PINYIN_CHINESE_PUNCTUATION]: true,
  [OptionType.PINYIN_DEFAULT_CHINESE]: true,
  [OptionType.PINYIN_ENABLE_FUZZY]: false,
  [OptionType.PINYIN_ENABLE_LOWER_PAGING]: true,
  [OptionType.PINYIN_ENABLE_UPPER_PAGING]: true,
  [OptionType.PINYIN_FULL_WIDTH_CHARACTER]: false,
  [OptionType.PINYIN_FUZZY_CONFIG]: {
    an_ang: undefined,
    c_ch: undefined,
    en_eng: undefined,
    f_h: undefined,
    ian_iang: undefined,
    in_ing: undefined,
    k_g: undefined,
    l_n: undefined,
    r_l: undefined,
    s_sh: undefined,
    uan_uang: undefined,
    z_zh: undefined,
  },
  // Options for zhuyin input method.
  [OptionType.ZHUYIN_KEYBOARD_LAYOUT]: KeyboardLayout.STANDARD,
  [OptionType.ZHUYIN_PAGE_SIZE]: '10',
  [OptionType.ZHUYIN_SELECT_KEYS]: '1234567890',
  // Options for Vietnamese inputs.
  [OptionType.VIETNAMESE_VNI_ALLOW_FLEXIBLE_DIACRITICS]: true,
  [OptionType.VIETNAMESE_VNI_NEW_STYLE_TONE_MARK_PLACEMENT]: false,
  [OptionType.VIETNAMESE_VNI_INSERT_DOUBLE_HORN_ON_UO]: false,
  [OptionType.VIETNAMESE_VNI_SHOW_UNDERLINE]: true,
  [OptionType.VIETNAMESE_TELEX_ALLOW_FLEXIBLE_DIACRITICS]: true,
  [OptionType.VIETNAMESE_TELEX_NEW_STYLE_TONE_MARK_PLACEMENT]: false,
  [OptionType.VIETNAMESE_TELEX_INSERT_DOUBLE_HORN_ON_UO]: false,
  [OptionType.VIETNAMESE_TELEX_INSERT_U_HORN_ON_W]: true,
  [OptionType.VIETNAMESE_TELEX_SHOW_UNDERLINE]: true,
} satisfies Partial<Record<OptionType, unknown>>;

/**
 * @param optionName The option we want the default value for.
 * @param overrides List of values to use instead of the default values.
 * @return The default, or overridden value.
 */
export function getDefaultValue<T extends keyof typeof OPTION_DEFAULT>(
    optionName: T, overrides: {[K in T]?: (typeof OPTION_DEFAULT)[K]}):
    (typeof OPTION_DEFAULT)[T] {
  // Overrides are only coming from the following flag, let's be safe here and
  // only enable this branch if the flag is also enabled.
  if (!loadTimeData.getBoolean('autocorrectEnableByDefault')) {
    return OPTION_DEFAULT[optionName];
  }
  return overrides[optionName] ?? OPTION_DEFAULT[optionName];
}

/**
 * Type conversions functions for reading and writing options.  Use these for
 * reading and writing pref values when we don't want the default mappings. This
 * is only used if allow autocorrect toggle is on.
 */
export const AUTOCORRECT_OPTION_MAP_OVERRIDE = {
  [OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL]: {
    mapValueForDisplay: (value: number): boolean => value > 0 ? true : false,
    mapValueForWrite: (value: boolean): 1 | 0 => value ? 1 : 0,
  },
  [OptionType.VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL]: {
    mapValueForDisplay: (value: number): boolean => value > 0 ? true : false,
    mapValueForWrite: (value: boolean): 1 | 0 => value ? 1 : 0,
  },
};

/**
 * All possible UI elements for options.
 */
export enum UiType {
  DROPDOWN = 'dropdown',
  LINK = 'link',
  SUBMENU_BUTTON = 'submenuButton',
  TOGGLE_BUTTON = 'toggleButton',
}

/**
 * All possible submenu button types.
 */
export enum SubmenuButton {
  JAPANESE_DELETE_PERSONALIZATION_DATA = 'SubmenuButtonDeletePersonalizedData',
}

/**
 * All possible Settings headers
 */
export enum SettingsHeaders {
  ADVANCED = 'advanced',
  BASIC = 'basic',
  INPUT_ASSISTANCE = 'inputAssistance',
  PHYSICAL_KEYBOARD = 'physicalKeyboard',
  PRIVACY = 'privacy',
  SUGGESTIONS = 'suggestions',
  USER_DICTIONARIES = 'userDictionaries',
  VIRTUAL_KEYBOARD = 'virtualKeyboard',
  VIETNAMESE_FLEXIBLE_TYPING_EMPTY_HEADER =
      'vietnameseFlexibleTypingEmptyHeader',
  VIETNAMESE_SHORTHAND = 'vietnameseShorthand',
  VIETNAMESE_SHOW_UNDERLINE_EMPTY_HEADER = 'vietnameseShowUnderlineEmptyHeader',
}

/**
 * Contents of the settings page for different settings types.
 * These should be in the order they are expected to appear in
 * the actual settings pages.
 */
const Settings = {
  [SettingsType.LATIN_SETTINGS]: [
    {
      title: SettingsHeaders.VIRTUAL_KEYBOARD,
      optionNames: [
        {name: OptionType.ENABLE_SOUND_ON_KEYPRESS},
        {
          name: OptionType.VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL,
          dependentOptions: [
            OptionType.VIRTUAL_KEYBOARD_ENABLE_CAPITALIZATION,
          ],
        },
        {name: OptionType.ENABLE_GESTURE_TYPING},
        {name: OptionType.ENABLE_DOUBLE_SPACE_PERIOD},
        {name: OptionType.EDIT_USER_DICT},
      ],
    },
  ],
  [SettingsType.JAPANESE_SETTINGS]: [
    {
      title: SettingsHeaders.BASIC,
      optionNames: [
        {name: OptionType.JAPANESE_INPUT_MODE},
        {name: OptionType.JAPANESE_PUNCTUATION_STYLE},
        {name: OptionType.JAPANESE_SYMBOL_STYLE},
        {name: OptionType.JAPANESE_SPACE_INPUT_STYLE},
        {name: OptionType.JAPANESE_SECTION_SHORTCUT},
        {name: OptionType.JAPANESE_KEYMAP_STYLE},
      ],
    },
    {
      title: SettingsHeaders.INPUT_ASSISTANCE,
      optionNames: [
        {name: OptionType.JAPANESE_AUTOMATICALLY_SWITCH_TO_HALFWIDTH},
        {name: OptionType.JAPANESE_SHIFT_KEY_MODE_STYLE},
      ],
    },
    {
      title: SettingsHeaders.SUGGESTIONS,
      optionNames: [
        {name: OptionType.JAPANESE_USE_INPUT_HISTORY},
        {name: OptionType.JAPANESE_USE_SYSTEM_DICTIONARY},
        {name: OptionType.JAPANESE_NUMBER_OF_SUGGESTIONS},
      ],
    },
    {
      title: SettingsHeaders.USER_DICTIONARIES,
      optionNames: [{
        name: OptionType.JAPANESE_MANAGE_USER_DICTIONARY,
      }],
    },
    {
      title: SettingsHeaders.PRIVACY,
      optionNames: [
        {name: OptionType.JAPANESE_DELETE_PERSONALIZATION_DATA},
        {name: OptionType.JAPANESE_DISABLE_PERSONALIZED_SUGGESTIONS},
        {name: OptionType.JAPANESE_AUTOMATICALLY_SEND_STATISTICS_TO_GOOGLE},
      ],
    },
  ],
  [SettingsType.ZHUYIN_SETTINGS]: [{
    title: SettingsHeaders.PHYSICAL_KEYBOARD,
    optionNames: [
      {name: OptionType.ZHUYIN_KEYBOARD_LAYOUT},
      {name: OptionType.ZHUYIN_SELECT_KEYS},
      {name: OptionType.ZHUYIN_PAGE_SIZE},
    ],
  }],
  [SettingsType.KOREAN_SETTINGS]: [{
    title: SettingsHeaders.BASIC,
    optionNames: [
      {name: OptionType.KOREAN_KEYBOARD_LAYOUT},
      {name: OptionType.KOREAN_ENABLE_SYLLABLE_INPUT},
    ],
  }],
  [SettingsType.PINYIN_FUZZY_SETTINGS]: [{
    title: SettingsHeaders.ADVANCED,
    optionNames: [{
      name: OptionType.PINYIN_ENABLE_FUZZY,
      dependentOptions: [
        OptionType.PINYIN_AN_ANG,
        OptionType.PINYIN_EN_ENG,
        OptionType.PINYIN_IAN_IANG,
        OptionType.PINYIN_K_G,
        OptionType.PINYIN_R_L,
        OptionType.PINYIN_UAN_UANG,
        OptionType.PINYIN_C_CH,
        OptionType.PINYIN_F_H,
        OptionType.PINYIN_IN_ING,
        OptionType.PINYIN_L_N,
        OptionType.PINYIN_S_SH,
        OptionType.PINYIN_Z_ZH,
      ],
    }],
  }],
  [SettingsType.PINYIN_SETTINGS]: [
    {
      title: SettingsHeaders.ADVANCED,
      optionNames: [{name: OptionType.EDIT_USER_DICT}],
    },
    {
      title: SettingsHeaders.PHYSICAL_KEYBOARD,
      optionNames: [
        {name: OptionType.XKB_LAYOUT},
        {name: OptionType.PINYIN_ENABLE_UPPER_PAGING},
        {name: OptionType.PINYIN_ENABLE_LOWER_PAGING},
        {name: OptionType.PINYIN_DEFAULT_CHINESE},
        {name: OptionType.PINYIN_FULL_WIDTH_CHARACTER},
        {name: OptionType.PINYIN_CHINESE_PUNCTUATION},
      ],
    },
  ],
  [SettingsType.BASIC_SETTINGS]: [{
    title: SettingsHeaders.VIRTUAL_KEYBOARD,
    optionNames: [
      {name: OptionType.ENABLE_SOUND_ON_KEYPRESS},
    ],
  }],
  [SettingsType.ENGLISH_BASIC_WITH_AUTOSHIFT_SETTINGS]: [{
    title: SettingsHeaders.VIRTUAL_KEYBOARD,
    optionNames: [
      {name: OptionType.ENABLE_SOUND_ON_KEYPRESS},
      {name: OptionType.VIRTUAL_KEYBOARD_ENABLE_CAPITALIZATION},
    ],
  }],
  [SettingsType.SUGGESTION_SETTINGS]: [{
    title: SettingsHeaders.SUGGESTIONS,
    optionNames:
        [{name: OptionType.PHYSICAL_KEYBOARD_ENABLE_PREDICTIVE_WRITING}],
  }],
  [SettingsType.LATIN_PHYSICAL_KEYBOARD_SETTINGS]: [{
    title: SettingsHeaders.PHYSICAL_KEYBOARD,
    optionNames: [{
      name: OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL,
    }],
  }],
  [SettingsType.VIETNAMESE_TELEX_SETTINGS]: [
    {
      title: SettingsHeaders.VIETNAMESE_FLEXIBLE_TYPING_EMPTY_HEADER,
      optionNames: [
        {
          name: OptionType.VIETNAMESE_TELEX_ALLOW_FLEXIBLE_DIACRITICS,
          dependentOptions: [
            OptionType.VIETNAMESE_TELEX_NEW_STYLE_TONE_MARK_PLACEMENT,
          ],
        },
      ],
    },
    {
      title: SettingsHeaders.VIETNAMESE_SHORTHAND,
      optionNames: [
        {name: OptionType.VIETNAMESE_TELEX_INSERT_DOUBLE_HORN_ON_UO},
        {name: OptionType.VIETNAMESE_TELEX_INSERT_U_HORN_ON_W},
      ],
    },
    {
      title: SettingsHeaders.VIETNAMESE_SHOW_UNDERLINE_EMPTY_HEADER,
      optionNames: [
        {name: OptionType.VIETNAMESE_TELEX_SHOW_UNDERLINE},
      ],
    },
  ],
  [SettingsType.VIETNAMESE_VNI_SETTINGS]: [
    {
      title: SettingsHeaders.VIETNAMESE_FLEXIBLE_TYPING_EMPTY_HEADER,
      optionNames: [
        {
          name: OptionType.VIETNAMESE_VNI_ALLOW_FLEXIBLE_DIACRITICS,
          dependentOptions: [
            OptionType.VIETNAMESE_VNI_NEW_STYLE_TONE_MARK_PLACEMENT,
          ],
        },
      ],
    },
    {
      title: SettingsHeaders.VIETNAMESE_SHORTHAND,
      optionNames: [
        {name: OptionType.VIETNAMESE_VNI_INSERT_DOUBLE_HORN_ON_UO},
      ],
    },
    {
      title: SettingsHeaders.VIETNAMESE_SHOW_UNDERLINE_EMPTY_HEADER,
      optionNames: [
        {name: OptionType.VIETNAMESE_VNI_SHOW_UNDERLINE},
      ],
    },
  ],
} satisfies Record<SettingsType, Array<{
                     title: SettingsHeaders,
                     optionNames: Array<{
                       name: OptionType,
                       dependentOptions?: OptionType[],
                     }>,
                   }>>;

/**
 * @param id A first party input method ID.
 * @return The corresponding engind ID of the input method.
 */
export function getFirstPartyInputMethodEngineId(id: string): string {
  // Safety: Enforced by documentation.
  assert(isFirstPartyInputMethodId(id));
  return id.substring(FIRST_PARTY_INPUT_METHOD_ID_PREFIX.length);
}

/**
 * @param id Input method ID.
 * @return true if the input method's options page is implemented.
 */
export function hasOptionsPageInSettings(
    id: string, context: SettingsContext): boolean {
  if (!isFirstPartyInputMethodId(id)) {
    return false;
  }
  const engineId = getFirstPartyInputMethodEngineId(id);
  const inputMethodSettings = getInputMethodSettings(context);
  return !!inputMethodSettings[engineId];
}

/**
 * Generates options to be displayed in the options page, grouped by sections.
 * @param engineId Input method engine ID.
 * @return the options to be displayed.
 */
export function generateOptions(
    engineId: string, context: SettingsContext): Array<{
  title: SettingsHeaders,
  optionNames: Array<{name: OptionType, dependentOptions?: OptionType[]}>,
}> {
  const options: Array<{
    title: SettingsHeaders,
    optionNames: Array<{name: OptionType, dependentOptions?: OptionType[]}>,
  }> = [];
  const inputMethodSettings = getInputMethodSettings(context);
  const engineSettings = inputMethodSettings[engineId];
  if (engineSettings) {
    const pushedOptions = new Map<SettingsHeaders, number>();

    engineSettings.forEach((settingType) => {
      const settings = Settings[settingType];
      for (const {title, optionNames} of settings) {
        if (optionNames) {
          const optionsIndex = pushedOptions.get(title);
          if (optionsIndex === undefined) {
            pushedOptions.set(title, options.length);
            options.push({
              title,
              optionNames: [...optionNames],
            });
          } else {
            // Safety: `pushedOptions` values are always set to
            // `options.length`, and `options` is immediately pushed to, so the
            // values of `pushedOptions` must always be valid indices into
            // `options`.
            options[optionsIndex]!.optionNames.push(...optionNames);
          }
        }
      }
    });
  }

  return options;
}

/**
 * @param option The option type.
 * @return The UI type of |option|.
 */
export function getOptionUiType(option: OptionType): UiType {
  switch (option) {
    // TODO(b/191608723): Clean up switch statements.
    case OptionType.ENABLE_COMPLETION:
    case OptionType.ENABLE_DOUBLE_SPACE_PERIOD:
    case OptionType.ENABLE_GESTURE_TYPING:
    case OptionType.ENABLE_PREDICTION:
    case OptionType.ENABLE_SOUND_ON_KEYPRESS:
    case OptionType.JAPANESE_AUTOMATICALLY_SWITCH_TO_HALFWIDTH:
    case OptionType.JAPANESE_USE_SYSTEM_DICTIONARY:
    case OptionType.JAPANESE_USE_INPUT_HISTORY:
    case OptionType.JAPANESE_DISABLE_PERSONALIZED_SUGGESTIONS:
    case OptionType.JAPANESE_AUTOMATICALLY_SEND_STATISTICS_TO_GOOGLE:
    case OptionType.PHYSICAL_KEYBOARD_ENABLE_CAPITALIZATION:
    case OptionType.PHYSICAL_KEYBOARD_ENABLE_PREDICTIVE_WRITING:
    case OptionType.VIRTUAL_KEYBOARD_ENABLE_CAPITALIZATION:
    case OptionType.KOREAN_ENABLE_SYLLABLE_INPUT:
    case OptionType.PINYIN_CHINESE_PUNCTUATION:
    case OptionType.PINYIN_DEFAULT_CHINESE:
    case OptionType.PINYIN_ENABLE_FUZZY:
    case OptionType.PINYIN_ENABLE_LOWER_PAGING:
    case OptionType.PINYIN_ENABLE_UPPER_PAGING:
    case OptionType.PINYIN_FULL_WIDTH_CHARACTER:
    case OptionType.PINYIN_AN_ANG:
    case OptionType.PINYIN_EN_ENG:
    case OptionType.PINYIN_IAN_IANG:
    case OptionType.PINYIN_K_G:
    case OptionType.PINYIN_R_L:
    case OptionType.PINYIN_UAN_UANG:
    case OptionType.PINYIN_C_CH:
    case OptionType.PINYIN_F_H:
    case OptionType.PINYIN_IN_ING:
    case OptionType.PINYIN_L_N:
    case OptionType.PINYIN_S_SH:
    case OptionType.PINYIN_Z_ZH:
    case OptionType.VIETNAMESE_VNI_ALLOW_FLEXIBLE_DIACRITICS:
    case OptionType.VIETNAMESE_VNI_NEW_STYLE_TONE_MARK_PLACEMENT:
    case OptionType.VIETNAMESE_VNI_INSERT_DOUBLE_HORN_ON_UO:
    case OptionType.VIETNAMESE_VNI_SHOW_UNDERLINE:
    case OptionType.VIETNAMESE_TELEX_ALLOW_FLEXIBLE_DIACRITICS:
    case OptionType.VIETNAMESE_TELEX_NEW_STYLE_TONE_MARK_PLACEMENT:
    case OptionType.VIETNAMESE_TELEX_INSERT_DOUBLE_HORN_ON_UO:
    case OptionType.VIETNAMESE_TELEX_INSERT_U_HORN_ON_W:
    case OptionType.VIETNAMESE_TELEX_SHOW_UNDERLINE:
      return UiType.TOGGLE_BUTTON;
    case OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL:
    case OptionType.VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL:
      return loadTimeData.getBoolean('allowAutocorrectToggle') ?
          UiType.TOGGLE_BUTTON :
          UiType.DROPDOWN;
    case OptionType.XKB_LAYOUT:
    case OptionType.JAPANESE_INPUT_MODE:
    case OptionType.JAPANESE_PUNCTUATION_STYLE:
    case OptionType.JAPANESE_SYMBOL_STYLE:
    case OptionType.JAPANESE_SPACE_INPUT_STYLE:
    case OptionType.JAPANESE_SECTION_SHORTCUT:
    case OptionType.JAPANESE_KEYMAP_STYLE:
    case OptionType.JAPANESE_SHIFT_KEY_MODE_STYLE:
    case OptionType.JAPANESE_NUMBER_OF_SUGGESTIONS:
    case OptionType.KOREAN_KEYBOARD_LAYOUT:
    case OptionType.ZHUYIN_KEYBOARD_LAYOUT:
    case OptionType.ZHUYIN_SELECT_KEYS:
    case OptionType.ZHUYIN_PAGE_SIZE:
      return UiType.DROPDOWN;
    case OptionType.EDIT_USER_DICT:
    case OptionType.JAPANESE_MANAGE_USER_DICTIONARY:
      return UiType.LINK;
    case OptionType.JAPANESE_DELETE_PERSONALIZATION_DATA:
      return UiType.SUBMENU_BUTTON;
    case OptionType.PINYIN_FUZZY_CONFIG:
      // Not implemented.
      assertNotReached();
    default:
      assertExhaustive(option);
  }
}

export function isOptionLabelTranslated(option: OptionType): option is Exclude<
    OptionType,
    OptionType.PINYIN_AN_ANG|OptionType.PINYIN_EN_ENG|OptionType
        .PINYIN_IAN_IANG|OptionType.PINYIN_K_G|OptionType.PINYIN_R_L|
    OptionType.PINYIN_UAN_UANG|OptionType.PINYIN_C_CH|
    OptionType.PINYIN_F_H|OptionType.PINYIN_IN_ING|
    OptionType.PINYIN_L_N|OptionType.PINYIN_S_SH|OptionType.PINYIN_Z_ZH> {
  switch (option) {
    // TODO(b/191608723): Clean up switch statements.
    case OptionType.PINYIN_AN_ANG:
    case OptionType.PINYIN_EN_ENG:
    case OptionType.PINYIN_IAN_IANG:
    case OptionType.PINYIN_K_G:
    case OptionType.PINYIN_R_L:
    case OptionType.PINYIN_UAN_UANG:
    case OptionType.PINYIN_C_CH:
    case OptionType.PINYIN_F_H:
    case OptionType.PINYIN_IN_ING:
    case OptionType.PINYIN_L_N:
    case OptionType.PINYIN_S_SH:
    case OptionType.PINYIN_Z_ZH:
      return false;
    default:
      return true;
  }
}

/**
 * `isOptionLabelTranslated(option)` must be true.
 * @param option The option type.
 * @return The name of the i18n string for the label of |option|.
 */
export function getOptionLabelName(option: OptionType): string {
  switch (option) {
    case OptionType.ENABLE_DOUBLE_SPACE_PERIOD:
      return 'inputMethodOptionsEnableDoubleSpacePeriod';
    case OptionType.ENABLE_GESTURE_TYPING:
      return 'inputMethodOptionsEnableGestureTyping';
    case OptionType.ENABLE_PREDICTION:
      return 'inputMethodOptionsEnablePrediction';
    case OptionType.ENABLE_SOUND_ON_KEYPRESS:
      return 'inputMethodOptionsEnableSoundOnKeypress';
    case OptionType.PHYSICAL_KEYBOARD_ENABLE_CAPITALIZATION:
    case OptionType.VIRTUAL_KEYBOARD_ENABLE_CAPITALIZATION:
      return 'inputMethodOptionsEnableCapitalization';
    case OptionType.PHYSICAL_KEYBOARD_ENABLE_PREDICTIVE_WRITING:
      return 'inputMethodOptionsPredictiveWriting';
    case OptionType.PINYIN_CHINESE_PUNCTUATION:
      return 'inputMethodOptionsPinyinChinesePunctuation';
    case OptionType.PINYIN_DEFAULT_CHINESE:
      return 'inputMethodOptionsPinyinDefaultChinese';
    case OptionType.PINYIN_ENABLE_FUZZY:
      return 'inputMethodOptionsPinyinEnableFuzzy';
    case OptionType.PINYIN_ENABLE_LOWER_PAGING:
      return 'inputMethodOptionsPinyinEnableLowerPaging';
    case OptionType.PINYIN_ENABLE_UPPER_PAGING:
      return 'inputMethodOptionsPinyinEnableUpperPaging';
    case OptionType.PINYIN_FULL_WIDTH_CHARACTER:
      return 'inputMethodOptionsPinyinFullWidthCharacter';
    case OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL:
    case OptionType.VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL:
      return 'inputMethodOptionsAutoCorrection';
    case OptionType.JAPANESE_INPUT_MODE:
      return 'inputMethodOptionsJapaneseInputMode';
    case OptionType.JAPANESE_PUNCTUATION_STYLE:
      return 'inputMethodOptionsJapanesePunctuationStyle';
    case OptionType.JAPANESE_SYMBOL_STYLE:
      return 'inputMethodOptionsJapaneseSymbolStyle';
    case OptionType.JAPANESE_SPACE_INPUT_STYLE:
      return 'inputMethodOptionsJapaneseSpaceInputStyle';
    case OptionType.JAPANESE_SECTION_SHORTCUT:
      return 'inputMethodOptionsJapaneseSectionShortcut';
    case OptionType.JAPANESE_KEYMAP_STYLE:
      return 'inputMethodOptionsJapaneseKeymapStyle';
    case OptionType.JAPANESE_AUTOMATICALLY_SWITCH_TO_HALFWIDTH:
      return 'inputMethodOptionsJapaneseAutomaticallySwitchToHalfwidth';
    case OptionType.JAPANESE_SHIFT_KEY_MODE_STYLE:
      return 'inputMethodOptionsJapaneseShiftKeyModeStyle';
    case OptionType.JAPANESE_USE_INPUT_HISTORY:
      return 'inputMethodOptionsJapaneseUseInputHistory';
    case OptionType.JAPANESE_USE_SYSTEM_DICTIONARY:
      return 'inputMethodOptionsJapaneseUseSystemDictionary';
    case OptionType.JAPANESE_NUMBER_OF_SUGGESTIONS:
      return 'inputMethodOptionsJapaneseNumberOfSuggestions';
    case OptionType.JAPANESE_MANAGE_USER_DICTIONARY:
      return 'inputMethodOptionsJapaneseManageUserDictionary';
    case OptionType.JAPANESE_DELETE_PERSONALIZATION_DATA:
      return 'inputMethodOptionsJapaneseDeletePersonalizationData';
    case OptionType.JAPANESE_DISABLE_PERSONALIZED_SUGGESTIONS:
      return 'inputMethodOptionsJapaneseDisablePersonalizedSuggestions';
    case OptionType.JAPANESE_AUTOMATICALLY_SEND_STATISTICS_TO_GOOGLE:
      return 'inputMethodOptionsJapaneseAutomaticallySendStatisticsToGoogle';
    case OptionType.XKB_LAYOUT:
      return 'inputMethodOptionsXkbLayout';
    case OptionType.EDIT_USER_DICT:
      return 'inputMethodOptionsEditUserDict';
    case OptionType.ZHUYIN_KEYBOARD_LAYOUT:
      return 'inputMethodOptionsZhuyinKeyboardLayout';
    case OptionType.ZHUYIN_SELECT_KEYS:
      return 'inputMethodOptionsZhuyinSelectKeys';
    case OptionType.ZHUYIN_PAGE_SIZE:
      return 'inputMethodOptionsZhuyinPageSize';
    case OptionType.KOREAN_KEYBOARD_LAYOUT:
      return 'inputMethodOptionsKoreanLayout';
    case OptionType.KOREAN_ENABLE_SYLLABLE_INPUT:
      return 'inputMethodOptionsKoreanSyllableInput';
    case OptionType.VIETNAMESE_VNI_ALLOW_FLEXIBLE_DIACRITICS:
      return 'inputMethodOptionsVietnameseFlexibleTyping';
    case OptionType.VIETNAMESE_VNI_NEW_STYLE_TONE_MARK_PLACEMENT:
      return 'inputMethodOptionsVietnameseModernToneMarkPlacement';
    case OptionType.VIETNAMESE_VNI_INSERT_DOUBLE_HORN_ON_UO:
      return 'inputMethodOptionsVietnameseVniUoHookShortcut';
    case OptionType.VIETNAMESE_VNI_SHOW_UNDERLINE:
      return 'inputMethodOptionsVietnameseShowUnderline';
    case OptionType.VIETNAMESE_TELEX_ALLOW_FLEXIBLE_DIACRITICS:
      return 'inputMethodOptionsVietnameseFlexibleTyping';
    case OptionType.VIETNAMESE_TELEX_NEW_STYLE_TONE_MARK_PLACEMENT:
      return 'inputMethodOptionsVietnameseModernToneMarkPlacement';
    case OptionType.VIETNAMESE_TELEX_INSERT_DOUBLE_HORN_ON_UO:
      return 'inputMethodOptionsVietnameseTelexUoHookShortcut';
    case OptionType.VIETNAMESE_TELEX_SHOW_UNDERLINE:
      return 'inputMethodOptionsVietnameseShowUnderline';
    case OptionType.VIETNAMESE_TELEX_INSERT_U_HORN_ON_W:
      return 'inputMethodOptionsVietnameseTelexWShortcut';
    case OptionType.ENABLE_COMPLETION:
    case OptionType.PINYIN_FUZZY_CONFIG:
      // Not implemented.
      assertNotReached();
    default:
      assert(isOptionLabelTranslated(option));
      assertExhaustive(option);
  }
}

/**
 * @param option The option type.
 * @return The name of the string for the subtitle of |option|. Returns empty
 *     string if no subtitle.
 */
export function getOptionSubtitleName(option: OptionType): string {
  switch (option) {
    // TODO(b/234790486): The subtitle is not forced to the next line if it is
    // too short. You end up with something like :
    // https://screenshot.googleplex.com/8xk2BfbBXcGqhvs This likely also
    // affects the diacritics label. This is not currently an issue since both
    // string are long enough and force themself to the next line, but it may be
    // an issue in other languages or with future strings which may be shorter.
    case OptionType.JAPANESE_MANAGE_USER_DICTIONARY:
      return 'inputMethodOptionsJapaneseManageUserDictionarySubtitle';
    case OptionType.VIETNAMESE_TELEX_NEW_STYLE_TONE_MARK_PLACEMENT:
    case OptionType.VIETNAMESE_VNI_NEW_STYLE_TONE_MARK_PLACEMENT:
      return 'inputMethodOptionsVietnameseModernToneMarkPlacementDescription';
    case OptionType.VIETNAMESE_TELEX_SHOW_UNDERLINE:
    case OptionType.VIETNAMESE_VNI_SHOW_UNDERLINE:
      return 'inputMethodOptionsVietnameseShowUnderlineDescription';
    case OptionType.VIETNAMESE_TELEX_ALLOW_FLEXIBLE_DIACRITICS:
      return 'inputMethodOptionsVietnameseTelexFlexibleTypingDescription';
    case OptionType.VIETNAMESE_VNI_ALLOW_FLEXIBLE_DIACRITICS:
      return 'inputMethodOptionsVietnameseVniFlexibleTypingDescription';
    default:
      return '';
  }
}

/**
 * `isOptionLabelTranslated(option)` must be false.
 */
export function getUntranslatedOptionLabelName(option: OptionType): string {
  switch (option) {
    case OptionType.PINYIN_AN_ANG:
      return 'an_ang';
    case OptionType.PINYIN_EN_ENG:
      return 'en_eng';
    case OptionType.PINYIN_IAN_IANG:
      return 'ian_iang';
    case OptionType.PINYIN_K_G:
      return 'k_g';
    case OptionType.PINYIN_R_L:
      return 'r_l';
    case OptionType.PINYIN_UAN_UANG:
      return 'uan_uang';
    case OptionType.PINYIN_C_CH:
      return 'c_ch';
    case OptionType.PINYIN_F_H:
      return 'f_h';
    case OptionType.PINYIN_IN_ING:
      return 'in_ing';
    case OptionType.PINYIN_L_N:
      return 'l_n';
    case OptionType.PINYIN_S_SH:
      return 's_sh';
    case OptionType.PINYIN_Z_ZH:
      return 'z_zh';
    default:
      assert(!isOptionLabelTranslated(option));
      assertExhaustive(option);
  }
}

/**
 * @param option The option type.
 * @return The list of items to be displayed in the dropdown for |option|.
 */
export function getOptionMenuItems(option: OptionType):
    Array<{name?: string, value: string | number}> {
  switch (option) {
    case OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL:
    case OptionType.VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL:
      return [
        {value: 0, name: 'inputMethodOptionsAutoCorrectionOff'},
        {value: 1, name: 'inputMethodOptionsAutoCorrectionModest'},
        {value: 2, name: 'inputMethodOptionsAutoCorrectionAggressive'},
      ];
    case OptionType.XKB_LAYOUT:
      return [
        {value: 'US', name: 'inputMethodOptionsUsKeyboard'},
        {value: 'Dvorak', name: 'inputMethodOptionsDvorakKeyboard'},
        {value: 'Colemak', name: 'inputMethodOptionsColemakKeyboard'},
      ];
    case OptionType.ZHUYIN_KEYBOARD_LAYOUT:
      return [
        {value: 'Default', name: 'inputMethodOptionsZhuyinLayoutDefault'},
        {value: 'IBM', name: 'inputMethodOptionsZhuyinLayoutIBM'},
        {value: 'Eten', name: 'inputMethodOptionsZhuyinLayoutEten'},
      ];
    case OptionType.ZHUYIN_SELECT_KEYS:
      // Zhuyin select keys correspond to physical keys so are not
      // translated.
      return [
        {value: '1234567890'},
        {value: 'asdfghjkl;'},
        {value: 'asdfzxcv89'},
        {value: 'asdfjkl789'},
        {value: '1234qweras'},
      ];
    case OptionType.ZHUYIN_PAGE_SIZE:
      // Zhuyin page size is just a number, so is not translated.
      return [
        {value: '10'},
        {value: '9'},
        {value: '8'},
      ];
    case OptionType.JAPANESE_INPUT_MODE:
      return [
        {
          value: JapaneseInputMode.KANA,
          name: 'inputMethodOptionsJapaneseInputModeKana',
        },
        {
          value: JapaneseInputMode.ROMAJI,
          name: 'inputMethodOptionsJapaneseInputModeRomaji',
        },
      ];
    case OptionType.JAPANESE_PUNCTUATION_STYLE:
      return [
        {
          value: JapanesePunctuationStyle.KUTEN_TOUTEN,
          name: 'inputMethodOptionsJapanesePunctuationStyleKutenTouten',
        },
        {
          value: JapanesePunctuationStyle.COMMA_PERIOD,
          name: 'inputMethodOptionsJapanesePunctuationStyleCommaPeriod',
        },
        {
          value: JapanesePunctuationStyle.KUTEN_PERIOD,
          name: 'inputMethodOptionsJapanesePunctuationStyleKutenPeriod',
        },
        {
          value: JapanesePunctuationStyle.COMMA_TOUTEN,
          name: 'inputMethodOptionsJapanesePunctuationStyleCommaTouten',
        },
      ];
    case OptionType.JAPANESE_SYMBOL_STYLE:
      return [
        {
          value: JapaneseSymbolStyle.CORNER_BRACKET_MIDDLE_DOT,
          name: 'inputMethodOptionsJapaneseSymbolStyleCornerBracketMiddleDot',
        },
        {
          value: JapaneseSymbolStyle.SQUARE_BRACKET_SLASH,
          name: 'inputMethodOptionsJapaneseSymbolStyleSquareBracketSlash',
        },
        {
          value: JapaneseSymbolStyle.CORNER_BRACKET_SLASH,
          name: 'inputMethodOptionsJapaneseSymbolStyleCornerBracketSlash',
        },
        {
          value: JapaneseSymbolStyle.SQUARE_BRACKET_MIDDLE_DOT,
          name: 'inputMethodOptionsJapaneseSymbolStyleSquareBracketMiddleDot',
        },
      ];
    case OptionType.JAPANESE_SPACE_INPUT_STYLE:
      return [
        {
          value: JapaneseSpaceInputStyle.INPUT_MODE,
          name: 'inputMethodOptionsJapaneseSpaceInputStyleInputMode',
        },
        {
          value: JapaneseSpaceInputStyle.FULLWIDTH,
          name: 'inputMethodOptionsJapaneseSpaceInputStyleFullwidth',
        },
        {
          value: JapaneseSpaceInputStyle.HALFWIDTH,
          name: 'inputMethodOptionsJapaneseSpaceInputStyleHalfwidth',
        },
      ];
    case OptionType.JAPANESE_SECTION_SHORTCUT:
      return [
        {
          value: JapaneseSectionShortcut.NO_SHORTCUT,
          name: 'inputMethodOptionsJapaneseSectionShortcutNoShortcut',
        },
        {
          value: JapaneseSectionShortcut.DIGITS_123456789,
          name: 'inputMethodOptionsJapaneseSectionShortcut123456789',
        },
        {
          value: JapaneseSectionShortcut.ASDFGHJKL,
          name: 'inputMethodOptionsJapaneseSectionShortcutAsdfghjkl',
        },
      ];
    case OptionType.JAPANESE_KEYMAP_STYLE:
      return [
        {
          value: JapaneseKeymapStyle.CUSTOM,
          name: 'inputMethodOptionsJapaneseKeymapStyleCustom',
        },
        {
          value: JapaneseKeymapStyle.ATOK,
          name: 'inputMethodOptionsJapaneseKeymapStyleAtok',
        },
        {
          value: JapaneseKeymapStyle.MS_IME,
          name: 'inputMethodOptionsJapaneseKeymapStyleMsIme',
        },
        {
          value: JapaneseKeymapStyle.KOTOERI,
          name: 'inputMethodOptionsJapaneseKeymapStyleKotoeri',
        },
        {
          value: JapaneseKeymapStyle.MOBILE,
          name: 'inputMethodOptionsJapaneseKeymapStyleMobile',
        },
        {
          value: JapaneseKeymapStyle.CHROME_OS,
          name: 'inputMethodOptionsJapaneseKeymapStyleChromeOs',
        },
      ];
    case OptionType.JAPANESE_SHIFT_KEY_MODE_STYLE:
      return [
        {
          value: JapaneseShiftKeyModeStyle.OFF,
          name: 'inputMethodOptionsJapaneseShiftKeyModeStyleOff',
        },
        {
          value: JapaneseShiftKeyModeStyle.ALPHANUMERIC,
          name: 'inputMethodOptionsJapaneseShiftKeyModeStyleAlphanumeric',
        },
        {
          value: JapaneseShiftKeyModeStyle.KATAKANA,
          name: 'inputMethodOptionsJapaneseShiftKeyModeStyleKatakana',
        },
      ];
    case OptionType.JAPANESE_NUMBER_OF_SUGGESTIONS:
      return [
        {
          value: 1,
        },
        {
          value: 2,
        },
        {
          value: 3,
        },
        {
          value: 4,
        },
        {
          value: 5,
        },
        {
          value: 6,
        },
        {
          value: 7,
        },
        {
          value: 8,
        },
        {
          value: 9,
        },
      ];
    case OptionType.KOREAN_KEYBOARD_LAYOUT:
      // Korean layout strings are already Korean / English, so not
      // translated. The literal values of these strings are critical.
      return [
        {value: '2 Set / 두벌식'},
        {value: '3 Set (390) / 세벌식 (390)'},
        {value: '3 Set (Final) / 세벌식 (최종)'},
        {value: '3 Set (No Shift) / 세벌식 (순아래)'},
        {value: '2 Set (Old Hangul) / 두벌식 (옛글)'},
        {value: '3 Set (Old Hangul) / 세벌식 (옛글)'},
      ];
    default:
      return [];
  }
}

/**
 * Used to work around dropdowns in the UI always storing their values as
 * strings.
 * @param option The option type.
 * @return true if the value for |option| is a number and |option| is a
 *     dropdown.
 */
// TODO(b/265557721): Remove this when we remove Polymer's two-way native
// binding of value changes.
export function shouldStoreAsNumber(option: OptionType):
    option is OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL|
    OptionType.VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL|
    OptionType.JAPANESE_NUMBER_OF_SUGGESTIONS {
  return option === OptionType.PHYSICAL_KEYBOARD_AUTO_CORRECTION_LEVEL ||
      option === OptionType.VIRTUAL_KEYBOARD_AUTO_CORRECTION_LEVEL ||
      option === OptionType.JAPANESE_NUMBER_OF_SUGGESTIONS;
}
/**
 * @param option The option type.
 * @return The url to open for |option|, returns undefined if |option| does not
 *     have a url.
 */
export function getOptionUrl(option: OptionType): Route|undefined {
  if (option === OptionType.EDIT_USER_DICT) {
    return routes.OS_LANGUAGES_EDIT_DICTIONARY;
  }
  if (option === OptionType.JAPANESE_MANAGE_USER_DICTIONARY) {
    return routes.OS_LANGUAGES_JAPANESE_MANAGE_USER_DICTIONARY;
  }
  return undefined;
}

/**
 * @param option The option type.
 * @return The submenu button type for |option|, returns undefined if |option|
 *     does not have a submenu button type.
 */
export function getSubmenuButtonType(option: OptionType): SubmenuButton|
    undefined {
  if (option === OptionType.JAPANESE_DELETE_PERSONALIZATION_DATA) {
    return SubmenuButton.JAPANESE_DELETE_PERSONALIZATION_DATA;
  }
  return undefined;
}

/**
 * @param id Input method ID.
 * @return true if |id| is a first party input method ID.
 */
function isFirstPartyInputMethodId(id: string): boolean {
  return id.startsWith(FIRST_PARTY_INPUT_METHOD_ID_PREFIX);
}