This is the line that is causing the redirect loop:
RewriteRule ^(en|de)/(.*)$ $2?lang=$1&%{query_STRING} [R=301,L]
Because it is redirecting the browser to /?lang=en
(for example). Then the first rule:
RewriteRule ^$ en/ [R=301,L]
Redirects it to /en/?lang=en
, then the last rule redirects it to /?lang=en
, then the first rule, etc.
You probably meant the last rule to be internal, additionally, your first rule needs to check if there's already a query string parameter, "lang":
RewriteEngine On
RewriteBase /
# empty url -> redirect to en/
RewriteCond %{QUERY_STRING} !lang=(en|de)
RewriteRule ^$ en/ [R=301,L]
# url is ONLY '/en' or '/de' -> redirect to /en/ or /de/ (adding slash)
RewriteRule ^(en|de)$ $1/ [R=301,L]
# now all urls have en/ de/ -> parse them
RewriteRule ^(en|de)/(.*)$ $2?lang=$1&%{query_STRING} [L]
# no "R=301" here --------------------------------------^
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…