Looping is fine in Julia, so no need to replace it by recursion. One could use broadcasting and dispatch (hiding the if) though:
updatekeys(f, v) = v # Base case, i.e., leave atomic `v` alone
updatekeys(f, v::AbstractDict) = Dict(zip(f.(keys(v)),
updatekeys.(Ref(f), values(v))))
# Works just like your dict_key_to_symbol_v2
updatekeys(Symbol, d3lvl)