Skip to content

Allow MacroComponents to emit (or also receive) elixir AST for expressions #3842

@LostKobrakai

Description

@LostKobrakai

I looked at MacroComponents a bit and I have some ideas not currently supported due to the limitations of things supported by the heex AST. One of those ideas is to make gettext more bearable to maintain in heex templates.

This could look somewhat like this – I know it would need more whitespace handling for a production take:

# Gettext MacroComponent
  #
  #   <span :type={Gettext} locale={@locale} domain="welcome">
  #     Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
  #     invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et
  #     accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren.
  #   </span>
  #
  # into
  #
  #   <span>
  #     {Gettext.with_locale(@locale, fn -> dgettext("welcome", "Lorem ipsum dolor …") end)}
  #   </span>
  #
  def transform({_, attr, _, _} = heex_ast, meta) do
    {"locale", locale_ast} = List.keyfind!(attr, "locale", 0)

    {macro, arity, args} =
      case {List.keyfind(attr, "domain", 0), List.keyfind(attr, "context", 0)} do
        {nil, nil} -> {:gettext, 1, []}
        {{"domain", domain}, nil} -> {:dgettext, 2, [domain]}
        {nil, {"context", context}} -> {:pgettext, 2, [context]}
        {{"domain", domain}, {"context", context}} -> {:dpgettext, 3, [domain, context]}
      end

    {:macro, Gettext.Macros, fun} =
      Macro.Env.expand_import(meta.env, [], macro, arity, allow_locals: false)

    heex_ast =
      postwalk(heex_ast, fn
        text when is_binary(text) ->
          case split(text) do
            [_ws1, "", _ws2] ->
              text

            [ws1, msgid, ws2] ->
              gettext_ast = fun.([context: __MODULE__], args ++ [msgid])

              with_locale =
                quote do
                  Gettext.with_locale(
                    unquote(locale_ast),
                    fn -> unquote(gettext_ast) end
                  )
                end

              [ws1, with_locale, ws2]
              text

            _ ->
              text
          end

        rest ->
          rest
      end)

    {:ok, heex_ast}
  end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions