Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

getT on API route on Vercel (serverless) #484

Open
Fivedark opened this issue Jan 31, 2021 · 11 comments
Open

getT on API route on Vercel (serverless) #484

Fivedark opened this issue Jan 31, 2021 · 11 comments
Labels
bug Something isn't working
Milestone

Comments

@Fivedark
Copy link

First: Thanks for this great lib!

I'm using next-translate @ 1.0.1 and next @ 10.0.5, and I have trouble to use getT on my API route.

The following error occurred in production on Vercel, when calling the API:
ERROR TypeError: Cannot read property 'loadLocaleFrom' of undefined

The API is called serverless on Vercel which mean the NodeJS global didn't contain the i18nConfig, which leads to this error message.

I tried to set the config to global inside the API route:

import getT from 'next-translate/getT'

import i18n from '../../i18n.json'

const handler = async (
  req,
  res,
) => {
  global.i18nConfig = i18n
  const t = await getT(req.query.__nextLocale, 'api')

  const error = t('error')

  res.statusCode = 200
  res.setHeader('Content-Type', 'application/json')
  res.end(JSON.stringify({ error }))
}

export default handler

The error disappears, but I get only the translation key instead of the translated text.

You can reproduce this on your local machine:
Build and start Next and call the API directly without any page load, because the page load will add the config to global.

Any ideas how to resolve this?

@aralroca aralroca added the bug Something isn't working label Feb 1, 2021
@aralroca aralroca added this to the 1.0.3 milestone Feb 1, 2021
@joeriharleman
Copy link

Can confirm that this bug exists, it virtually makes next-translate impossible to use on an API.

Here's a stacktrace I'm getting in Vercel (just trying to be helpful):

2021-02-07T09:11:37.129Z	6aba0774-c6e7-487b-9f6c-3d20f2172049	ERROR	TypeError: Cannot read property 'loadLocaleFrom' of undefined
    at /var/task/node_modules/next-translate/lib/cjs/getT.js:60:37
    at step (/var/task/node_modules/next-translate/lib/cjs/getT.js:33:23)
    at Object.next (/var/task/node_modules/next-translate/lib/cjs/getT.js:14:53)
    at /var/task/node_modules/next-translate/lib/cjs/getT.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (/var/task/node_modules/next-translate/lib/cjs/getT.js:4:12)
    at getT (/var/task/node_modules/next-translate/lib/cjs/getT.js:48:12)
    at handler (/var/task/.next/serverless/pages/api/tools.js:345:77)
    at apiResolver (/var/task/node_modules/next/dist/next-server/server/api-utils.js:8:7)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
2021-02-07T09:11:37.130Z	6aba0774-c6e7-487b-9f6c-3d20f2172049	ERROR	TypeError: Cannot read property 'loadLocaleFrom' of undefined
    at /var/task/node_modules/next-translate/lib/cjs/getT.js:60:37
    at step (/var/task/node_modules/next-translate/lib/cjs/getT.js:33:23)
    at Object.next (/var/task/node_modules/next-translate/lib/cjs/getT.js:14:53)
    at /var/task/node_modules/next-translate/lib/cjs/getT.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (/var/task/node_modules/next-translate/lib/cjs/getT.js:4:12)
    at getT (/var/task/node_modules/next-translate/lib/cjs/getT.js:48:12)
    at handler (/var/task/.next/serverless/pages/api/tools.js:345:77)
    at apiResolver (/var/task/node_modules/next/dist/next-server/server/api-utils.js:8:7)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
2021-02-07T09:11:37.130Z	6aba0774-c6e7-487b-9f6c-3d20f2172049	ERROR	Unhandled Promise Rejection 	{"errorType":"Runtime.UnhandledPromiseRejection"
,"errorMessage":"TypeError: Cannot read property 'loadLocaleFrom' of undefined"
,"reason":{"errorType":"TypeError"
,"errorMessage":"Cannot read property 'loadLocaleFrom' of undefined"
,"stack":["TypeError: Cannot read property 'loadLocaleFrom' of undefined"
,"    at /var/task/node_modules/next-translate/lib/cjs/getT.js:60:37"
,"    at step (/var/task/node_modules/next-translate/lib/cjs/getT.js:33:23)"
,"    at Object.next (/var/task/node_modules/next-translate/lib/cjs/getT.js:14:53)"
,"    at /var/task/node_modules/next-translate/lib/cjs/getT.js:8:71"
,"    at new Promise (<anonymous>)"
,"    at __awaiter (/var/task/node_modules/next-translate/lib/cjs/getT.js:4:12)"
,"    at getT (/var/task/node_modules/next-translate/lib/cjs/getT.js:48:12)"
,"    at handler (/var/task/.next/serverless/pages/api/tools.js:345:77)"
,"    at apiResolver (/var/task/node_modules/next/dist/next-server/server/api-utils.js:8:7)"
,"    at processTicksAndRejections (internal/process/task_queues.js:97:5)"]}
,"promise":{}
,"stack":["Runtime.UnhandledPromiseRejection: TypeError: Cannot read property 'loadLocaleFrom' of undefined"
,"    at process.<anonymous> (/var/runtime/index.js:35:15)"
,"    at process.emit (events.js:326:22)"
,"    at processPromiseRejections (internal/process/promises.js:209:33)"
,"    at processTicksAndRejections (internal/process/task_queues.js:98:32)"]}

