@vyxos/astro-i18next
Version: 
I18next integration for Astro with dynamic namespace loading.
832 lines (789 loc) • 27.4 kB
JavaScript
;
var fs = require('fs');
var pathe = require('pathe');
var module$1 = require('module');
var path = require('path');
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
function _interopNamespace(e) {
  if (e && e.__esModule) return e;
  var n = Object.create(null);
  if (e) {
    Object.keys(e).forEach(function (k) {
      if (k !== 'default') {
        var d = Object.getOwnPropertyDescriptor(e, k);
        Object.defineProperty(n, k, d.get ? d : {
          enumerable: true,
          get: function () { return e[k]; }
        });
      }
    });
  }
  n.default = e;
  return Object.freeze(n);
}
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
// src/config.ts
function applyInternalDefaults(options) {
  return {
    translationsDir: options.translationsDir ?? defaultOptions.translationsDir,
    generatedTypes: {
      dirPath: options?.generatedTypes?.dirPath ?? defaultOptions.generatedTypes.dirPath,
      fileName: options?.generatedTypes?.fileName ?? defaultOptions.generatedTypes.fileName
    }
  };
}
var defaultOptions = {
  generatedTypes: {
    dirPath: "types",
    fileName: "i18next-resources"
  },
  translationsDir: "i18n"
};
// src/constants.ts
var INTEGRATION_NAME = "@vyxos/astro-i18next";
var isBrowser = typeof window !== "undefined";
var nodeRequire = isBrowser ? null : module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
var colorTimestamp = (value) => {
  if (isBrowser || !nodeRequire) return value;
  try {
    const { dim } = nodeRequire("kleur/colors");
    return dim(value);
  } catch {
    return value;
  }
};
var colorIntegration = (value) => {
  if (isBrowser || !nodeRequire) return value;
  try {
    const { bold, green } = nodeRequire("kleur/colors");
    return bold(green(value));
  } catch {
    return value;
  }
};
var colorWarn = (value) => {
  if (isBrowser || !nodeRequire) return value;
  try {
    const { yellow } = nodeRequire("kleur/colors");
    return yellow(value);
  } catch {
    return value;
  }
};
var colorError = (value) => {
  if (isBrowser || !nodeRequire) return value;
  try {
    const { red } = nodeRequire("kleur/colors");
    return red(value);
  } catch {
    return value;
  }
};
var colorWarnPrefix = (value) => {
  if (isBrowser || !nodeRequire) return value;
  try {
    const { bold, yellow } = nodeRequire("kleur/colors");
    return bold(yellow(value));
  } catch {
    return value;
  }
};
var colorErrorPrefix = (value) => {
  if (isBrowser || !nodeRequire) return value;
  try {
    const { red } = nodeRequire("kleur/colors");
    return red(value);
  } catch {
    return value;
  }
};
// src/logger/index.ts
function log(message, label = INTEGRATION_NAME) {
  const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
    hour12: false,
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit"
  });
  console.log(
    `${colorTimestamp(timestamp)} ${colorIntegration(`[${label}]`)} ${message}`
  );
}
function logError(error, label = INTEGRATION_NAME) {
  const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
    hour12: false,
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit"
  });
  console.error(
    `${colorTimestamp(timestamp)} ${colorIntegration(`[${label}]`)} ${colorErrorPrefix(`[ERROR]`)} ${colorError(error)}`
  );
}
function logWarn(message, label = INTEGRATION_NAME) {
  const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
    hour12: false,
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit"
  });
  console.warn(
    `${colorTimestamp(timestamp)} ${colorIntegration(`[${label}]`)} ${colorWarnPrefix(`[WARN]`)} ${colorWarn(message)}`
  );
}
// src/loader/translation-loader.ts
function loadTranslation(filePath) {
  if (!fs.existsSync(filePath)) {
    logWarn(`Translation file not found: ${filePath}`);
    return {};
  }
  try {
    const content = fs.readFileSync(filePath, "utf-8");
    const parsed = JSON.parse(content);
    if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
      logError(
        `Invalid translation file format: ${filePath}
Expected JSON object, got ${typeof parsed}`
      );
      return {};
    }
    return parsed;
  } catch (error) {
    logError(
      `Failed to parse translation file: ${filePath}. Original error: ${error instanceof Error ? error.message : String(error)}`
    );
    return {};
  }
}
function loadAllTranslations(srcDir, internalOptions, i18nextOptions) {
  const allTranslations = {};
  const localeFilesData = getAllFilePaths(
    srcDir,
    internalOptions,
    i18nextOptions
  );
  for (const data of localeFilesData) {
    if (allTranslations[data.locale] === void 0) {
      allTranslations[data.locale] = {};
    }
    allTranslations[data.locale][data.namespace] = loadTranslation(data.path);
  }
  return allTranslations;
}
function scanDirectoryRecursively(currentPath, localeBasePath, locale, filePaths) {
  try {
    const entries = fs.readdirSync(currentPath);
    for (const entry of entries) {
      const entryPath = pathe.resolve(currentPath, entry);
      const stats = fs.statSync(entryPath);
      if (stats.isDirectory()) {
        scanDirectoryRecursively(entryPath, localeBasePath, locale, filePaths);
      } else if (entry.endsWith(".json")) {
        const relativePath = entryPath.substring(localeBasePath.length + 1);
        const pathParts = relativePath.split(/[/\\]/);
        pathParts[pathParts.length - 1] = pathParts[pathParts.length - 1].replace(".json", "");
        const namespace = pathParts.join(".");
        filePaths.push({ path: entryPath, locale, namespace });
      }
    }
  } catch (_error) {
    logWarn(`Failed to scan directory: ${currentPath}`);
  }
}
function getAllFilePaths(srcDir, internalOptions, i18nextOptions) {
  const filePaths = [];
  if (i18nextOptions.supportedLngs === false || i18nextOptions.supportedLngs === void 0) {
    const translationDirPath = pathe.resolve(srcDir, internalOptions.translationsDir);
    if (!fs.existsSync(translationDirPath)) {
      return filePaths;
    }
    try {
      const localeEntries = fs.readdirSync(translationDirPath);
      for (const localeEntry of localeEntries) {
        const localeDir = pathe.resolve(translationDirPath, localeEntry);
        if (fs.statSync(localeDir).isDirectory()) {
          const locale = localeEntry;
          scanDirectoryRecursively(localeDir, localeDir, locale, filePaths);
        }
      }
    } catch (_error) {
      logError(`Failed to scan translation directory: ${translationDirPath}`);
      return filePaths;
    }
    return filePaths;
  }
  if (Array.isArray(i18nextOptions.supportedLngs)) {
    let namespaces = [];
    if (i18nextOptions.ns === void 0) {
      const translationDirPath = pathe.resolve(
        srcDir,
        internalOptions.translationsDir
      );
      const discoveredNamespaces = /* @__PURE__ */ new Set();
      for (const locale of i18nextOptions.supportedLngs) {
        const localeDir = pathe.resolve(translationDirPath, locale);
        if (fs.existsSync(localeDir) && fs.statSync(localeDir).isDirectory()) {
          const tempFilePaths = [];
          scanDirectoryRecursively(localeDir, localeDir, locale, tempFilePaths);
          tempFilePaths.forEach(
            ({ namespace }) => discoveredNamespaces.add(namespace)
          );
        }
      }
      namespaces = Array.from(discoveredNamespaces);
      if (namespaces.length === 0) {
        namespaces = ["translation"];
      }
    } else if (typeof i18nextOptions.ns === "string") {
      namespaces = [i18nextOptions.ns];
    } else if (Array.isArray(i18nextOptions.ns)) {
      namespaces = i18nextOptions.ns;
    }
    for (const locale of i18nextOptions.supportedLngs) {
      for (const namespace of namespaces) {
        const filePath = getFilePath(
          locale,
          namespace,
          srcDir,
          internalOptions.translationsDir
        );
        filePaths.push({ path: filePath, locale, namespace });
      }
    }
  }
  return filePaths;
}
function getFilePath(locale, namespace, srcDir, translationDirectoryPath) {
  const namespacePath = namespace.replace(/\./g, "/");
  return pathe.resolve(
    srcDir,
    translationDirectoryPath,
    `${locale}/${namespacePath}.json`
  );
}
function hasJsonFilesRecursively(dirPath) {
  try {
    const entries = fs.readdirSync(dirPath);
    for (const entry of entries) {
      const entryPath = pathe.resolve(dirPath, entry);
      const stats = fs.statSync(entryPath);
      if (stats.isDirectory()) {
        if (hasJsonFilesRecursively(entryPath)) {
          return true;
        }
      } else if (entry.endsWith(".json")) {
        return true;
      }
    }
    return false;
  } catch {
    return false;
  }
}
function discoverAvailableLanguages(srcDir, translationsDir) {
  const translationDirPath = pathe.resolve(srcDir, translationsDir);
  if (!fs.existsSync(translationDirPath)) {
    logWarn(`Translation directory not found: ${translationDirPath}`);
    return [];
  }
  try {
    const localeEntries = fs.readdirSync(translationDirPath);
    const availableLocales = [];
    for (const localeEntry of localeEntries) {
      const localeDir = pathe.resolve(translationDirPath, localeEntry);
      if (fs.statSync(localeDir).isDirectory()) {
        if (hasJsonFilesRecursively(localeDir)) {
          availableLocales.push(localeEntry);
        }
      }
    }
    return availableLocales;
  } catch (_error) {
    logError(`Failed to scan translation directory: ${translationDirPath}`);
    return [];
  }
}
// src/scripts/client.ts
function generateClientScript(baseConfig, internalOptions, i18nextOptions) {
  return `
    import i18next from "i18next";
    import LanguageDetector from "i18next-browser-languagedetector";
    
    // CRITICAL: Read server state synchronously (react-i18next SSR pattern)
    const initialI18nStore = typeof window !== 'undefined' ? window.__initialI18nStore__ : null;
    const initialLanguage = typeof window !== 'undefined' ? window.__initialLanguage__ : null;
    
    if (initialI18nStore && initialLanguage) {
      // SYNCHRONOUS initialization with exact server resources
      i18next.init({
        ...${JSON.stringify(baseConfig)},
        lng: initialLanguage,
        resources: initialI18nStore,
        initImmediate: false,  // CRITICAL: Synchronous initialization
        fallbackLng: false,
        integrationOptions: ${JSON.stringify({ ...internalOptions, ...i18nextOptions })}
      }).then(() => {
        setupTranslationWrapper();
        setupDynamicLoading();
      }).catch(err => console.error('[ASTRO-I18N] SSR hydration initialization failed:', err));
      
    } else {
      // Fallback: Dynamic loading for non-SSR or missing server data
      const dynamicBackend = {
        type: 'backend',
        init: function() {},
        read: async function(language, namespace, callback) {
          try {
            const { loadTranslation } = await import('virtual:i18n-loader');
            const data = await loadTranslation(language, namespace);
            callback(null, data);
          } catch (err) {
            console.warn(\`Failed to load \${language}/\${namespace}:\`, err);
            callback(null, {});
          }
        }
      };
      
      i18next
        .use(LanguageDetector)
        .use(dynamicBackend)
        .init({
          ...${JSON.stringify(baseConfig)},
          fallbackLng: false,
          initImmediate: true,
          detection: {
            order: ["htmlTag", "path"],
            lookupFromPathIndex: 0,
            caches: []
          },
          load: 'currentOnly',
          partialBundledLanguages: true,
          integrationOptions: ${JSON.stringify({ ...internalOptions, ...i18nextOptions })}
        }).then(() => {
          setupTranslationWrapper();
          setupDynamicLoading();
        }).catch(err => console.error('Dynamic initialization failed:', err));
    }
    
    // Setup translation wrapper with dev warnings
    function setupTranslationWrapper() {
      const originalT = i18next.t;
      i18next.t = function (...args) {
        const key = args[0];
        const lastArg = args[args.length - 1];
        const options = typeof lastArg === 'object' && lastArg !== null ? lastArg : undefined;
        let namespace;
        if (typeof key === 'string' && key.includes(':')) {
          namespace = key.split(':')[0];
        } else if (options && 'ns' in options && typeof options.ns === 'string') {
          namespace = options.ns;
        }
        if (import.meta.env.DEV && namespace) {
          const currentLanguage = i18next.language;
          if (!i18next.hasResourceBundle(currentLanguage, namespace)) {
            console.warn(
              \`Warning: Translation key "\${String(key)}" is being accessed \` +
              \`for namespace "\${namespace}" in locale "\${currentLanguage}", \` +
              \`but this namespace is not currently loaded. Ensure '\${namespace}' is loaded \` +
              \`using 'loadNamespacesForRoute' or 'useLoadNamespaces'.\`
            );
          }
        }
        return originalT.apply(this, args);
      };
    }
    
    // Setup dynamic loading functions for SPA navigation
    function setupDynamicLoading() {
      window.__i18nLoadNamespaces = async function(namespaces) {
        const currentLang = i18next.language${baseConfig.lng ? ` || '${baseConfig.lng}'` : ""};
        const promises = namespaces.map(ns => 
          new Promise((resolve) => {
            if (i18next.hasResourceBundle(currentLang, ns)) {
              resolve(null);
            } else {
              i18next.loadNamespaces(ns, resolve);
            }
          })
        );
        await Promise.all(promises);
      };
    }
  `;
}
// src/scripts/server.ts
function generateServerScript(baseConfig, allTranslations, internalOptions, i18nextOptions) {
  return `
    import i18next from "i18next";
    
    const resources = ${JSON.stringify(allTranslations)};
    const usedNamespaces = new Set();
    
    i18next.init({
      ...${JSON.stringify(baseConfig)},
      resources,
      initImmediate: true,
      integrationOptions: ${JSON.stringify({ ...internalOptions, ...i18nextOptions })}
    }).then(() => {
      // Track namespace usage during SSR
      const originalT = i18next.t;
      i18next.t = function(...args) {
        const key = args[0];
        const lastArg = args[args.length - 1];
        const options = typeof lastArg === 'object' && lastArg !== null ? lastArg : undefined;
        
        let namespace;
        if (typeof key === 'string' && key.includes(':')) {
          namespace = key.split(':')[0];
        } else if (options && 'ns' in options && typeof options.ns === 'string') {
          namespace = options.ns;
        } else {
          namespace = '${baseConfig.defaultNS || "translation"}';
        }
        
        if (namespace) {
          usedNamespaces.add(namespace);
        }
        
        return originalT.apply(this, args);
      };
      
      // CRITICAL: Serialize exact server state for client hydration
      if (typeof window !== 'undefined') {
        const currentLang = i18next.language;
        
        // Extract ONLY the resources that were actually used during SSR
        const usedResources = {};
        usedNamespaces.forEach(ns => {
          if (resources[currentLang] && resources[currentLang][ns]) {
            if (!usedResources[currentLang]) usedResources[currentLang] = {};
            usedResources[currentLang][ns] = resources[currentLang][ns];
          }
        });
        
        // Serialize for synchronous client initialization (react-i18next SSR pattern)
        window.__initialI18nStore__ = usedResources;
        window.__initialLanguage__ = currentLang;
      }
    }).catch(err => console.error('[${INTEGRATION_NAME}] Server initialization failed:', err));
  `;
}
// src/scripts/ssg.ts
function generateSSGSerializationScript(baseConfig, allTranslations, _internalOptions) {
  const supportedLanguages = baseConfig.supportedLngs || Object.keys(allTranslations);
  const defaultNamespace = baseConfig.defaultNS || "translation";
  const namespaces = baseConfig.ns || [defaultNamespace];
  return `
    // CRITICAL: Detect language from current URL/HTML for SSG pages
    (function() {
      const detectSSGLanguage = function() {
        // Try path-based detection first  
        const pathMatch = window.location.pathname.match(/^\\/([a-z]{2}(?:-[A-Z]{2})?)/);
        if (pathMatch) {
          const detectedLang = pathMatch[1];
          const supportedLangs = ${JSON.stringify(supportedLanguages)};
          if (supportedLangs.includes(detectedLang)) {
            return detectedLang;
          }
        }
        // Try HTML lang attribute
        const htmlLang = document.documentElement.lang;
        if (htmlLang) {
          const supportedLangs = ${JSON.stringify(supportedLanguages)};
          if (supportedLangs.includes(htmlLang)) {
            return htmlLang;
          }
        }
        // Fallback to default
        return "${baseConfig.lng || supportedLanguages[0]}";
      };
      const currentLanguage = detectSSGLanguage();
      const allTranslations = ${JSON.stringify(allTranslations)};
      const expectedNamespaces = ${JSON.stringify(namespaces)};
      // Extract resources for the detected language and expected namespaces
      const ssgResources = {};
      if (allTranslations[currentLanguage]) {
        ssgResources[currentLanguage] = {};
        expectedNamespaces.forEach(function(ns) {
          if (allTranslations[currentLanguage][ns]) {
            ssgResources[currentLanguage][ns] = allTranslations[currentLanguage][ns];
          }
        });
      }
      // Serialize for synchronous client access
      window.__initialI18nStore__ = ssgResources;
      window.__initialLanguage__ = currentLanguage;
    })();
  `;
}
// node_modules/.pnpm/i18next-resources-for-ts@1.6.0/node_modules/i18next-resources-for-ts/dist/esm/mergeResources.js
function mergeResources(namespaces) {
  return namespaces.reduce((prev, cur) => {
    prev[cur.name] = cur.resources;
    return prev;
  }, {});
}
// node_modules/.pnpm/i18next-resources-for-ts@1.6.0/node_modules/i18next-resources-for-ts/dist/esm/mergeResourcesAsInterface.js
function mergeResourcesAsInterface(namespaces) {
  const resources = mergeResources(namespaces);
  let interfaceFileContent = "interface Resources ";
  interfaceFileContent += JSON.stringify(resources, null, 2);
  interfaceFileContent += "\n\nexport default Resources;\n";
  return interfaceFileContent;
}
function toNamespaceArray(translationMap, lng) {
  const localeForTypes = !lng || lng === "cimode" ? Object.keys(translationMap)[0] : lng;
  return Object.entries(translationMap[localeForTypes]).map(
    ([namespaceKey, resources]) => ({
      name: namespaceKey,
      resources
    })
  );
}
function generateTypescriptDefinitions(namespaces, outputDirPath, internalOptions, i18nextOptions) {
  try {
    const INTERFACE_OUTPUT_FILE = path.join(
      pathe.resolve(outputDirPath, internalOptions.generatedTypes.dirPath),
      `${internalOptions.generatedTypes.fileName}.d.ts`
    );
    const typeDefinitionFile = mergeResourcesAsInterface(
      toNamespaceArray(namespaces, i18nextOptions.lng)
    );
    const final = `
import "i18next";
declare module "i18next" {
  interface CustomTypeOptions {
    defaultNS: "${i18nextOptions.defaultNS === false ? "false" : i18nextOptions.defaultNS || "translation"}";
    resources: Resources;
  }
}
${typeDefinitionFile}
`;
    const namespacesLength = Object.keys(Object.values(namespaces)[0]).length;
    const RELATIVE_OUTPUT_PATH = pathe.relative(process.cwd(), INTERFACE_OUTPUT_FILE);
    fs__namespace.writeFileSync(INTERFACE_OUTPUT_FILE, final, {
      encoding: "utf-8",
      flag: "w"
    });
    log(
      `Created interface file for ${namespacesLength !== void 0 ? namespacesLength : 0} namespaces: ${RELATIVE_OUTPUT_PATH}`
    );
  } catch (error) {
    log(` Failed to create interface resources file: ${error}`);
  }
}
// src/validation.ts
var I18nConfigError = class extends Error {
  constructor(message, field) {
    super(message);
    this.field = field;
    this.name = "I18nConfigError";
  }
};
function validateOptions(options) {
  if (!options) {
    throw new I18nConfigError("Integration options are required");
  }
}
// src/vite-plugin.ts
function createI18nVitePlugin(srcDir, internalOptions, i18nextOptions) {
  return {
    name: "i18n-virtual-modules",
    resolveId(id) {
      if (id === "virtual:i18n-loader") return id;
      const match = id.match(/^virtual:i18n-translation:(.+)\/(.+)$/);
      if (match) return id;
      const virtualMatch = id.match(/^\.?\/virtual-i18n-(.+?)__(.+)\.js$/);
      if (virtualMatch) {
        const locale = virtualMatch[1];
        const namespace = virtualMatch[2];
        return `virtual:i18n-translation:${locale}/${namespace}`;
      }
      return null;
    },
    load(id) {
      if (id === "virtual:i18n-loader") {
        return generateDynamicTranslationLoader(
          srcDir,
          internalOptions,
          i18nextOptions
        );
      }
      const match = id.match(/^virtual:i18n-translation:(.+)\/(.+)$/);
      if (match) {
        const [, locale, namespace] = match;
        const translation = loadTranslation(
          getFilePath(
            locale,
            namespace,
            srcDir,
            internalOptions.translationsDir
          )
        );
        return `export default ${JSON.stringify(translation)};`;
      }
      return null;
    }
  };
}
function generateDynamicTranslationLoader(srcDir, internalOptions, i18nextOptions) {
  const importMap = [];
  const caseStatements = [];
  let locales = [];
  let namespaces = [];
  if (i18nextOptions.supportedLngs === false || i18nextOptions.supportedLngs === void 0) {
    locales = discoverAvailableLanguages(
      srcDir,
      internalOptions.translationsDir
    );
    const allFilePaths = getAllFilePaths(
      srcDir,
      internalOptions,
      i18nextOptions
    );
    const discoveredNamespaces = /* @__PURE__ */ new Set();
    allFilePaths.forEach(
      ({ namespace }) => discoveredNamespaces.add(namespace)
    );
    namespaces = Array.from(discoveredNamespaces);
    if (namespaces.length === 0) {
      if (i18nextOptions.ns === void 0) {
        namespaces = ["translation"];
      } else if (typeof i18nextOptions.ns === "string") {
        namespaces = [i18nextOptions.ns];
      } else if (Array.isArray(i18nextOptions.ns)) {
        namespaces = i18nextOptions.ns;
      }
    }
  } else if (Array.isArray(i18nextOptions.supportedLngs)) {
    locales = i18nextOptions.supportedLngs;
    if (i18nextOptions.ns === void 0) {
      const allFilePaths = getAllFilePaths(
        srcDir,
        internalOptions,
        i18nextOptions
      );
      const discoveredNamespaces = /* @__PURE__ */ new Set();
      allFilePaths.forEach(
        ({ namespace }) => discoveredNamespaces.add(namespace)
      );
      namespaces = Array.from(discoveredNamespaces);
      if (namespaces.length === 0) {
        namespaces = ["translation"];
      }
    } else if (typeof i18nextOptions.ns === "string") {
      namespaces = [i18nextOptions.ns];
    } else if (Array.isArray(i18nextOptions.ns)) {
      namespaces = i18nextOptions.ns;
    }
  }
  locales.forEach((locale) => {
    namespaces.forEach((namespace) => {
      const importVar = `${locale}_${namespace}`.replace(/[^a-zA-Z0-9_]/g, "_");
      importMap.push(
        `const ${importVar} = () => import('./virtual-i18n-${locale}__${namespace}.js');`
      );
      caseStatements.push(
        `    case '${locale}/${namespace}': return (await ${importVar}()).default || {};`
      );
    });
  });
  return `
${importMap.join("\n")}
export async function loadTranslation(locale, namespace) {
  try {
    const key = \`\${locale}/\${namespace}\`;
    switch (key) {
${caseStatements.join("\n")}
      default:
        console.warn(\`[${INTEGRATION_NAME}] Unknown translation: \${locale}/\${namespace}\`);
        return {};
    }
  } catch (err) {
    console.warn(\`[${INTEGRATION_NAME}] Failed to load translation \${locale}/\${namespace}:\`, err);
    return {};
  }
}
// Helper to preload specific namespaces
export async function preloadNamespaces(locale, namespaces) {
  const promises = namespaces.map(ns => loadTranslation(locale, ns));
  return Promise.all(promises);
}
// Available locales and namespaces for validation
export const availableLocales = ${JSON.stringify(locales)};
export const availableNamespaces = ${JSON.stringify(namespaces)};
`;
}
// src/integration.ts
function i18nIntegration(options) {
  return {
    name: INTEGRATION_NAME,
    hooks: {
      "astro:config:setup": async ({
        config,
        injectScript,
        addWatchFile,
        updateConfig,
        addMiddleware
      }) => {
        try {
          validateOptions(options);
          const internalOptions = applyInternalDefaults(options);
          const allTranslations = loadAllTranslations(
            config.srcDir.pathname,
            internalOptions,
            options.i18NextOptions
          );
          updateConfig({
            vite: {
              plugins: [
                createI18nVitePlugin(
                  config.srcDir.pathname,
                  internalOptions,
                  options.i18NextOptions
                )
              ]
            }
          });
          injectScript(
            "page-ssr",
            generateServerScript(
              options.i18NextOptions,
              allTranslations,
              internalOptions,
              options.i18NextOptions
            )
          );
          injectScript(
            "head-inline",
            generateSSGSerializationScript(
              options.i18NextOptions,
              allTranslations,
              internalOptions
            )
          );
          injectScript(
            "before-hydration",
            generateClientScript(
              options.i18NextOptions,
              internalOptions,
              options.i18NextOptions
            )
          );
          generateTypescriptDefinitions(
            allTranslations,
            config.srcDir.pathname,
            internalOptions,
            options.i18NextOptions
          );
          addMiddleware({
            entrypoint: `${INTEGRATION_NAME}/middleware`,
            order: "post"
          });
          const translationsData = getAllFilePaths(
            config.srcDir.pathname,
            internalOptions,
            options.i18NextOptions
          );
          translationsData.forEach(({ path }) => addWatchFile(path));
        } catch (error) {
          if (error instanceof Error) {
            throw new Error(
              `[${INTEGRATION_NAME}] Configuration error: ${error.message}`
            );
          }
          throw error;
        }
      }
    }
  };
}
exports.i18nIntegration = i18nIntegration;
//# sourceMappingURL=index.cjs.map
//# sourceMappingURL=index.cjs.map