code: def extract_from_ast(
      ast: nodes.Template,
      gettext_functions: t.Sequence[str] = GETTEXT_FUNCTIONS,
      babel_style: bool = True,
  ) -> t.Iterator[
      t.Tuple[
          int,
          str,
          t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]],
      ]
  ]:
      """Extract localizable strings from the given template node.  Per
      default this function returns matches in babel style that means non string
      parameters as well as keyword arguments are returned as `None`.  This
      allows Babel to figure out what you really meant if you are using
      gettext functions that allow keyword arguments for placeholder expansion.
      If you don't want that behavior set the `babel_style` parameter to `False`
      which causes only strings to be returned and parameters are always stored
      in tuples.  As a consequence invalid gettext calls (calls without a single
      string parameter or string parameters after non-string parameters) are
      skipped.
  
      This example explains the behavior:
  
      >>> from jinja2 import Environment
      >>> env = Environment()
      >>> node = env.parse('{{ (_("foo"), _(), ngettext("foo", "bar", 42)) }}')
      >>> list(extract_from_ast(node))
      [(1, '_', 'foo'), (1, '_', ()), (1, 'ngettext', ('foo', 'bar', None))]
      >>> list(extract_from_ast(node, babel_style=False))
      [(1, '_', ('foo',)), (1, 'ngettext', ('foo', 'bar'))]
  
      For every string found this function yields a ``(lineno, function,
      message)`` tuple, where:
  
      * ``lineno`` is the number of the line on which the string was found,
      * ``function`` is the name of the ``gettext`` function used (if the
        string was extracted from embedded Python code), and
      *   ``message`` is the string, or a tuple of strings for functions
           with multiple string arguments.
  
      This extraction function operates on the AST and is because of that unable
      to extract any comments.  For comment support you have to use the babel
      extraction interface or extract comments yourself.
      """
      out: t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]]
  
      for node in ast.find_all(nodes.Call):
          if (
              not isinstance(node.node, nodes.Name)
              or node.node.name not in gettext_functions
          ):
              continue
  
          strings: t.List[t.Optional[str]] = []
  
          for arg in node.args:
              if isinstance(arg, nodes.Const) and isinstance(
                  arg.value, str
              ):
                  strings.append(arg.value)
              else:
                  strings.append(None)
  
          for _ in node.kwargs:
              strings.append(None)
          if node.dyn_args is not None:
              strings.append(None)
          if node.dyn_kwargs is not None:
              strings.append(None)
  
          if not babel_style:
              out = tuple(x for x in strings if x is not None)
  
              if not out:
                  continue
          else:
              if len(strings) == 1:
                  out = strings[0]
              else:
                  out = tuple(strings)
  
          yield node.lineno, node.node.name, out
  
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 6 for calling a global function with example usage: extract_from_ast(ast, gettext_functions, babel_style) without return types