code: def babel_extract(
      fileobj: t.BinaryIO,
      keywords: t.Sequence[str],
      comment_tags: t.Sequence[str],
      options: t.Dict[str, t.Any],
  ) -> t.Iterator[
      t.Tuple[
          int,
          str,
          t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]],
          t.List[str],
      ]
  ]:
      """Babel extraction method for Jinja templates.
  
      .. versionchanged:: 2.3
         Basic support for translation comments was added.  If `comment_tags`
         is now set to a list of keywords for extraction, the extractor will
         try to find the best preceding comment that begins with one of the
         keywords.  For best results, make sure to not have more than one
         gettext call in one line of code and the matching comment in the
         same line or the line before.
  
      .. versionchanged:: 2.5.1
         The `newstyle_gettext` flag can be set to `True` to enable newstyle
         gettext calls.
  
      .. versionchanged:: 2.7
         A `silent` option can now be provided.  If set to `False` template
         syntax errors are propagated instead of being ignored.
  
      :param fileobj: the file-like object the messages should be extracted from
      :param keywords: a list of keywords (i.e. function names) that should be
                       recognized as translation functions
      :param comment_tags: a list of translator tags to search for and include
                           in the results.
      :param options: a dictionary of additional options (optional)
      :return: an iterator over ``(lineno, funcname, message, comments)`` tuples.
               (comments will be empty currently)
      """
      extensions: t.Dict[t.Type[Extension], None] = {}
  
      for extension_name in options.get("extensions", "").split(","):
          extension_name = extension_name.strip()
  
          if not extension_name:
              continue
  
          extensions[import_string(extension_name)] = None
  
      if InternationalizationExtension not in extensions:
          extensions[InternationalizationExtension] = None
  
      def getbool(
          options: t.Mapping[str, str], key: str, default: bool = False
      ) -> bool:
          return options.get(key, str(default)).lower() in {
              "1",
              "on",
              "yes",
              "true",
          }
  
      silent = getbool(options, "silent", True)
      environment = Environment(
          options.get(
              "block_start_string", defaults.BLOCK_START_STRING
          ),
          options.get("block_end_string", defaults.BLOCK_END_STRING),
          options.get(
              "variable_start_string", defaults.VARIABLE_START_STRING
          ),
          options.get(
              "variable_end_string", defaults.VARIABLE_END_STRING
          ),
          options.get(
              "comment_start_string", defaults.COMMENT_START_STRING
          ),
          options.get(
              "comment_end_string", defaults.COMMENT_END_STRING
          ),
          options.get("line_statement_prefix")
          or defaults.LINE_STATEMENT_PREFIX,
          options.get("line_comment_prefix")
          or defaults.LINE_COMMENT_PREFIX,
          getbool(options, "trim_blocks", defaults.TRIM_BLOCKS),
          getbool(options, "lstrip_blocks", defaults.LSTRIP_BLOCKS),
          defaults.NEWLINE_SEQUENCE,
          getbool(
              options,
              "keep_trailing_newline",
              defaults.KEEP_TRAILING_NEWLINE,
          ),
          tuple(extensions),
          cache_size=0,
          auto_reload=False,
      )
  
      if getbool(options, "trimmed"):
          environment.policies["ext.i18n.trimmed"] = True
      if getbool(options, "newstyle_gettext"):
          environment.newstyle_gettext = True  # type: ignore
  
      source = fileobj.read().decode(options.get("encoding", "utf-8"))
      try:
          node = environment.parse(source)
          tokens = list(environment.lex(environment.preprocess(source)))
      except TemplateSyntaxError:
          if not silent:
              raise
          # skip templates with syntax errors
          return
  
      finder = _CommentFinder(tokens, comment_tags)
      for lineno, func, message in extract_from_ast(node, keywords):
          yield lineno, func, message, finder.find_comments(lineno)
  
imports: import pprint
  import re
  import typing
  from markupsafe import Markup
  from .None import defaults
  from .None import nodes
  from .environment import Environment
  from .exceptions import TemplateAssertionError
  from .exceptions import TemplateSyntaxError
  from .runtime import concat
  from .runtime import Context
  from .runtime import Undefined
  from .utils import import_string
  from .utils import pass_context
label_desc: Use image node_id 7 for calling a global function with example usage: babel_extract(fileobj, keywords, comment_tags, options) and returns: unknown