in reply to How do I pretend a reference isn't a reference

The real problem is that you are trying to get a single function to accept two different styles of arguments. As you see, that can get you in trouble.

If you want to change the check, eval { %{$_[0]} } works best to detect a hash.

sub better { my %params = eval { %{$_[0]} } || @_; }

But in this case, the following should do fine:

sub better { my %params = @_ == 1 ? %{$_[0]} : @_; }

Of course, you could always give the sub what it wants:

bad_but_typical("$i18n"); # Force stringification

Update: Added missing curlies.