Repository navigation
|
Hi guys, |
Replies: 33 comments 101 replies
|
For now a common solution is https://github.com/isaachinman/next-i18next. UPD (2021-10): |
|
@kachkaev thanks but I meant for serverless. I updated the title. |
|
Still struggling to find a clean and simple solution for this. I'm currently using next-i18next, but that requires a HOC with Then there is https://github.com/fwojciec/simple-i18n-example which uses dynamic routing and no custom server, but again requires a HOC that uses Another example is https://github.com/vinissimus/next-translate which allows for static rendering by using a separate folder Now that the nextjs team recommends static pages as a default, it would really be helpful to get their opinion, or even better, an example on how i18n should be implemented properly, as this really is a common requirement. |
|
It might be worth it to use https://github.com/fwojciec/simple-i18n-example as a base, but simply remove the browser language detection in I made a quick example for this: https://codesandbox.io/s/serverless-i18n-s0t6h For demonstration purpouses this now simply defaults to "en" at first, and there are several options to deal with this, for example:
One minor restriction of this approach is, that the language path is not freely configurable but sits on the beginning like: domain.com/language/page1 domain.com/language/page2, as else you would need to replicate this structure for each path. Also, I don't know yet how well this will scale if you have several languages and everything is included per page. |
|
I'm working on an alternative which takes the approach of building a Next.js application per locale, and relies on webpack aliasing features to distribute the localized strings to each app. I made an example which deploys to ZEIT now: https://github.com/Janpot/nymus/tree/master/examples/next.js. The key elements are:
Disclaimer: I don't have it anywhere in production yet. This approach and code should only serve as inspiration. The |
|
@Janpot Interesting, thank you for sharing this. I'm wondering, what was the main blocker or reason that made it more feasible for you to actually build separate applications per locale despite the added complexity? |
|
@janus-reith For me, the main unresolved question/problem here is:
One approach could be to separate these out in one namespace per page and to make sure you only ship that namespace when you transfer messages. This should be relatively straightforward to build right now I guess with Another approach could be to make sure that messages are just normal ES6 modules with named exports and use them like any other code, then have the build system tree-shake away whatever is not used. And if you generate highly optimized components like
The fact that for this approach you'd need to be able alias a module per locale. Which in practice means, a different alias per basepath. I don't think there is any other way to do it currently with Next.js. It's easy to add custom webpack configuration for the whole application, but not if you want to do it more fine-grained. And if run as serverless, it should have no overhead at all whether it's 1 or 10 applications. |
|
I created a new example, which uses static props to generate locale subpaths during build, supports namespaces and only bundles necessary strings for each page: https://codesandbox.io/s/nextjs-i18n-staticprops-92ebn Instead of API routes I just import them in the staticProps step and treeshaking works fine here so only the necessary ones are included. One thing missing is to add rewrites using the pattern described in #9081, so a path like "/de/someSubdir/test" would also work without a defined locale as "/someSubdir/test". Some note for testing Static Props seems to behave different during development than I expected. When I first tried to disable browser scripts to see the initial rendering I got a blank page and thought things didn't work out. But running a production build ( |
|
π So that would basically be the first approach I mentioned in my previous comment. So some of the drawbacks I tried to solve with the other approach I describe are:
All these are fine tradeoffs of course, and your solution is good IMO. I just don't really think this is less complex. |
|
@Janpot Right, let me rephrase that, what I had in mind was complex as in, is it possible to package it into one simple repo for beginners to check out and get started with, without the need for any existing infrastructure in place, just like most of the other nextjs example projects. |
The folder I shared is independent of the rest of that repo. It works on its own, just like an example from the Next.js examples folder would. |
|
I am currently using https://github.com/vinissimus/next-translate . It adds a build step, but beside that everything works fine and on serverless |
|
BTW in the meantime I revised my approach to also optionally be able work with getInitialProps as I have some dynamic and some static pages. Furthermore I now have proper Server Side Language detection in place, without needing getInitalProps or a custom server by using an API route which detects the language header of the request. Next I use the new experimental rewrites, so all routes without a language in their path are redirected to the api endpoint, which detects the language, gets all the remaining path segments in the query and redirects it to the localized route. No unnecessary clientside redirect, no added build step and full static page support. |
|
We've built a Next.js boilerplate with built-in i18n at https://github.com/UnlyEd/next-right-now, it uses i18next and react-i18next, also, it uses Locize provider for fetching translations, but that can be changed. In any way, it's a working implementation used in production that can also be used as a learning resource! |
|
With Next.js 9.3 you can use getStaticProps/getStaticPaths to easily generate localized versions of pages -- no external packages needed. Use dynamic routes to include the language code as part of the url (i.e. something like import React from "react";
import { NextPage, GetStaticProps } from "next";
import Home from "../../components/Home";
import { LanguageProvider } from "../../context/LanguageContext";
interface Props {
locale: Locale;
}
const HomePage: NextPage<Props> = ({ locale }) => {
return (
<LanguageProvider lang={locale}>
<Home />
</LanguageProvider>
);
};
export const getStaticProps: GetStaticProps = async ctx => {
return {
props: {
locale: ctx.params?.lang || "en"
}
};
};
export async function getStaticPaths() {
return {
paths: [{ params: { lang: "en" } }, { params: { lang: "pl" } }],
fallback: false
};
}
export default HomePage;For example implementation of If you need a more sophisticated approach with all the bells and whistles of a full-size localization library something like |
|
What's wrong with just having a [locale] directory and getting the locale from router.query? I'm new with this whole next.js thing and I want to understand what the downsides of this approach are. I see a lot of complex solution that make me wonder if I just have the wrong idea π |
|
Is there any official solution? |
|
Okay so I have been looking into this from a pure SSR perspective (no SSG possible in my app anyways). I wanted to solve this without routes. My solution is not the best and I don't like it. It is not very performant I believe. But it works (for now, until nextjs supports it out of the box or someone finds a better solution) and it doesn't take a lot of code . Needed dependencies:
Note the lack of i18n.js import i18n from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import { initReactI18next } from 'react-i18next'
const options = (lng = undefined) => ({
lng,
resources: {
en: { ...enNamespaces },
de: { ...deNamespaces }
},
// ...
})
let i18next
if (process.browser) {
i18next = i18n.use(LanguageDetector).use(initReactI18next).init(options())
} else {
i18next = (lng) => i18n.use(initReactI18next).init(options(lng)).catch(console.error)
}
export default i18nextNote the following:
_app.js import { universalLanguageDetect } from '@unly/universal-language-detector'
import i18next from './i18n'
const determineLanguage = (req) =>
universalLanguageDetect({
supportedLanguages: SUPPORTED_LANGUAGES,
fallbackLanguage: FALLBACK_LANGUAGE,
acceptLanguageHeader: req.headers['accept-language'],
errorHandler: console.error
})
MyApp.getInitialProps = async (props) => {
const language = determineLanguage(props.ctx.req)
await i18next(language)
return NextApp.getInitialProps(props)
}Note the following:
You can use namespaces, hoc, hook (basically all react-i18next features) with this approach. Again, this can be a band-aid until something better comes along. |
|
I had a tiny i18next binding library at https://github.com/jokester/i18next-react . It works with next.js without needing a custom server (but no effortless SSG). It has a nextjs example at examples/nextjs-serverless. In SSR part, the example used The code is actually quite simple, one may be able to do the same with Anyway hope it can be of some use for other people. |
|
I just wrote a proposal to simplify i18n. Feedbacks are welcome! |
|
I used lingui js in my next application and made a redirect to the default language if no language is First you need to install lingui js and configure it. Install dependencies yarn add --dev @lingui/cli@next @lingui/loader@next @lingui/macro@next @babel/core babel-core@bridge
yarn add @lingui/react@nextAdd lingui commands to package.json {
"scripts": {
"start": "lingui compile && next start",
"build": "lingui compile && next build",
"extract": "lingui extract --clean",
"compile": "lingui compile"
}
}Setup lingui via rc file {
"locales": ["de", "en"],
"sourceLocale": "de",
"format": "po",
"catalogs": [
{
"path": "src/locales/{locale}/messages",
"include": [
"<rootDir>/src",
],
"exclude": [
"*/node_modules/*",
"*/.next/*"
]
}
]
}Setup lingui in _app.tsx _app.tsx import { de, en } from "make-plural/plurals";
import { I18nProvider } from "@lingui/react";
import { setupI18n } from "@lingui/core";
export default function MyApp(
props: { lang: string; catalog: any } & AppProps
) {
const { Component, lang, pageProps, catalog } = props;
const i18n = React.useMemo(() => {
const i = setupI18n({
locale: lang,
localeData: {
de: { plurals: de },
en: { plurals: en },
},
messages: {
[lang]: props.catalog.messages,
},
});
i.activate(lang);
return i;
}, [catalog]);
return (
<I18nProvider i18n={i18n}>
<Component {...pageProps} />
</I18nProvider>
);
}
MyApp.getInitialProps = async (rootCtx) => {
let { lang = "de" } = rootCtx.ctx.query;
if (!lang.match(/^(de|en)$/i)) lang = "de";
// @ts-ignore
const catalog = await import(`@lingui/loader!../locales/${lang}/messages.po`);
const appProps = await App.getInitialProps(rootCtx);
return {
...appProps,
catalog,
lang,
};
};Redirect to default language if no language given: pages/index.tsx import { useEffect } from "react";
import Router from "next/router";
const defaultLanguage = "de"; // TODO: Maybe do browser detection
export default function Index() {
useEffect(() => {
Router.replace(`/${defaultLanguage}`);
}, []);
return null;
}Leverage next.js dynamic routing Add all pages under the .
βββ [lang]
βΒ Β βββ page-a.tsx
βΒ Β βββ page-b.tsx
βΒ Β βββ index.tsx
βββ _app.tsx
βββ _document.tsx
βββ index.tsxAll lingui functions including macros work out of the box. I used lingui v3 here so I can leverage hooks. There are no custom routes or server needed and deployment on vercel works as well. Only the active language is imported when using ssr to reduce the bundle size. Hope that helps someone! |
|
Hi all, just wanted to mention that we have successfully leveraged rewrites in You can find the source code here. |
|
I just added a serverless example with react-i18next. The code is available for review at #14978 The only dependencies needed apart from the default |
|
Did anyone come up with a slim solution that does not require external plugins for this topic? I'd like to use:
My concerns are:
|
|
Check out the new i18n RFC and give us your feedback! π |
|
Next.js Internationalized Routing (i18n) has been released in Next.js 10 one month ago. Check out the Next.js 10 blog post and the official i18n documentation to learn more. |
|
We are transferring our website https://dewesoft.com to Next.js where we have the same need of setting up translated static and dynamic routes. It's important for the SEO to have translated URLs. And of course we would like to keep the existing URL structure! Static routesDynanic routesthis can translate into:
Is this possible to setup? |
|
My preferred way to translate pages (marketing site context) while having different localized slugs is to use a CMS (I recommend Sanity.io) and Next.js with optional catch all routes + This approach will allow you to change content faster, and have everything translated including slugs while delivering a great user experience to your users since all pages will be built upfront of users' requests. |
|
We just released a solution that supports serverless (and localized) URLs out of the box - looking for more community feedback! https://github.com/Avansai/next-multilingual |
Next.js Internationalized Routing (i18n) has been released in Next.js 10 one month ago. Check out the Next.js 10 blog post and the official i18n documentation to learn more.