Using _e() or __() to translate text with div

None of them are correct. These APIs are not intended for dynamic data or content in the database.

This would be the best practice answer:

echo '<h2 class="title">';
esc_html_e( 'static string', 'text-domain' );
echo '</h2>';

If you want to translate posts and other database user entered content, use a translation plugin, not the localisation API.

But Why?

You should never use variables as the first parameter of a localisation API call.

Aside from being extreme bad practice, it means the string will not get picked up by tools, so it’s impossible to generate translation files to translaters.

It does not matter how you pass $var to the function, it will always be incorrect. Do not pass variables to localisation functions in WordPress. These functions are intended for static strings, not dynamic values.

If you want to localise content from the database, this API is not the way to do it.

HTML tags

Localised strings shouldn’t include H2 tags and other HTML tags, but instead provide the text content that goes in those tags. There are rare cases when you do, in which case __() and wp_kses_post or sprintf can be useful.

_e() vs __()

_e() is equivalent to echo __()

Why are _e and __ wrong?

Because neither do escaping.

This is the canonical correct answer:

echo '<h2 class="title">';
esc_html_e( 'static string', 'text-domain' );
echo '</h2>';

esc_html_e( is shorthand for echo esc_html( __(. We know that inside the H2 tag there will be text, but no tags, so we use esc_html to escape any HTML that appears

If this were an attribute of a tag, then it would be attribute="<?php esc_attr_e(...); ?>"

So then, why does __( etc exist? Because escaping has to happen as late as possible, and only once. Otherwise we run the risk of double escaping strings.

Fixing The printf example

We can escape the localised string prior to passing it to printf allowing it to be escaped:

printf( '<h2 class="title">%s</h2>', esc_html__( 'static string','text-domain' )  );

So How Do You Translate Dynamic Content?

If you want to enable posts/terms/titles/etc in multiple languages, you need a translation plugin. The i18n APIs are for hardcoded static strings, not database or generated content.