Next-i18next: Example of integrating next-i18next using typescript

Created on 22 Feb 2019  路  15Comments  路  Source: isaachinman/next-i18next

Right now I try to integrate next-i18next into my nextjs project where I am using typescript. I am struggling with making it work properly. Is there someone out there who has a repo where I can check how its done or can someone maybe create a small codesandbox or sth? Would be awesome, I could also make it nice and contribute it to the repo

Most helpful comment

Hi @BjoernRave! Feel free to check out my integration of this library into a TypeScript project: https://gitlab.com/kachkaev/website-frontend

I guess the issue can be close because it's a question and not a bug or a feature request. Although it might be worth adding a TypeScript example into the repo at one point 馃槈

All 15 comments

Hi @BjoernRave! Feel free to check out my integration of this library into a TypeScript project: https://gitlab.com/kachkaev/website-frontend

I guess the issue can be close because it's a question and not a bug or a feature request. Although it might be worth adding a TypeScript example into the repo at one point 馃槈

Thanks alot for the link, will check it out

yea as first I wrote @isaachinman an email and he asked me to open an issue because alot of the other maintainers might have a good example, so thats why I did it

Yes, I asked @BjoernRave to open this so that we could get feedback.

I think before an actual TypeScript example, we need to export proper types from this package - #74.

@lucasfeliciano Do you perhaps have any helpful tips?

@isaachinman I wish I could have some good tips but I'm not familiar with typescript setup. Sorry. :(

One thing that would help would be update i18next and react-i18next, since they are already supporting typescript

One thing that would help would be update i18next and react-i18next, since they are already supporting typescript

i18next should be sitting at the latest major. I have specifically chosen to not update react-i18next for other reasons - see #164.

@BjoernRave Is @kachkaev's link helpful to you? Can we provide anything else?

@isaachinman react-i18next v9.0.4 you're using also already got type definitions built in -> upgrade to latest v9 -> 9.0.10 would be best shape for using types in the react-i18next without hooks version

@jamuhl #200

I've made a PR with typescript types, hope that will help. (https://github.com/isaachinman/next-i18next/pull/201).

I've solved it in my project using typescript paths feature, it looks like that:

// tsconfig.json
...
    "typeRoots": [
        "node_modules/@types",
        "my-types"
    ],
    "baseUrl": ".",
    "paths": {
      "~i18n": ["src/path/to/i18n/file"]
    }
....

Pay attention to typeRoots extension with my-types folder.
In that file I've added a file called: i18n.d.ts

declare module '~i18n' {
  export { Trans } from 'react-i18next';
  export { default as Link } from 'next/link';
  export { default as Router } from 'next/router';

  export function withNamespaces(namespace: string | string[]): any;
  export function appWithTranslation(Component: React.ComponentType): any;
}

Now I get something like that:
image

Why was this issue closed? I've spent days trying to integrate next-i18next with typescript. Why not add a simple typescript example?

Why was this issue closed? I've spent days trying to integrate next-i18next with typescript. Why not add a simple typescript example?

Currently, the lib ships with TS types... so what was your issue?

Why was this issue closed? I've spent days trying to integrate next-i18next with typescript. Why not add a simple typescript example?

Currently, the lib ships with TS types... so what was your issue?

Lib using esmodules. Many developers can't use option esModuleInterop: true And u typings a useless and wrong...
Without esModuleInterop

import i18next from 'i18next'

i18next // undefined

Good!
And we can't use import * as i18next from 'i18next' because type mismatch

This is my approach to this problem:
Generally based on this: https://www.freecodecamp.org/news/how-to-enable-es6-and-beyond-syntax-with-node-and-express-68d3e11fe1ab

package.json:

 "scripts": {
    "dev": "npm-run-all clean transpile server:dev",
    "start": "npm-run-all clean transpile build server:prod",
    "build": "next build",
    "server:prod": "NODE_ENV=production node .build/server",
    "server:dev": "node .build/server",
    "transpile": "babel server.ts i18n.ts --extensions \".ts\" --out-dir .build",
    "clean": "rimraf dist-server",
    ...
  },
  "dependencies": {
    "@babel/cli": "^7.8.4",
    "express": "^4.17.1",
    "npm-run-all": "^4.1.5",
    "rimraf": "^3.0.2",
    ...
  }
  "

i18n.ts:

import NextI18Next from 'next-i18next';

const NextI18NextInstance = new NextI18Next({
  defaultLanguage: 'en',
  defaultNS: 'translations',
  localePath: 'public/locales',
  otherLanguages: ['de'],
});

export const { appWithTranslation, useTranslation } = NextI18NextInstance;

export default NextI18NextInstance;

server.ts

import express from 'express';
import next from 'next';
import nextI18NextMiddleware from 'next-i18next/middleware';
import nextI18next from './i18n';

const port = process.env.PORT || 3000;
const app = next({ dev: process.env.NODE_ENV !== 'production' });
const appHandler = app.getRequestHandler();

(async () => {
  await app.prepare();
  await nextI18next.initPromise;

  await express()
    .use(nextI18NextMiddleware(nextI18next))
    .get('*', (req, res) => appHandler(req, res))
    .listen(port);
})();

The suggestion from @MichalW worked for me, after I started using node -r esm and added index.ts to the transpile step.

package.json

"scripts": {
  "dev": "npm-run-all clean transpile server:dev",
  "start": "npm-run-all clean transpile build server:prod",
  "build": "next build",
  "server:prod": "NODE_ENV=production node -r esm .build/server",
  "server:dev": "node -r esm .build/server",
  "transpile": "babel index.ts server.ts i18n.ts --extensions \".ts\" --out-dir .build",
  "clean": "rimraf dist-server",
  ...
},
"dependencies": {
  "esm": "^3.2.25",
  ...
}

This is my approach to this problem:
Generally based on this: https://www.freecodecamp.org/news/how-to-enable-es6-and-beyond-syntax-with-node-and-express-68d3e11fe1ab

package.json:

 "scripts": {
    "dev": "npm-run-all clean transpile server:dev",
    "start": "npm-run-all clean transpile build server:prod",
    "build": "next build",
    "server:prod": "NODE_ENV=production node .build/server",
    "server:dev": "node .build/server",
    "transpile": "babel server.ts i18n.ts --extensions \".ts\" --out-dir .build",
    "clean": "rimraf dist-server",
    ...
  },
  "dependencies": {
    "@babel/cli": "^7.8.4",
    "express": "^4.17.1",
    "npm-run-all": "^4.1.5",
    "rimraf": "^3.0.2",
    ...
  }
  "

i18n.ts:

import NextI18Next from 'next-i18next';

const NextI18NextInstance = new NextI18Next({
  defaultLanguage: 'en',
  defaultNS: 'translations',
  localePath: 'public/locales',
  otherLanguages: ['de'],
});

export const { appWithTranslation, useTranslation } = NextI18NextInstance;

export default NextI18NextInstance;

server.ts

import express from 'express';
import next from 'next';
import nextI18NextMiddleware from 'next-i18next/middleware';
import nextI18next from './i18n';

const port = process.env.PORT || 3000;
const app = next({ dev: process.env.NODE_ENV !== 'production' });
const appHandler = app.getRequestHandler();

(async () => {
  await app.prepare();
  await nextI18next.initPromise;

  await express()
    .use(nextI18NextMiddleware(nextI18next))
    .get('*', (req, res) => appHandler(req, res))
    .listen(port);
})();

Do you still need next build? if the answer is yes then next build will throw error because it doesn't support next.config.ts

Was this page helpful?
0 / 5 - 0 ratings