@guydumais
Copy link

Thanks to @aralroca and @Fivedark :)

I was having the exact same issue and after applying the solution above from @Fivedark, everything is working as expected now. For the locale, I'm passing the value to my api function. Here's my code in case it could help anyone else:

// I18N
import getT from 'next-translate/getT'
import i18n from '../i18n'

const SENDGRID_API = 'https://api.sendgrid.com/v3/mail/send'

const sendEmail = async ({ name, email, message, locale }) => {
  // I18N
  global.i18nConfig = i18n
  const t = await getT(locale, 'contact')

  /* Send to client */
  await fetch(SENDGRID_API, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${process.env.SENDGRID_API_KEY}`,
        'Accept-Language': `${locale}`
      },
      body: JSON.stringify({
        personalizations: [
          {
            to: [
              {
                email: email
              }
            ],
            subject: t('EmailSubject')
          }
        ],
        from: {
          email: 'noreply@guydumais.digital',
          name: 'Guy Dumais'
        },
        content: [
          {
            type: 'text/html',
            value: `${t('Thank You')} <b><a href='mailto:${email}'>${name}</a></b>,<br/><br/>${t('EmailConfirmation')}<br/><br/>Message:<br/>${message}`
          }
        ]
      })
  })
    
}

export default sendEmail

@aralroca aralroca modified the milestones: 1.0.6, 1.0.7 Apr 22, 2021
@aralroca aralroca modified the milestones: 1.0.7, 1.0.8 May 21, 2021
@kotsh23
Copy link

kotsh23 commented May 29, 2021

any idea how make it work guys ?
i wont re edit my all backend work to front end :S

@slevy85
Copy link
Contributor

slevy85 commented Jul 8, 2021

It is also happening on localhost, not only Vercel.
It happens when the first call made on the server is an api call.

I mean that, when I start the server, if I load a page in the browser, the subsequent api calls work fine, and global.i18nConfig is correctly loaded.
But, if the first call made to the server is an API call, then global.i18nConfig is undefined and I have this error Cannot read property 'loadLocaleFrom' of undefined.

@aralroca
Copy link
Owner

aralroca commented Jul 8, 2021

A simple workaround would be to load it manually:

import i18n from '../i18n'

global.i18nConfig = i18n

Before solving it, I would like to rethink the way of consuming the configuration...

@goellner
Copy link

@aralroca with the workaround I only get the keys and not the values returned.

And can the workaround be added once in the next.js project or do we have to add this on every api route?

@jzzfs
Copy link

jzzfs commented Jul 29, 2021

@goellner No, the workaround will need to be added in every api route where you use getT.

The following patch works for me until this issue is resolved:

// monkey-patches.ts
import getT from "next-translate/getT";
import i18n from "../i18n";

export const ensureAvailabilityOfGetT = () => {
  global.i18nConfig = i18n;
  return getT;
};

and then:

// some-api-route.ts

import { ensureAvailabilityOfGetT } from "../../../utils/api/utils/monkey-patches";

const parsedLocale = "..."; 

const getT = ensureAvailabilityOfGetT();
const errorsT = await getT(parsedLocale, "errors");
const feedbackT = await getT(parsedLocale, "feedback");

// do your thing

Once getT from next-translate works properly, refactoring will be a piece of cake.

@slevy85
Copy link
Contributor

slevy85 commented Aug 16, 2021

@goellner I had the same problem than you, only keys where return and not the values, it was because my i18n.js file didn't contain loadLocaleFrom which is needed by getT, I had to add it.

At first I had only locales, defaultLocale and pages, when I added loadLocaleFrom it worked :

{
  locales: [ 'en' ],
  defaultLocale: 'en',
  pages: { '*': [ 'common' ] },
  loadLocaleFrom: (lang, ns) =>
    import(`./locales/${lang}/${ns}.json`).then((m) => m.default),
}

@aralroca aralroca modified the milestones: 1.1.0, future Sep 18, 2021
@marc-on-github
Copy link

It's a shame that this bug/feature isn't implemented in a timely manner. Can you think about it again?

@aralroca
Copy link
Owner

aralroca commented Jan 17, 2022

@Marc-Hoch the project is open-source, feel free to implement and do a PR

@brunoscopelliti
Copy link

@aralroca

This is what I ended up doing:

import getT_ from "next-translate/getT";

import i18n from "path/to/i18n_config";

export const getT = (locale?: string, namespace?: string | string[]) => {
  global.i18nConfig = i18n;
  
  
  // This part in particular fixes a problem that happens only when
  // I start the next server, and before any other navigation, I send a request to an API route
  // that is supposed to return some localised text.
  if (global?.__NEXT_TRANSLATE__?.config) {
    if (!global.__NEXT_TRANSLATE__.config.loadLocaleFrom) {
      global.__NEXT_TRANSLATE__.config.loadLocaleFrom = i18n.loadLocaleFrom;
    }
  }

  return getT_(locale, namespace);
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

10 participants