Translation text can't change, its loaded from the code archive we ourselves came from.  So I think we should do a global table that holds a cached singleton of all translations.  Its a finite cost and "leaking" them after they are needed shouldn't be a problem.

So change this code to be:

  TranslationBundle bundle = map.get(type);
  if (bundle == null) {
    bundle = lookupBundle(locale, type);
    map.putIfAbsent(type, bundle);
  }

and write a global cache:

  private static final Map<Locale, Map<Class, TranslationBundle>> cachedBundles
    = new HashMap<Locale, Map<Class, TranslationBundle>>();

  private static synchronized <T extends TranslationBundle>
  T lookupBundle(Locale locale, Class<T> type) {
    ...
  }