# Path: pyxform/aliases.py
# TRANSLATABLE_SURVEY_COLUMNS = {
#     constants.LABEL: constants.LABEL,
#     # Per ODK Spec, could include "short" once pyxform supports it.
#     constants.HINT: constants.HINT,
#     "guidance_hint": "guidance_hint",
#     "image": survey_header["image"],
#     # Per ODK Spec, could include "big-image" once pyxform supports it.
#     "audio": survey_header["audio"],
#     "video": survey_header["video"],
#     "jr:constraintMsg": "constraint_message",
#     "jr:requiredMsg": "required_message",
# }
# TRANSLATABLE_CHOICES_COLUMNS = {
#     "label": constants.LABEL,
#     "image": "media::image",
#     "audio": "media::audio",
#     "video": "media::video",
# }
# 
# Path: pyxform/constants.py
# TYPE = "type"
# TITLE = "title"
# NAME = "name"
# ID_STRING = "id_string"
# SMS_KEYWORD = "sms_keyword"
# SMS_FIELD = "sms_field"
# SMS_OPTION = "sms_option"
# SMS_SEPARATOR = "sms_separator"
# SMS_ALLOW_MEDIA = "sms_allow_media"
# SMS_DATE_FORMAT = "sms_date_format"
# SMS_DATETIME_FORMAT = "sms_datetime_format"
# SMS_RESPONSE = "sms_response"
# COMPACT_PREFIX = "prefix"
# COMPACT_DELIMITER = "delimiter"
# COMPACT_TAG = "compact_tag"
# VERSION = "version"
# PUBLIC_KEY = "public_key"
# SUBMISSION_URL = "submission_url"
# AUTO_SEND = "auto_send"
# AUTO_DELETE = "auto_delete"
# DEFAULT_LANGUAGE_KEY = "default_language"
# DEFAULT_LANGUAGE_VALUE = "default"
# LABEL = "label"
# HINT = "hint"
# STYLE = "style"
# ATTRIBUTE = "attribute"
# ALLOW_CHOICE_DUPLICATES = "allow_choice_duplicates"
# BIND = (
#     "bind"  # TODO: What should I do with the nested types? (readonly and relevant) # noqa
# )
# MEDIA = "media"
# CONTROL = "control"
# APPEARANCE = "appearance"
# LOOP = "loop"
# COLUMNS = "columns"
# REPEAT = "repeat"
# GROUP = "group"
# CHILDREN = "children"
# SELECT_ONE = "select one"
# SELECT_ALL_THAT_APPLY = "select all that apply"
# RANK = "rank"
# CHOICES = "choices"
# LIST_NAME = "list name"
# CASCADING_SELECT = "cascading_select"
# TABLE_LIST = "table-list"  # hyphenated because it goes in appearance, and convention for appearance column is dashes # noqa
# FIELD_LIST = "field-list"
# SURVEY = "survey"
# SETTINGS = "settings"
# EXTERNAL_CHOICES = "external_choices"
# OSM = "osm"
# OSM_TYPE = "binary"
# NAMESPACES = "namespaces"
# SUPPORTED_SHEET_NAMES = [
#     SURVEY,
#     CHOICES,
#     SETTINGS,
#     EXTERNAL_CHOICES,
#     OSM,
# ]
# XLS_EXTENSIONS = [".xls"]
# XLSX_EXTENSIONS = [".xlsx", ".xlsm"]
# SUPPORTED_FILE_EXTENSIONS = XLS_EXTENSIONS + XLSX_EXTENSIONS
# LOCATION_PRIORITY = "location-priority"
# LOCATION_MIN_INTERVAL = "location-min-interval"
# LOCATION_MAX_AGE = "location-max-age"
# TRACK_CHANGES = "track-changes"
# IDENTIFY_USER = "identify-user"
# TRACK_CHANGES_REASONS = "track-changes-reasons"
# EXTERNAL_INSTANCES = ["calculate", "constraint", "readonly", "required", "relevant"]
# CURRENT_XFORMS_VERSION = "1.0.0"
# DEPRECATED_DEVICE_ID_METADATA_FIELDS = ["subscriberid", "simserial"]
# AUDIO_QUALITY_VOICE_ONLY = "voice-only"
# AUDIO_QUALITY_LOW = "low"
# AUDIO_QUALITY_NORMAL = "normal"
# AUDIO_QUALITY_EXTERNAL = "external"
# EXTERNAL_CHOICES_ITEMSET_REF_LABEL = "label"
# EXTERNAL_CHOICES_ITEMSET_REF_VALUE = "name"
# ROW_FORMAT_STRING: str = "[row : %s]"
# 
# Path: pyxform/errors.py
# class PyXFormError(Exception):
#     """Common base class for pyxform exceptions."""
# 
#     pass


