Yeah, this is pretty similar to how I would handle it (coming from someone who does materials, not necessarily UI).
I think the biggest optimization you could make is controlling changes within the shader instead of through external code, since then you wouldn’t need to update the player/camera direction every tick.
This gives you a full 4 point rotational value in one float, which you could then modify to the correct range and add to your texture coordinates to get your compass rotation. This would also theoretically give you perfect tiling.
I imagine the map icons would still have to be controlled through code though, as doing it through a shader would be pointless unless you have a set maximum number of markers and that number is reasonably low.
For the localization issue, I imagine the best solution that mixes optimization with ease of use is to separate the 4 cardinal values out into a separate texture, which you can then easily replace with the correct letters, like you mentioned. Then just apply the same rotational logic to keep it in line.
Totally just my opinion as a non-expert! Sounds to me like the way you handled it makes complete sense.