gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.28k stars 10.31k forks source link

Add an official guide for internationalizing websites with Gatsby #3853

Closed kripod closed 5 years ago

kripod commented 6 years ago

Seeing the reactions to my comment on an other issue, I decided to open this issue.

I think that i18n is much harder than it should be. I could not find any official documentation or plugin for internationalizing content on Gatsby-made websites. I came across jsLingui, which seems to solve most of the issues, but there are still no guides about maintaining e.g. markdown files/pages in different languages.

jeffwillette commented 6 years ago

@pbrandone you are right, it does statically render that way. I remember testing it in the past and failing, but that was before I had a decent grasp of how gatsby works, I might have had my react-intl setup in gatsby browser which seems like it might not render without javascript. My solution now looks just like yours

szimek commented 6 years ago

@KyleAMathews I'm trying to update our page to Gatsby to v2 and have an issue with our react-intl setup and graphql queries.

I previously explained how I use language-specific layouts to load language data in Gatsby v1 - https://github.com/szimek/gatsby-react-intl-example. In Gatsby v2 I had an idea to replace these layouts with language-specific page components. I'd have a language-agnostic src/templates/Post.js component and then language-specific components like src/templates/Post.en.js, src/templates/Post.de.js that would only load language data and render the language-agnostic component.

In your previous comment (https://github.com/gatsbyjs/gatsby/issues/3853#issuecomment-367115380) you showed an example where each page component has language specific query.

The problem with it is that when calling createPage, I'm passing names of these language-specific components (e.g. src/templates/Post.en.js) as component option, but the graphql query is in the language-agnostic component, because it's exactly the same for all languages (it depends on locale, but I'm passing it in context). I'd like to avoid repeating exactly the same query in all these language-specific components.

Any ideas how to solve it? Can I extract this query to a variable? When I tried it, Gatsby complains about query and fragment names being the same...

wiziple commented 6 years ago

I recently added a default Gatsby starter with features of multi-language url routes and browser language detection. (demo)

gatsby-starter-default-intl

Features:

szimek commented 6 years ago

@wiziple Thanks! It looks really interesting. I had no idea that you can do something like this: https://github.com/wiziple/gatsby-starter-default-intl/blob/master/src/i18n/withIntl.js#L38 ;) Hopefully, it still works in Webpack 4...

Is it possible to load locale data in the same way here https://github.com/wiziple/gatsby-starter-default-intl/blob/master/src/i18n/withIntl.js#L6? We support 6 (soon 7 languages), so it would be great if I could load only the one that I'm building the page for. it's no big deal if it's not possible - fortunately, these locale data files are relatively small.

I'll also have to look into how you generate these pages, because in my case not every page is translated into all languages (there's no single "source" language), so the solution with onCreatePage will probably not work in my case.

Hopefully, this will solve my problem with the same graphql query in every language-specific page component.

wiziple commented 6 years ago

@szimek The website I manage has 14 languages and each language file is 12-15 KB. I'm pretty sure we need to provide the right language for each language router at the build time in order to generate SEO data. So I'm not sure how I can handle this without providing all languages.

I understand that sometimes it is hard to provide every page translated into all languages. You might be able to solve this by providing some exception on onCreatePage in gatsby-node.js. In my case, I just simply solved by not offering translated language regardless of the language router. 😆 You can find showcase website on production from the starter README.md and check its performance.

szimek commented 6 years ago

@wiziple Thank you so much!

I used your withIntl component with dynamic require trick for translations (I have no idea if there are any disadvantages to using it) and it seems to work great. It solved the problem I was struggling with - how to handle the same graphql query in multiple language-specific page components - by having a single page component for all languages.

brotzky commented 6 years ago

@wiziple thanks for the repo share. Got me on the right path 😄 🎉

rfox12 commented 6 years ago

lingui seems to be a better alternative. I don't think @dcroitoru got proper recognition for a great example. Just needs a little love to push it to Gatsby 2.0

sedubois commented 6 years ago

I agree that Lingui is indeed really nice, although still needs a complete starter, with the latest version of Gatsby but also Lingui. The mentioned starter is unofficial and was missing some features last time I checked (e.g using a loader to run lingui compile on the fly). Lingui's author @tricoder42 said that he would provide documentation when Lingui v3 is out (which appears to be soon).

NB: I noticed that my need for an i18n library decreased after integrating a CMS (DatoCMS), but I still need Lingui for some strings that don't find their place in the CMS and also for pluralization and possibly other things later so I definitely want to keep it in my codebase.

Anyhow in my case the existence of gatsby-plugin-i18n made things quite confusing as it is non-maintained, has a confusing name, and draws the attention away from these other really nice solutions like js-lingui and CMSes which I then took a while to figure out and assemble together.

smakosh commented 6 years ago

Just made this starter to help you folks: https://github.com/smakosh/gatsby-starter-i18n Article: https://dev.to/smakosh/implement-i18n-to-a-gatsby-site-5ala

bmihelac commented 6 years ago

I have made two internationalising examples with react-intl integration

First example is focused on bundling only current translations in js chunks (something I couldn't find in other plugins that I checked).

Second example focus on using dynamic queries to provide only requested translations for given page/language combination.

Hopefully, this examples would be useful to someone.

pdrbrnd commented 6 years ago

Also made a quick medium post (and forgot to post it here) with pretty much what's in https://github.com/gatsbyjs/gatsby/issues/3853#issuecomment-395432693 (albeit a bit more in depth).

https://blog.significa.pt/i18n-with-gatsby-528607b4da81 for anyone who's interested

gatsbot[bot] commented 5 years ago

Old issues will be closed after 30 days of inactivity. This issue has been quiet for 20 days and is being marked as stale. Reply here or add the label "not stale" to keep this issue open!

wiziple commented 5 years ago

Hey guys, it's been almost a year 😅

I recently released new gatsby plugin gatsby-plugin-intl that easily makes your gatsby website as an internationalization framework out of the box.

DEMO: https://gatsby-starter-default-intl.netlify.com

Also, I want to mention that many of i18n examples / starters are actually rendered on client side. The best way to check if the app is rendered as SSR is viewing the source code and checking whether the localized texts exist. Please double check this matter when you internationalize your gatsby website for SEO.

cant89 commented 5 years ago

Hey guys, it's been almost a year 😅

I recently released new gatsby plugin gatsby-plugin-intl that easily makes your gatsby website as an internationalization framework out of the box.

DEMO: https://gatsby-starter-default-intl.netlify.com

  • Out of box internationalization-framework powered by react-intl
  • Support automatic redirection based on the user's preferred language in browser
  • Support multi-language url routes in a single page component. This means you don't have to create separate pages such as pages/en/index.js or pages/ko/index.js.
  • As some of you guys suggested above, now it bundles only current language during build time.

Also, I want to mention that many of i18n examples / starters are actually rendered on client side. The best way to check if the app is rendered as SSR is viewing the source code and checking whether the localized texts exist. Please double check this matter when you internationalize your gatsby website for SEO.

Hey @wiziple thanks so much for it, I was going crazy finding a solution for localize Gatsby. Maybe I didn't get the point but, do you have ALL the strings of a language in just one file? Would it be possible to split the JSON of each language in more files, maybe using the same structure of components?

wiziple commented 5 years ago

@cant89 I see your point, but It's currently not possible without changing the plugin code. Or you can make a script that parses src directory and grab all component language files. Merge into one JSON then hook into gatsby develop or gatsby build. Once you get all JSON files and merge as a nested object, you can also convert it as a flatten object. https://github.com/yahoo/react-intl/wiki/Upgrade-Guide#flatten-messages-object

wardpeet commented 5 years ago

We have a good example setup for i18n. https://github.com/gatsbyjs/gatsby/tree/master/examples/using-i18n. We don't really have an opinion on i18n frameworks. Just pick one to your liking.

cant89 commented 5 years ago

We have a good example setup for i18n. https://github.com/gatsbyjs/gatsby/tree/master/examples/using-i18n. We don't really have an opinion on i18n frameworks. Just pick one to your liking.

Cool, thanks, Im gonna try! Anyway the link on the readme is broken, probably you mean https://using-i18n.netlify.com/ ?

monsieurnebo commented 5 years ago

@wardpeet Does your example generate static translated strings (on build time) ? Or does it generate the text during runtime?

stefanoTron commented 5 years ago

@monsieurnebo looks like build time

wardpeet commented 5 years ago

@cant89 we're still updating the dns so it's up soon for now using-i18n.netlify.com/ is the correct link.

@monsieurnebo it's at build time. It creates a copy of your website for each language so everything can be statically build. This means your website stays fast as everything is just a .html.

jasonnoahchoi commented 5 years ago

not sure where else to ask this but a bit relevant. do any of these plugins support gatsby's pathPrefix?

i.e. 
// gatsby-config.js

modules.exports = {
    pathPrefix: 'bar'
}

https://foo.com => https://foo.com/bar

but now my language locales will now be https://foo.com/bar/de-DE/
when I think I would prefer it be https://foo.com/de-DE/bar if that makes sense.
CanRau commented 5 years ago

Hmm interesting, I think the former makes usually more sense though as the pathPrefix is kind of making your domain to be domain.com/prefix so changing the root when you have installed Gatsby in a subdirectory, if you don't install it to a subdirectory you don't need it, if you use a subdirectory changing the prefix to be after the language would break it..

Now the question comes up, why are you using the pathPrefix in the first place?

Ref: pathPrefix docs

slorber commented 5 years ago

Hi,

Most of the discussions here are about how to i18n a gatsby site. But there's a difference between having a POC working, and having an optimized production ready system.

If you are interested to read more about code splitting and i18n files, and why most solutions in this thread are not optimized, you'll find this issue useful