from collections import defaultdict
from typing import TYPE_CHECKING
from pyxform import aliases, constants
from pyxform.errors import PyXFormError
    from typing import Dict, List, Optional, Sequence, Union
                process_cell(typ=column_type, cell=cell_content)

    missing = defaultdict(list)
    for lang, lang_trans in translations_seen.items():
        for seen_tran in translation_columns_seen:
            if seen_tran not in lang_trans:
                missing[lang].append(seen_tran)

    return missing


def missing_translations_check(
    survey_sheet: "SheetData",
    choices_sheet: "SheetData",
    warnings: "List[str]",
):
    """
    Add a warning if there are missing translation columns in the survey or choices data.

    :param survey_sheet: The survey sheet data.
    :param choices_sheet: The choices sheet data.
    :param warnings: The warnings list, which may be empty.
    :return: The warnings list, possibly with a new message, otherwise unchanged.
    """
    survey_missing_trans = find_missing_translations(
        sheet_data=survey_sheet,
        translatable_columns=aliases.TRANSLATABLE_SURVEY_COLUMNS,
    )
    choices_missing_trans = find_missing_translations(
        sheet_data=choices_sheet,

# Path: pyxform/aliases.py
# TRANSLATABLE_SURVEY_COLUMNS = {
#     constants.LABEL: constants.LABEL,
#     # Per ODK Spec, could include "short" once pyxform supports it.
#     constants.HINT: constants.HINT,
#     "guidance_hint": "guidance_hint",
#     "image": survey_header["image"],
#     # Per ODK Spec, could include "big-image" once pyxform supports it.
#     "audio": survey_header["audio"],
#     "video": survey_header["video"],
#     "jr:constraintMsg": "constraint_message",
#     "jr:requiredMsg": "required_message",
# }
# TRANSLATABLE_CHOICES_COLUMNS = {
#     "label": constants.LABEL,
#     "image": "media::image",
#     "audio": "media::audio",
#     "video": "media::video",
# }
# 
# Path: pyxform/constants.py
# TYPE = "type"
# TITLE = "title"
# NAME = "name"
# ID_STRING = "id_string"
# SMS_KEYWORD = "sms_keyword"
# SMS_FIELD = "sms_field"
# SMS_OPTION = "sms_option"
# SMS_SEPARATOR = "sms_separator"
# SMS_ALLOW_MEDIA = "sms_allow_media"
# SMS_DATE_FORMAT = "sms_date_format"
# SMS_DATETIME_FORMAT = "sms_datetime_format"
# SMS_RESPONSE = "sms_response"
# COMPACT_PREFIX = "prefix"
# COMPACT_DELIMITER = "delimiter"
# COMPACT_TAG = "compact_tag"
# VERSION = "version"
# PUBLIC_KEY = "public_key"
# SUBMISSION_URL = "submission_url"
# AUTO_SEND = "auto_send"
# AUTO_DELETE = "auto_delete"
# DEFAULT_LANGUAGE_KEY = "default_language"
# DEFAULT_LANGUAGE_VALUE = "default"
# LABEL = "label"
# HINT = "hint"
# STYLE = "style"
# ATTRIBUTE = "attribute"
# ALLOW_CHOICE_DUPLICATES = "allow_choice_duplicates"
# BIND = (
#     "bind"  # TODO: What should I do with the nested types? (readonly and relevant) # noqa
# )
# MEDIA = "media"
# CONTROL = "control"
# APPEARANCE = "appearance"
# LOOP = "loop"
# COLUMNS = "columns"
# REPEAT = "repeat"
# GROUP = "group"
# CHILDREN = "children"
# SELECT_ONE = "select one"
# SELECT_ALL_THAT_APPLY = "select all that apply"
# RANK = "rank"
# CHOICES = "choices"
# LIST_NAME = "list name"
# CASCADING_SELECT = "cascading_select"
# TABLE_LIST = "table-list"  # hyphenated because it goes in appearance, and convention for appearance column is dashes # noqa
# FIELD_LIST = "field-list"
# SURVEY = "survey"
# SETTINGS = "settings"
# EXTERNAL_CHOICES = "external_choices"
# OSM = "osm"
# OSM_TYPE = "binary"
# NAMESPACES = "namespaces"
# SUPPORTED_SHEET_NAMES = [
#     SURVEY,
#     CHOICES,
#     SETTINGS,
#     EXTERNAL_CHOICES,
#     OSM,
# ]
# XLS_EXTENSIONS = [".xls"]
# XLSX_EXTENSIONS = [".xlsx", ".xlsm"]
# SUPPORTED_FILE_EXTENSIONS = XLS_EXTENSIONS + XLSX_EXTENSIONS
# LOCATION_PRIORITY = "location-priority"
# LOCATION_MIN_INTERVAL = "location-min-interval"
# LOCATION_MAX_AGE = "location-max-age"
# TRACK_CHANGES = "track-changes"
# IDENTIFY_USER = "identify-user"
# TRACK_CHANGES_REASONS = "track-changes-reasons"
# EXTERNAL_INSTANCES = ["calculate", "constraint", "readonly", "required", "relevant"]
# CURRENT_XFORMS_VERSION = "1.0.0"
# DEPRECATED_DEVICE_ID_METADATA_FIELDS = ["subscriberid", "simserial"]
# AUDIO_QUALITY_VOICE_ONLY = "voice-only"
# AUDIO_QUALITY_LOW = "low"
# AUDIO_QUALITY_NORMAL = "normal"
# AUDIO_QUALITY_EXTERNAL = "external"
# EXTERNAL_CHOICES_ITEMSET_REF_LABEL = "label"
# EXTERNAL_CHOICES_ITEMSET_REF_VALUE = "name"
# ROW_FORMAT_STRING: str = "[row : %s]"
# 
# Path: pyxform/errors.py
# class PyXFormError(Exception):
#     """Common base class for pyxform exceptions."""
# 
#     pass


# Path: pyxform/validators/pyxform/missing_translations_check.py
from collections import defaultdict
from typing import TYPE_CHECKING
from pyxform import aliases, constants
from pyxform.errors import PyXFormError
    from typing import Dict, List, Optional, Sequence, Union

                process_cell(typ=column_type, cell=cell_content)

    missing = defaultdict(list)
    for lang, lang_trans in translations_seen.items():
        for seen_tran in translation_columns_seen:
            if seen_tran not in lang_trans:
                missing[lang].append(seen_tran)

    return missing


def missing_translations_check(
    survey_sheet: "SheetData",
    choices_sheet: "SheetData",
    warnings: "List[str]",
):
    """
    Add a warning if there are missing translation columns in the survey or choices data.

    :param survey_sheet: The survey sheet data.
    :param choices_sheet: The choices sheet data.
    :param warnings: The warnings list, which may be empty.
    :return: The warnings list, possibly with a new message, otherwise unchanged.
    """
    survey_missing_trans = find_missing_translations(
        sheet_data=survey_sheet,
        translatable_columns=aliases.TRANSLATABLE_SURVEY_COLUMNS,
    )
    choices_missing_trans = find_missing_translations(
        sheet_data=choices_sheet,

        translatable_columns=aliases.TRANSLATABLE_CHOICES_COLUMNS,