withastro / adapters

Home for Astro's core maintained adapters
69 stars 41 forks source link

i18next translations not being loaded with astrojs/netlify v5.3.3 and later on output: server #346

Closed tobbicool closed 3 months ago

tobbicool commented 3 months ago

Astro Info

Astro                    v4.12.2
Node                     v18.18.0
System                   Windows (x64)
Package Manager          npm
Output                   server
Adapter                  @astrojs/netlify
Integrations             none

Describe the Bug

I recently wanted to add a middleware file in my Astro project because I use translations in my project and wanted it to redirect to the right page automatically. I use i18next's general js library and NOT astro-i18next. So to get the middleware to work, I had change the output to server and use the netlify adapter, but with astrojs/netlify v5.3.3 and later the translations don't work. I.e. I only see the translation keys, not the actual translations. With astrojs/netlify v5.0.0 and v5.3.2 it works completely fine, and that is with the latest version of Astro.

Also, everything seems to work completely fine on my localhost, but when I deploy with Netlify to my domain, I get the issue. The deploy is published without any errors, and there are no errors on either the localhost or the domain. I am not able to recreate the issue with astro.new, possibly because the code works completely fine on my localhost. In the minimal reproduction I have linked to here, the translations work just fine, but I tried to deploy it and the issue is still there, but only on the domain.

UPDATE: On Netlify I get this error: ERROR Failed to load translations for en/common: [Error: ENOENT: no such file or directory, open '/var/task/public/locales/en/common.json'] { errno: -2, code: 'ENOENT', syscall: 'open', path: '/var/task/public/locales/en/common.json' }

image

What's the expected result?

I obviously expect to see all the translations and not just the keys.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-g4pecm?file=astro.config.mjs

Participation

tobbicool commented 3 months ago

Turns out the issue was on my part. I fixed the i18n.js file. Here it is if anyone wonders:

import i18next from 'i18next';

export const supportedLngs = ['en', 'no'];
export const defaultLng = 'en';

export const languageMapping = {
  'nb': 'no',
  'nn': 'no',
  'nb-no': 'no',
  'nn-no': 'no',
  'en-us': 'en',
  'en-gb': 'en',
};

export const namespaces = ['common', 'routes', 'char-info'];

const i18n = i18next.createInstance();

import fs from 'fs/promises';
import path from 'path';

export async function loadTranslations(lng, ns) {
  if (typeof window === 'undefined') {
    // Server-side: Use fs and path
    const possiblePaths = [
      path.join('public', 'locales', lng, `${ns}.json`),
      // path.join('locales', lng, `${ns}.json`),
      // path.join(process.cwd(), 'public', 'locales', lng, `${ns}.json`),
      // path.join(process.cwd(), 'dist', 'locales', lng, `${ns}.json`),
      // path.join(process.cwd(), 'locales', lng, `${ns}.json`),
      // path.join('/var/task', 'dist', 'locales', lng, `${ns}.json`),
      // path.join('/var/task', 'locales', lng, `${ns}.json`),
    ];

    for (const filePath of possiblePaths) {
      try {
        console.log(`Attempting to read file from: ${filePath}`);
        const data = await fs.readFile(filePath, 'utf8');
        console.log(`Successfully read file from: ${filePath}`);
        return JSON.parse(data);
      } catch (error) {
        console.error(`Failed to read file from ${filePath}:`, error.message);
      }
    }
    console.error(`Failed to load translations for ${lng}/${ns} from any location`);
    return {};
  } else {
    // Client-side: Fetch from an API endpoint
    try {
      const response = await fetch(`/api/translations/${lng}/${ns}`);
      return await response.json();
    } catch (error) {
      console.error(`Failed to load translations for ${lng}/${ns}:`, error);
      return {};
    }
  }
}

export async function initI18n() {
  const resources = {};
  for (const lng of supportedLngs) {
    resources[lng] = {};
    for (const ns of namespaces) {
      resources[lng][ns] = await loadTranslations(lng, ns);
    }
  }

  await i18n.init({
    fallbackLng: defaultLng,
    supportedLngs,
    ns: namespaces,
    defaultNS: 'common',
    resources,
    interpolation: {
      escapeValue: false // This allows HTML in translations
    }
  });

  return i18n;
}

export { i18n };