import re


def translate(text: str, transdict: dict) -> str:
    """
    Translates the provided text using the translation dictionary.
    Text inside square brackets [] and angle brackets <> as well as in comments (starting with #) is left unchanged.
    If multiple matches from the provided keys are possible, the longest applicable key will be used.

    :param text:        the text to be translated
    :param transdict:   the translation dictionary (key -> value)
    :return:            the translated text
    """

    # Compile regex matching ciphertext keys from dictionary, sorted by key length (longest first)
    ciphers_pattern = re.compile('|'.join(sorted(transdict.keys(), key=len, reverse=True)))

    # https://regexper.com/#(%5B%5E%3C%5C%5B%23%5D*)(((%3F%3A%3C%5B%5E%3E%5D*%3E)%7C(%3F%3A%5C%5B%5B%5E%5C%5D%5D*%5C%5D))*(%23.*%24)%3F)
    regex = r'([^<\[#]*)(((?:<[^>]*>)|(?:\[[^\]]*\]))*(#.*$)?)'

    # Decode the text by splitting the string into the part to be translated (group 0)
    # and the part to be ignored (cleartext and comments) (group 1).
    # In the first group, each key from the dictionary is replaced by the corresponding value.
    # The result is then concatenated with the unchanged second group.
    output = ''
    for match in re.findall(regex, text, flags=re.MULTILINE):
        output += ciphers_pattern.sub(
            lambda l: transdict[l.group()], match[0]) + match[1]
    return output