Add i18n vendor overlays and dynamic bundling

- Add opt-in vendor overlays under src/env/locales/<env>
  (and optional variant), merged on top of base locales at runtime.
- Auto-discover and bundle all base locale JSON files
  in src/locales/.
- Example: move dump type labels under pageDumps.dumpTypes;
  read vendor-only dump labels from overlays.
- Docs: update i18n guidelines and env README (formatting fixes).
- Tests: add focused unit tests for overlays and locale aliases.

Tested:
- Unit: i18n.locale-alias.spec.js, i18n.vendor.spec.js (passing)
- Manual: Verified dynamic locale discovery and overlay merge in UI

Change-Id: I8eae2bfec0e9622bafdafac3168dbf96650e8ae8
Signed-off-by: jason westover <jwestover@nvidia.com>
diff --git a/src/i18n.js b/src/i18n.js
index 2580784..65c7d1f 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -1,29 +1,94 @@
 import { createI18n } from 'vue-i18n';
+import { deepMerge } from './utilities/objectUtils';
 
-import en_us from './locales/en-US.json';
-import ru_ru from './locales/ru-RU.json';
-import ka_ge from './locales/ka-GE.json';
-
-function loadLocaleMessages() {
-  const messages = {
-    'en-US': en_us,
-    'ka-GE': ka_ge,
-    'ru-RU': ru_ru,
-  };
+export function loadBaseLocaleMessages() {
+  const context = require.context(
+    './locales',
+    true,
+    /[A-Za-z0-9-_,\s]+\.json$/i,
+  );
+  const messages = {};
+  context.keys().forEach((key) => {
+    const match = key.match(/([A-Za-z0-9-_]+)\.json$/i);
+    if (!match) return;
+    const locale = match[1];
+    const mod = context(key);
+    messages[locale] = mod && mod.default ? mod.default : mod;
+  });
   return messages;
 }
 
-const i18n = createI18n({
-  // Get default locale from local storage
-  locale: window.localStorage.getItem('storedLanguage'),
-  // Locales that don't exist will fallback to English
-  fallbackLocale: 'en-US',
-  // Falling back to fallbackLocale generates two console warnings
-  // Silent fallback suppresses console warnings when using fallback
-  silentFallbackWarn: true,
-  messages: loadLocaleMessages(),
-  globalInjection: false,
-  legacy: false,
-});
+export function loadEnvLocaleMessages(envName) {
+  if (!envName) return {};
+  const envMessages = {};
+  const envLocales = require.context(
+    './env/locales',
+    true,
+    /[A-Za-z0-9-_,\s]+\.json$/i,
+  );
+  const vendorRoot = String(envName).split('-')[0];
+  const candidates =
+    vendorRoot && vendorRoot !== envName ? [vendorRoot, envName] : [envName];
+  candidates.forEach((candidate) => {
+    envLocales.keys().forEach((key) => {
+      if (!key.includes(`/${candidate}/`)) return;
+      const localeMatch = key.match(/([A-Za-z0-9-_]+)\.json$/i);
+      if (!localeMatch) return;
+      const locale = localeMatch[1];
+      const mod = envLocales(key);
+      const bundle = mod && mod.default ? mod.default : mod;
+      envMessages[locale] = deepMerge(envMessages[locale] || {}, bundle);
+    });
+  });
+  return envMessages;
+}
 
-export default i18n;
+export function createI18nInstance(
+  envName,
+  locale,
+  loadEnv = loadEnvLocaleMessages,
+  loadBase = loadBaseLocaleMessages,
+) {
+  const base = loadBase();
+  const env = loadEnv(envName);
+  const messages = { ...base };
+  Object.keys(env).forEach((loc) => {
+    messages[loc] = deepMerge(base[loc] || {}, env[loc]);
+  });
+
+  const addAlias = (alias, target) => {
+    if (!messages[alias] && messages[target])
+      messages[alias] = messages[target];
+  };
+  addAlias('en', 'en-US');
+  addAlias('ru', 'ru-RU');
+  addAlias('zh', 'zh-CN');
+  addAlias('ka', 'ka-GE');
+
+  const normalize = (val) => {
+    if (!val) return undefined;
+    const s = String(val);
+    if (s === 'en') return 'en-US';
+    if (s === 'ru') return 'ru-RU';
+    if (s === 'zh') return 'zh-CN';
+    if (s === 'ka') return 'ka-GE';
+    return s;
+  };
+
+  return createI18n({
+    locale: normalize(locale),
+    // Locales that don't exist will fallback to English
+    fallbackLocale: 'en-US',
+    // Falling back to fallbackLocale generates two console warnings
+    // Silent fallback suppresses console warnings when using fallback
+    silentFallbackWarn: true,
+    messages,
+    globalInjection: false,
+    legacy: false,
+  });
+}
+
+const envName = process.env.VUE_APP_ENV_NAME;
+// Get default locale from local storage
+const stored = window.localStorage.getItem('storedLanguage');
+export default createI18nInstance(envName, stored);