wiziple / gatsby-plugin-intl Goto Github PK
View Code? Open in Web Editor NEWGatsby plugin that turns your website into an internationalization-framework out of the box.
Home Page: http://gatsby-starter-default-intl.netlify.com
Gatsby plugin that turns your website into an internationalization-framework out of the box.
Home Page: http://gatsby-starter-default-intl.netlify.com
I followed the instructions here at https://www.gatsbyjs.org/starters/wiziple/gatsby-starter-default-intl/, but what you end up with is actually the plugin code, not explicitly the starter. Should the starter be its own repo so people can truly use it as a starter?
I know that technically you can just grab what's in the examples directory and use that, but it's not as intuitive and I think Gatsby starters are meant to more turn-key.
Got the plugin working on my site for the most part XD
The last issue I'm having is figuring out how to use the plugin for the blog/news section of the site, in which the posts are written in MDX and are multilingual as well.
Any thoughts on how to do this with the plugin?
Thank you @wiziple XD
(anonymous function)
node_modules/gatsby-plugin-intl/link.js:27
24 | onClick = _ref.onClick,
25 | rest = (0, _objectWithoutPropertiesLoose2.default)(_ref, ["to", "language", "children", "onClick"]);
26 | return _react.default.createElement(_intlContext.IntlContextConsumer, null, function (intl) {
27 | var languageLink = language || intl.language;
28 | var link = intl.routed || language ? "/" + languageLink + to : "" + to;
29 |
30 | var handleClick = function handleClick(e) {
Hi Everybody,
In an app I'm working on I have two languages and buttons that switch between them. But what seems to be happening now is that when I switch languages the site redirects to the homepage and scrolls to top, rather than staying on the same page and keeping the same scroll position, which is the desired behavior.
Any ideas why this might be the case?
This is the code for my language switching buttons:
const Language = () => {
return (
<>
<IntlContextConsumer>
{({ languages, language: currentLocale }) =>
languages.map(language => (
<LocaleButton
key={language}
onClick={() => changeLocale(language)}
>
{languageName[language]}
</LocaleButton>
))
}
</IntlContextConsumer>
</>
)
}
The <LocaleButton>
is just a few basic visual styles.
Hi @wiziple!
I am having this issue where links using the Link
component from this plugin do not reset scroll position to the top of the next page, but rather persist the scroll position of the current page, which is breaking the usability of the app. I'm thinking it's this plugins Link
component, because when I use the regular Gatsby Link
component the new page resets scroll position upon the new route. I am also using gatsby-plugin-layout
to achieve a single page application where the navigation and certain elements on the page do not reload, to allow for animated route transitions, and a smoother, better user experience. I do not know if maybe the combination of both plugins might be the issue, but in any case, if you have any thoughts as to why this might be happening, please share.
This is the repo, if you have the time or energy to take a look:
https://github.com/arrowgtp/alma
Anyway, thanks again :-)
This would be more useful if it was adapted to work with source plugins (e.g. gatsby-source-contentful
) rather than relying on outdated, hardcoded translation files. It seems unrealistic that a majority of Gatsby websites would forgo GraphQL querying in order to support translations.
Dear wiziple,
The plugin worked great up to the point where I wrapped all of my pages with withIntl(...). I was able to get the routing going and all, yet, when I use the injectIntl(...) method around my class components and some of my ES6 functional components it breaks.
The following error is given:
[React Intl] Could not find required
intl object. <IntlProvider> needs to exist in the component ancestry.
Any ideas?
Best,
Alexandros
Hi @wiziple, thanks for this nice plugin. I was wondering if you plan to add url slug's translations too, which is a feature I haven't seen yet in the various gatsby i18n plugins.
So, to make it more clear, I mean if you plan to allow this:
en/about
it/chi-siamo (instead of it/about)
same page with two different slugs.
I guess is not easy to manage the link routing, but I think it's possible to build a sort of routes map during the createPages
step and pass it to the pages inside the intl
context. The link component can then use the to
prop as a key that would match this routes map.
Some super pseudo code:
in src/pages/about/index.en.md
url: /about
in src/pages/about/index.it.md
url: /chi-siamo
Then we would have a routes map in page contexts like:
intl = {
...,
routes: {
'about': {
en: '/about',
it: '/chi-siamo'
}
}
}
And the Link component would do
intl => (
Link = ({ to, ... }) => {
const toRoute = intl.routes[to][intl.language]
}
I am curious to see what you think of this approach or if you have any other idea in this regard.
Let me know if all this is a bit unclear!
Doing some research on i18n for Gatsby and this so far has been the best plugin available. Thank you for this plugin!
Any chance that there will be an update to allow HMR for the locale files? For example changing a locale string in fr.json
requires a restart of the gastbsy develop
.
Hi thanks for your help, using the lang switcher the page switch smoothly, but for the Links in my nav when clicking one the page seems to do a reload. Is there a way to change this?
This is an example of a link on my website:
<Link to="/"><img src={logo} width="145" height="39" className="img-fluid"/></Link>
The hook approach is much cleaner and enables user to write their own custom hooks. Please consider adding it
Hi, first of all thanks for this plugin, I like the fact that allows a single page pull data rather than one page for each language.
Overall it works very well, creating pages for each language, but I'm having issues with the automatic redirect, as always goes to the default language, although I can change it later.
I'm looking for an automatic, non changeable option where it only shows the language based on the browser language like:
<script>
let language = window.navigator.language;
if (language == "es") {
window.location.href = "/es";
}
if (language == "en") {
window.location.href = "/en";
}
</script>
As adding the previous snippet to the helmet causes a load loop, is there a way to achieve it?
Thanks!
Repo: https://github.com/lewislbr/lewis-llobera-photography-gatsby
After the latest update, I noticed that on SSR builds yarn build
the value for intl.locale
is incorrect.
CodeSandbox
https://codesandbox.io/s/gatsby-starter-default-fx5gw?fontsize=14
The setup is I have two languages: [en-us, es-es]
. The default language is set to en-us
. Everything works as expected in development mode yarn develop
. However, running yarn build
and logging out the value of intl.locale
from either useIntl
or injectIntl
shows that durring the SSR pass on the build, the value is incorrect.
Expected
intl.locale value is: en-us
intl.locale value is: es-es
Actual
intl.locale value is: en-us
intl.locale value is: en
It's worth noting that the new version of react-intl
sets a defaultLocale
if one is not created. See related PR #80
When I add the plug-in run gatsby develop
is blocked at this stage createPagesStatefully
.Finally, throw Allocation failed
> gatsby develop
success open and validate gatsby-configs - 0.024 s
success load plugins - 0.460 s
success onPreInit - 0.024 s
success initialize cache - 0.516 s
success copy gatsby files - 2.455 s
success onPreBootstrap - 0.067 s
success source and transform nodes - 0.072 s
success building schema - 1.529 s
success createPages - 0.005 s
⠙ createPagesStatefully
<--- Last few GCs --->
[19280:000002901D5C17D0] 343097 ms: Scavenge 1305.9 (1423.7) -> 1305.1 (1424.2) MB, 4.5 / 0.0 ms (average mu = 0.284, curre
nt mu = 0.248) allocation failure
[19280:000002901D5C17D0] 343104 ms: Scavenge 1306.3 (1424.9) -> 1305.9 (1425.4) MB, 3.7 / 0.0 ms (average mu = 0.284, curre
nt mu = 0.248) allocation failure
[19280:000002901D5C17D0] 343117 ms: Scavenge 1306.7 (1425.4) -> 1306.0 (1425.9) MB, 4.6 / 0.0 ms (average mu = 0.284, curre
nt mu = 0.248) allocation failure
<--- JS stacktrace --->
==== JS stack trace =========================================
0: ExitFrame [pc: 000000229A05C5C1]
Security context: 0x03efa411e6e1 <JSObject>
1: map [000003EFA4106E59](this=0x002bd8606059 <JSArray[49144]>,0x002bd8606079 <JSFunction (sfi = 000002BAE60D19D1)>)
2: /* anonymous */(aka /* anonymous */) [000001A856FA8849] [C:\Users\yeming\Desktop\work\madecare-website\node_modules\gat
sby\dist\redux\index.js:~72] [pc=000000229A3594C5](this=0x03c6fd8826f1 <undefined>)
3: _callee$(aka _callee...
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
1: 00007FF74DADECE5
2: 00007FF74DAB8196
3: 00007FF74DAB8BA0
4: 00007FF74DD48D5E
5: 00007FF74DD48C8F
6: 00007FF74E2869D4
7: 00007FF74E27D137
8: 00007FF74E27B6AC
9: 00007FF74E284627
10: 00007FF74E2846A6
11: 00007FF74DE27767
12: 00007FF74DEBF44A
13: 000000229A05C5C1
npm ERR! code ELIFECYCLE
npm ERR! errno 134
npm ERR! [email protected] develop: `gatsby develop`
npm ERR! Exit status 134
npm ERR!
npm ERR! Failed at the [email protected] develop script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\yeming\AppData\Roaming\npm-cache\_logs\2019-07-01T04_59_34_996Z-debug.log
error Command failed with exit code 134.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
gatsby-config.js
module.exports = {
/* Your site config here */
plugins:[
'gatsby-plugin-sass',
'gatsby-plugin-layout',
{
resolve:'gatsby-plugin-intl',
options:{
path:`${__dirname}/src/intl`,
languages:['en','zh'],
defaultLanguage:'zh',
}
}
]
}
package.json
{
"name": "gatsby-starter-hello-world",
"private": true,
"description": "A simplified bare-bones starter for Gatsby",
"version": "0.1.0",
"license": "MIT",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write src/**/*.{js,jsx}",
"start": "npm run develop",
"serve": "gatsby serve",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\""
},
"dependencies": {
"gatsby": "^2.10.4",
"gatsby-plugin-intl": "^0.2.0",
"react": "^16.8.6",
"react-dom": "^16.8.6"
},
"devDependencies": {
"@babel/plugin-proposal-decorators": "^7.4.4",
"babel-preset-gatsby": "^0.2.0",
"gatsby-plugin-layout": "^1.1.0",
"gatsby-plugin-react-css-modules": "^2.1.0",
"gatsby-plugin-sass": "^2.1.0",
"node-sass": "^4.12.0",
"prettier": "^1.18.2",
"sass-loader": "^7.1.0"
},
"repository": {
"type": "git",
"url": "https://github.com/gatsbyjs/gatsby-starter-hello-world"
},
"bugs": {
"url": "https://github.com/gatsbyjs/gatsby/issues"
}
}
gatsby-node.js
const replacePath = path => (path === `/` ? path.toLowerCase() : path.replace(/\/$/, ``).toLowerCase())
// Implement the Gatsby API “onCreatePage”. This is
// called after every page is created.
exports.onCreatePage = ({ page, actions }) => {
const { createPage, deletePage } = actions
const oldPage = Object.assign({}, page);
// Remove trailing slash unless page is /
page.path = replacePath(page.path);
//是否生成新页面
let createNews = false;
if (page.path !== oldPage.path) {
// Replace new page with old page
deletePage(oldPage);
createNews = true;
}
//设置不一样的状态
if (page.path.match(/solution/)) {
page.context.layout = 'solution';
createNews = true;
}
createNews && createPage(page);
}
I can't see this plugin scaling well when a site has many pages, since paths to all localized pages are stored in allSitePage
. This can easily grow to megabytes in size. Am I missing something here?
right now intl is an object passed to context on the creating page loop
return { ...page, path: newPath, context: { ...page.context, intl: { language, languages, messages, routed, originalPath: page.path, redirect, }, }, }
so if I want to access it later on as part of the context is not possible unless we create some sort of intl Type for graphql that allow us to do so, something like this:
const Intl = new GraphQLObjectType({ name: 'Intl', fields: { language: { type: GraphQLString }, languages: { type: GraphQLList }, messages: { type: GraphQLString }, routed: { type: GraphQLString }, originalPath: { type: GraphQLString }, redirect: { type: GraphQLString }, } });
this will be usefull to create pages which can pull the language dynamically from graphql
Hey there! This is a really nice gatsby plugin. Thank you! My team translated our entire site using it to support english and german.
Currently you are using JSON for the language files. I just tested the readability of our translation files as I converted them to YAML. I find that YAML seems very suited for this kind of content files.
Do you have any plan on supporting it as a second option?
We are using typescript in our project. Can't import methods/components from gatsby-plugin-intl because it doesn't have a type declarations. Can you please add a type declarations?
Hey.
I have gatsby-plugin-intl
along with gatsby-sourcre-directus7
, which already comes with a translation interface for dynamic content.
Now the problem is, that when doing createPages
for a single blog post, I would end up having the same URLs.
Example:
1
has a custom slug
in the translations
createPages
will be executed/blog/10-tips-to-manage-your-finances
/blog/10-tipps-wie-sie-ihre-finanzen-verwalten
/en/blog/10-tips-to-manage-your-finances
/de/blog/10-tips-to-manage-your-finances
My gatsby-node.js
file looks as followed:
const path = require('path')
exports.createPages = async ({ actions, graphql }) => {
const { createPage } = actions
// GET Posts and create URL
try {
const result = await graphql(`
{
allDirectusArticle {
edges {
node {
translations {
article {
directusId
}
language
title
slug
}
}
}
}
}
`)
result.data.allDirectusArticle.edges.map(({ node }) => {
node.translations.map(a => {
try {
const url = `blog/${a.slug}`
createPage({
path: url,
component: path.resolve('src/templates/blog/post.js'),
context: {
id: a.article.directusId,
},
})
console.log(`Generated url '${a.title}' to path '/${url}'`)
} catch (error) {
console.error(`Failed to generate url: ${error}`)
}
})
})
} catch (error) {
console.error(`GraphQL query returned error: ${error}`)
}
}
The JSON returned from the above GraphQL request:
{
"data": {
"allDirectusArticle": {
"edges": [
{
"node": {
"translations": [
{
"title": "10 tips to manage your finances",
"slug": "10-tips-to-manage-your-finances",
"language": "en",
"article": {
"directusId": 1
}
},
{
"title": "10 Tipps, wie Sie Ihre Finanzen verwalten können",
"slug": "10-tipps-wie-sie-ihre-finanzen-verwalten-konnen",
"language": "de",
"article": {
"directusId": 1
}
}
]
}
},
{
"node": {
"translations": [
{
"title": "Non modo carum sibi quemque, verum etiam vehementer carum esse?",
"slug": "non-modo-carum-sibi-quemque-verum-etiam-vehementer-carum-esse",
"language": "en",
"article": {
"directusId": 2
}
}
]
}
}
]
}
}
}
I already did try to add ${a.language}
to the url
, but this resulted in having /en/en/
or /de/de/
. Is there something I'm missing out here?
Hello!
Thank you for this great plugin, it helped me a lot!
Is there a way to use HTML in json translation? For example "message" : "hello <strong>awesome</strong> world"
will be output like hello <strong>awesome</strong> world
. And i want it to be like "hello awesome world". Is it possible to achieve?
Dear @wiziple,
Would you consider making the language JSON resource path of the plugin optional?; for instance, I source the data, for each page, from markdown files; each .md file contains a title and metaDescription for each page.
This can be achieved by using injectIntl, graphql magic and component props that access the intl property.
What do you guys think?
Best,
Alexandros
It seems that content is split up based on language. My content team does not work this way at all, and would make it difficult to work with them on content and translations this way:
Rather then this (Please support yaml as well, please):
en:
title: English words
vn:
title: Vietnamese words
they prefer to work like this:
title:
en: English words
vn: Vietnamese words
...where the separation of concerns is based on the content, rather than the language.
It makes sense to me as well, being a react developer, since I don't separate html, css and js, but rather combine them together and make separations based on the idea of a component, rather than arbitrary languages.
I hope that makes sense, and that it might be possible to do so :-)
Any thoughts on this @wiziple? Do you think this is something that could be doable, or would it be really hard to impossible?
When running [email protected]
, [email protected]
, and [email protected]
, I'm seeing this error on both the development server and the static build.
I played around with versions and did not see this with [email protected]
.
I am also aware of the fact that there are still issues with [email protected]
, but this doesn't seem related.
36 | if (!localeData) {
> 37 | throw new Error("Cannot find react-intl/locale-data/" + language);
| ^
38 | }
39 |
40 | _reactIntl.addLocaleData.apply(void 0, localeData);
WebpackError: Cannot find react-intl/locale-data/en
- wrap-page.js:37 addLocaleDataForGatsby
node_modules/gatsby-plugin-intl/wrap-page.js:37:1
- wrap-page.js:106 Object._default [as wrapPageElement]
node_modules/gatsby-plugin-intl/wrap-page.js:106:1
- gatsby-ssr.js:13 Module.replaceRenderer
gatsby-config.js
{
resolve: 'gatsby-plugin-intl',
options: {
// language JSON resource path
path: `${__dirname}/src/i18n/messages`,
// supported language
languages: ['es'],
defaultLanguage: 'en',
// if true, redirect to `/en` when connecting `/`
redirect: false,
},
},
Gatsby Info:
System:
OS: Linux 4.9 Debian GNU/Linux 9 (stretch) 9 (stretch)
CPU: (6) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
Shell: 4.4.12 - /bin/bash
Binaries:
Node: 10.15.3 - /usr/local/bin/node
Yarn: 1.13.0 - /usr/local/bin/yarn
npm: 6.4.1 - /usr/local/bin/npm
Languages:
Python: 2.7.13 - /usr/bin/python
npmPackages:
gatsby: 2.10.4 => 2.10.4
gatsby-cli: ^2.4.15 => 2.7.2
gatsby-image: ^2.0.33 => 2.2.3
gatsby-link: ^2.0.16 => 2.2.0
gatsby-node-helpers: ^0.3.0 => 0.3.0
gatsby-plugin-intl: 0.2.4 => 0.2.4
gatsby-plugin-netlify: ^2.0.12 => 2.1.0
gatsby-plugin-netlify-cms: ^3.0.14 => 3.0.18
gatsby-plugin-purgecss: ^4.0.0 => 4.0.0
gatsby-plugin-react-axe: ^0.2.2 => 0.2.2
gatsby-plugin-react-helmet: ^3.0.9 => 3.1.0
gatsby-plugin-react-svg: ^2.1.1 => 2.1.1
gatsby-plugin-sass: ^2.0.11 => 2.1.0
gatsby-plugin-segment-js: ^3.0.1 => 3.0.1
gatsby-plugin-sharp: ^2.0.28 => 2.2.1
gatsby-plugin-web-font-loader: ^1.0.4 => 1.0.4
gatsby-plugin-webpack-bundle-analyser-v2: ^1.1.0 => 1.1.1
gatsby-source-filesystem: ^2.0.25 => 2.1.1
gatsby-transformer-json: ^2.1.10 => 2.2.0
gatsby-transformer-remark: ^2.3.3 => 2.5.0
npmGlobalPackages:
gatsby: 2.4.2
Hi! First, congrats for your work, I use it and it works really well. I faced an issue to which I made a pull request just to later on realise someone else already did it, which is great!, but it is merged on the versions/0.2.7 branch and I need to use it now, so I installed your package referencing that specific branch.
It would be cool if you can just add a "next" label (or tag) to that branch, so we can just install it as yarn add gatsby-plugin-intl@next
Thanks!
This is not an issue but a question. It's the first time I am using Gatsby and this plugin gatsby-plugin-intl
. My site consists of only static pages and I am using the config to support two locales en
and ja
.
My requirement is to generate separate builds and host them on separate domains. For example ja.example.com
should serve the Japanese site and en.example.com
should serve the English site. Is it possible to tweak the build process of Gatsby to generate independent builds for both?
Like instead of public
directory, I want to generate two separate directories, public-en
and public-ja
and then use those builds for my deployment.
Hello, I have used the plug in properly I believe (similar to the example given) however when I switch language I get redirected to the main page. For example if I am at localhost:8000/en/page-2
and I switch language to fr
I got redirected to localhost:8000/fr/
instead of localhost:8000/fr/page-2
These are the most important files
//gatsby-config.js
module.exports = {
siteMetadata: {
title: `CcLàQ`,
description: `Page officiel de la Chambre de commerce Latinoamèriquenne à Québec`,
author: `@davidneios`,
siteUrl: `https://cclaq.netlify.com/`,
},
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-starter-default`,
short_name: `starter`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/images/cclaq_logo.png`, // This path is relative to the root of the site.
},
},
`gatsby-plugin-offline`,
{
resolve: `gatsby-plugin-intl`,
options: {
path: `${__dirname}/src/intl`,
languages: [`en`, `es`, `fr`],
defaultLanguage: `fr`,
redirect: true,
},
},
`gatsby-plugin-sitemap`,
`gatsby-plugin-robots-txt`,
// this (optional) plugin enables Progressive Web App + Offline functionality
// To learn more, visit: https://gatsby.dev/offline
// `gatsby-plugin-offline`,
],
}
// src/components/languageSwitcher.js
import React from "react"
import { Helmet } from "react-helmet"
import Dropdown from "react-bootstrap/Dropdown"
const languageNames = {
en: "English",
fr: "Francais",
es: "Espanol",
}
const LanguageSwitcher = () => (
<IntlContextConsumer>
{({ languages, language: currentLocale }) => (
<>
<Helmet>
<html lang={currentLocale} />
</Helmet>
<Dropdown>
<Dropdown.Toggle variant="dark" id="dropdown-basic">
langue
</Dropdown.Toggle>
<Dropdown.Menu>
{languages.map(lng => (
<Dropdown.Item
key={lng}
onSelect={() => {
changeLocale(lng)
}}
as="button"
>
{languageNames[lng]}
</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
</>
)}
</IntlContextConsumer>
)
export default injectIntl(LanguageSwitcher)
For the css I am using Bootstrap
You can see the project live here
I hope you can help, thanks!
Hi, thanks for sharing this starter.
I have been trying to add a default language route that goes to url.com/* rather than url.com/en/* etc
I managed to get it half working with some ternary expressions but I haven't been able to do it without breaking the language detection in the redirect.js file and I am a bit stumped. Where would be the best place to start with this?
Default route would be a great feature to implement.
Here's what I'm trying to accomplish:
Rather than storing my translations in src/18n/locales/*.js
, I need to get them from a third party REST API. I'm doing that via sourceNodes
in /gatsby-node.js
as per this example.
My difficulty is in getting the data from GraphQL to react-intl. Specifically, I can't manage to set messages
in the withIntl
component, since Gatsby only executes queries in page and layouts components and I was not able to export a fragment from withIntl
that Gatsby could find.
I suspect that I cannot accomplish what I'm trying to do with this setup and will instead have to move some of the implementation in withIntl
into a layout component that I can provide it with data from GraphQL.
However, before embarking down that road, I thought I'd see if anyone had a better idea.
Thanks very much @wiziple for the awesome starter.
To ensure language changes work when the url does not contain for forward slash, would it be possible to add a check such as this (seems there is a TODO for this):
if (allSitePage.includes(link) || allSitePage.includes(`${link}/`)) {
gatsbyNavigate(link)
} else {
gatsbyNavigate(`/${language}/`)
}
If you are just starting out with this this plugin it can be a bit of a head-scratcher at first why language changes do not work as intended.
I can't seem to figure out how to set up buttons to switch from one language to another. I tried to copy and paste the setup you have going on from the language.js
file in the example, but it doesn't seem to be working at all in any way for me. It might be nice to add an example in the readme file on how to go about doing this for us new to the plugin.
Currently Doing this inside my persistent sidebar:
<Locales>
<IntlContextConsumer>
{({ languages, language: currentLocale }) =>
languages.map(language => (
<a
key={language}
onClick={() => changeLocale(language)}
>
{languageName[language]}
</a>
))
}
</IntlContextConsumer>
</Locales>
Thanks!
Hello,
are there any plans for migration to Gatsby v2.0?
I am trying to get it to work, but I am having some problems regarding context (since it was deprecated in react and it should use ContextProvider now instead)
Hey.
Is it possible to split language files? So instead of having en.json
and de.json
a structure like this:
intl
- de
-- index.json
-- services
--- index.json
--- react.json
--- ...
- en
-- index.json
-- services
--- index.json
--- react.json
--- ...
In the case where the plugin option for redirection
is set to true
, client-only routes for things like authenticated pages do not load, but instead, get redirected to the base route because the routed
value comes back false
for these client routes.
/en-us/account <--- routes properly
/en-us/account/profile <--- redirects back to the account page, preventing the account page client router from acting on the "profile" slug
Note I was only even able to get here after nullifying the 404 matchPaths that the plugin sets here. Match path sorting may be broken in the current release, see gatsbyjs/gatsby#16098
In the example starter, you have an anchor link without an href
attribute in the language switcher.
const Language = () => {
return (
<div>
<IntlContextConsumer>
{({ languages, language: currentLocale }) =>
languages.map(language => (
<a
key={language}
onClick={() => changeLocale(language)}
>
{languageName[language]}
</a>
))
}
</IntlContextConsumer>
</div>
)
}
This is problematic for a number of reasons, including accessibility and SEO, since there is no proper link to the other language version. How would I go about rewriting this to create a proper link (perhaps by using the Link
component)?
Both slash stripper and internationalization plugins need to mash up so as to meet both common SEO and multilingual requirements. The ordering of the plugins in this case is important. If trailing slashes is first the browser URL is more correct but SEO is potentially dinged.
For best results, internationalization should follow stripper. Did not realize that the plugins were order sensitive in gatsby-config.js. As long as the URL has at least two levels, this is fairly close but may still have the trailing slash.
gatsby new my-blog-starter https://github.com/gatsbyjs/gatsby-starter-blog
cd my-blog-starter
npm install --require gatsby-plugin-remove-trailing-slashes
'gatsby-plugin-remove-trailing-slashes',
{
resolve: `gatsby-plugin-intl`,
options: {
// language JSON resource path
path: `${__dirname}/src/intl`,
// supported language
languages: [`en`, `ko`, `de`],
// language file path
defaultLanguage: `en`,
// option to redirect to `/en` when connecting `/`
redirect: true,
},
https://github.com/wiziple/gatsby-plugin-intl/tree/master/examples/gatsby-starter-default-intl/src/intl.
import React from "react"
// TKTKTK
// import { Link, graphql } from "gatsby"
import { graphql } from "gatsby"
import { FormattedMessage, Link, injectIntl } from "gatsby-plugin-intl"
import Bio from "../components/bio"
import Layout from "../components/layout"
import SEO from "../components/seo"
import { rhythm } from "../utils/typography"
class BlogIndex extends React.Component {
render() {
const { data } = this.props
const siteTitle = data.site.siteMetadata.title
const posts = data.allMarkdownRemark.edges
// TKTKTK
const intl = this.props.intl
const intlTitle = intl.formatMessage({ id: "welcome" });
return (
<Layout location={this.props.location} title={siteTitle}>
<SEO title="All posts" />
<h1>{intlTitle}</h1>
<h1><FormattedMessage id="title" /></h1>
<h1><FormattedMessage id="hello" /></h1>
<Bio />
{posts.map(({ node }) => {
const title = node.frontmatter.title || node.fields.slug
return (
<div key={node.fields.slug}>
<h3
style={{
marginBottom: rhythm(1 / 4),
}}
>
<Link style={{ boxShadow: `none` }} to={node.fields.slug}>
{title}
</Link>
</h3>
<small>{node.frontmatter.date}</small>
<p
dangerouslySetInnerHTML={{
__html: node.frontmatter.description || node.excerpt,
}}
/>
</div>
)
})}
</Layout>
)
}
}
// TKTKTK
// export default BlogIndex
export default injectIntl(BlogIndex)
export const pageQuery = graphql`
query {
site {
siteMetadata {
title
}
}
allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
edges {
node {
excerpt
fields {
slug
}
frontmatter {
date(formatString: "MMMM DD, YYYY")
title
description
}
}
}
}
}
`
import React from "react"
// TKTKTK
// import { Link, graphql } from "gatsby"
import { graphql } from "gatsby"
import { FormattedMessage, Link, injectIntl } from "gatsby-plugin-intl"
import Bio from "../components/bio"
import Layout from "../components/layout"
import SEO from "../components/seo"
import { rhythm, scale } from "../utils/typography"
class BlogPostTemplate extends React.Component {
render() {
const post = this.props.data.markdownRemark
const siteTitle = this.props.data.site.siteMetadata.title
const { previous, next } = this.props.pageContext
// TKTKTK
const intl = this.props.intl
const intlTitle = intl.formatMessage({ id: "welcome" });
// const intlTitle = 'fubar'
return (
<Layout location={this.props.location} title={siteTitle}>
<SEO
title={post.frontmatter.title}
description={post.frontmatter.description || post.excerpt}
/>
<h1>{intlTitle}</h1>
<h1><FormattedMessage id="title" /></h1>
<h1><FormattedMessage id="hello" /></h1>
<h1>{post.frontmatter.title}</h1>
<p
style={{
...scale(-1 / 5),
display: `block`,
marginBottom: rhythm(1),
marginTop: rhythm(-1),
}}
>
{post.frontmatter.date}
</p>
<div dangerouslySetInnerHTML={{ __html: post.html }} />
<hr
style={{
marginBottom: rhythm(1),
}}
/>
<Bio />
<ul
style={{
display: `flex`,
flexWrap: `wrap`,
justifyContent: `space-between`,
listStyle: `none`,
padding: 0,
}}
>
<li>
{previous && (
<Link to={previous.fields.slug} rel="prev">
← {previous.frontmatter.title}
</Link>
)}
</li>
<li>
{next && (
<Link to={next.fields.slug} rel="next">
{next.frontmatter.title} →
</Link>
)}
</li>
</ul>
</Layout>
)
}
}
// TKTKTK
// export default BlogPostTemplate
export default injectIntl(BlogPostTemplate)
export const pageQuery = graphql`
query BlogPostBySlug($slug: String!) {
site {
siteMetadata {
title
author
}
}
markdownRemark(fields: { slug: { eq: $slug } }) {
id
excerpt(pruneLength: 160)
html
frontmatter {
title
date(formatString: "MMMM DD, YYYY")
description
}
}
}
`
clear && rm -rf .cache public && gatsby develop
When order in gatsby-config.js:
http://localhost ==>
http://localhost/en/ ==>
Actual: http://localhost/en/en/ with English text
Expected: http://localhost/en with English text
http://localhost/ ==>
http://localhost/en/ ==>
Actual: http://localhost/en/en/ with English text
Expected: http://localhost/en with English text
http://localhost/de ==>
Actual: http://localhost/en/de with English text
Expected: http://localhost/de with German text
http://localhost/de/ ==>
Actual: http://localhost/en/de/ with English text
Expected: http://localhost/de with German text
http://localhost/my-second-post ==>
Actual: http://localhost/en/en/my-second-post with English text
Expected: http://localhost/en/my-second-post English text
http://localhost/my-second-post/ ==>
Actual: http://localhost/en/en/my-second-post/ with English text
Expected: http://localhost/en/my-second-post with English text
http://localhost/de/my-second-post ==>
Actual: http://localhost/en/de/my-second-post with English text
Expected: http://localhost/de/my-second-post with German text
http://localhost/de/my-second-post/ ==>
Actual: http://localhost/en/de/my-second-post/ with English text
Expected: http://localhost/de/my-second-post with German text
When order in gatsby-config.js:
http://localhost ==>
http://localhost/en/ ==>
Actual: http://localhost/en/en/ with English text
Expected: http://localhost/en with English text
http://localhost/ ==>
http://localhost/en/ ==>
Actual: http://localhost/en/en/ with English text
Expected: http://localhost/en with English text
http://localhost/de ==>
Actual: http://localhost/en/de with English text
Expected: http://localhost/de with German text
http://localhost/de/ ==>
Actual: http://localhost/en/de/ with English text
Expected: http://localhost/de with German text
http://localhost/my-second-post ==>
Actual: http://localhost/en/my-second-post with English text
Expected: Successful URL with English text
http://localhost/my-second-post/ ==>
Actual: http://localhost/en/my-second-post/ with English text
Expected: http://localhost/en/my-second-post with English text
http://localhost/de/my-second-post ==>
Actual: http://localhost/de/my-second-post with German text
Expected: Successful URL with German text
http://localhost/de/my-second-post/ ==>
Actual: http://localhost/de/my-second-post/ with German text
Expected: http://localhost/de/my-second-post with German text
Only gatsby-plugin-intl enabled in gatsby-config.js:
http://localhost ==>
Actual: http://localhost/en/ with English text
Expected: Successful URL with English text
http://localhost/ ==>
Actual: http://localhost/en/ with English text
Expected: Successful URL with English text
http://localhost/de ==>
Actual: http://localhost/de with German text
Expected: Successful URL with German text
http://localhost/de/ ==>
Actual: http://localhost/de/ with German text
Expected: Successful URL with German text
http://localhost/my-second-post ==>
Actual: http://localhost/en/my-second-post with English text
Expected: Successful URL with English text
http://localhost/my-second-post/ ==>
Actual: http://localhost/en/my-second-post/ with English text
Expected: Successful URL with English text
http://localhost/de/my-second-post ==>
Actual: http://localhost/de/my-second-post with German text
Expected: Successful URL with German text
http://localhost/de/my-second-post/ ==>
Actual: http://localhost/de/my-second-post/ with German text
Expected: Successful URL with German text
Maybe these two plugins would benefit from being combined together. The addition of the stripping slashes feature into international would seem pretty straight forward and might result in better performance.
Tomorrow, I plan to run the tests with just international. I will update with my findings. Updated.
System:
OS: macOS 10.14.5
CPU: (8) x64 Intel(R) Core(TM) i7-7920HQ CPU @ 3.10GHz
Shell: 5.0.2 - /usr/local/bin/bash
Binaries:
Node: 10.15.2 - /usr/local/bin/node
Yarn: 1.15.2 - ~/.yarn/bin/yarn
npm: 6.9.0 - /usr/local/bin/npm
Languages:
Python: 2.7.10 - /usr/bin/python
Browsers:
Chrome: 74.0.3729.169
Safari: 12.1.1
npmPackages:
gatsby: ^2.7.5 => 2.7.5
gatsby-image: ^2.1.2 => 2.1.2
gatsby-plugin-feed: ^2.2.1 => 2.2.1
gatsby-plugin-google-analytics: ^2.0.20 => 2.0.20
gatsby-plugin-intl: ^0.1.7 => 0.1.7
gatsby-plugin-manifest: ^2.1.1 => 2.1.1
gatsby-plugin-offline: ^2.1.1 => 2.1.1
gatsby-plugin-react-helmet: ^3.0.12 => 3.0.12
gatsby-plugin-remove-trailing-slashes: ^2.0.11 => 2.0.11
gatsby-plugin-sharp: ^2.1.2 => 2.1.2
gatsby-plugin-typography: ^2.2.13 => 2.2.13
gatsby-remark-copy-linked-files: ^2.0.13 => 2.0.13
gatsby-remark-images: ^3.0.14 => 3.0.14
gatsby-remark-prismjs: ^3.2.9 => 3.2.9
gatsby-remark-responsive-iframe: ^2.1.1 => 2.1.1
gatsby-remark-smartypants: ^2.0.9 => 2.0.9
gatsby-source-filesystem: ^2.0.37 => 2.0.37
gatsby-transformer-remark: ^2.3.12 => 2.3.12
gatsby-transformer-sharp: ^2.1.20 => 2.1.20
npmGlobalPackages:
gatsby-cli: 2.6.3
AdvThanksance!!!
As far as I can tell I have more or less the same setup as the gatsby-starter-default-intl
, but I get a TypeError: intl is undefined
on the 404 page (https://postimg.cc/Zv03RQBc).
Here is a link to my repo: https://github.com/stefanfrede/50plus-treff/blob/i18n/src/pages/404.js.
I can't figure out if I forgot something or if I found a bug in the plugin, so every help is much appreciated.
The other pages are working.
Hey.
Since version0.2.0
, I get the 404 page instead of the e.g. index pages.
en.json: {'home.title': 'xxxx {br} xxxx',}
component:
import React from 'react';
import { injectIntl } from 'gatsby-plugin-intl';
const Home = ({ intl }) => {
return (
<div>{intl.formatMessage({ id: 'home_title' }, { br: <br /> })}</div>
);
};
export default injectIntl(Home);
Expected behavior:
xxxx
xxxx
Current behavior:
xxxx [object Object] xxxx
[React Intl] Error formatting message: "home.title" for locale: "en"
Error: The intl string context variable 'br' was not provided to the string 'xxxx {br} xxxx'
I have a use case where I need to revamp a landing page that was on wordpress to Gatsby which is well reference in Google and all but with a wrong locale name (site.com/us-en/some-route-url) instead of (site.com/en-us/some-route-url).
The issue is that in my config file if I do
{
resolve: `gatsby-plugin-intl`,
options: {
path: `${__dirname}/src/intl`,
languages: [`us-en`, `ma-ar`],
defaultLanguage: `us-en`,
redirect: true,
},
},
it gives error of can't find locale "us-en" in react-inlt/locale-data. and when I just reverse it to
languages: [`en-us`, `ar-ma`],
it works, but I need the first use case of us-en to work to maintain the SEO of the landing page, because changing this will ruin my SEO which I worked for, for years.
How can I achieve this with the plugin please ?
Will it be possible to update this plugin to work with [email protected]
? There are some useful new features!
https://github.com/formatjs/react-intl/blob/master/docs/Upgrade-Guide.md
I'm pretty sure this was a side effect of the react-intl
update. If you don't set a defaultLocale
on the provider component, it defaults to en
. This should probably default to what our config value for defaultLanguage
otherwise it causes unexpected behavior if performing evaluations on intl.locale
.
https://github.com/formatjs/react-intl/blob/master/src/utils.ts#L93
Expected: intl.defaultLocale
matches the value set in our plugin config.
Actual: intl.defaultLocale
defaults to en
always.
Hi!
I'm trying to use Link
component from gatsby-plugin-intl
and got an error:
<LocationProvider>
componentI cloned repo with example and everything works fine, but not in my project :(
Could it be a conflict with other libraries?
Thank you!
Somehow the plugin is not able to find the messages defined.
I have the following setup.
gatsby-config.js
module.exports = {
siteMetadata: {
title: `XXX`,
description: `XXX`,
author: `XXX`,
},
plugins: [
`gatsby-plugin-flow`,
`gatsby-plugin-react-helmet`,
`gatsby-plugin-styled-components`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/assets`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-starter-default`,
short_name: `starter`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
},
},
{
resolve: `gatsby-plugin-module-resolver`,
options: {
root: `./src`,
aliases: {
components: `./components`,
constants: `./constants`,
i18n: `./i18n`,
pages: `./pages`,
utils: `./utils`,
assets: `./assets`,
static: {
root: `./public`,
alias: `./static`,
},
},
},
},
{
resolve: `gatsby-plugin-intl`,
options: {
path: `${__dirname}/src/i18n`,
languages: [`en`, `de`],
defaultLanguage: `en`,
redirect: true,
},
},
],
}
i18n/en.json
{
"navigation": {
"sprints": "Sprints & Processes",
"company": "Company",
"learning": "Blog"
}
}
i18n/de.json
{
"navigation": {
"sprints": "Sprints & Prozesse",
"company": "Unternehmen",
"learning": "Blog"
}
}
When using the FormattedMessage
component like so <FormattedMessage id={
navigation.${item.title}} />
I get the following error in the console back:
10:41:58.156
[React Intl] Missing message: "navigation.sprints" for locale: "en"
10:41:58.157
[React Intl] Cannot format message: "navigation.sprints", using message id as fallback.
10:41:58.160
[React Intl] Missing message: "navigation.company" for locale: "en"
10:41:58.160
[React Intl] Cannot format message: "navigation.company", using message id as fallback.
10:41:58.164
[React Intl] Missing message: "navigation.learning" for locale: "en"
10:41:58.164
[React Intl] Cannot format message: "navigation.learning", using message id as fallback.
injectIntl
is being used on the component that renders the Navigation. Full code example of components/Navigation
:
// @flow
import React from 'react'
import { Container } from 'styled-bootstrap-grid'
import { injectIntl, FormattedMessage } from 'gatsby-plugin-intl'
import ITEMS from 'constants/menu'
import {
Wrapper,
Item,
Link,
SubMenu,
SubMenuFooter,
SubMenuLink,
Product,
ProductLogo,
ProductContent,
MobileProduct,
MobileProductLogo,
MobileProductContent,
Toggle,
MobileWrapper,
MobileContent,
MobileItem,
MobileFooter,
MobileFooterLink,
} from './styles'
const Navigation = ({ intl }) => (
<Wrapper>
{ITEMS.map((item, index) => (
<Item key={index.toString()}>
<Link to={item.link} activeClassName="active">
<FormattedMessage id={`navigation.${item.title}`} />
</Link>
</Item>
))}
</Wrapper>
)
export default injectIntl(Navigation)
Any ideas on what's causing this issue?
When I have a defaultLanguage
set, I'd like an option to have that redirects all pages for that language to the root, instead of /<lang>
. This applies mostly to <Link>
and changeLocale()
E.g. I have en
and is
and is
is the default language. If I call changeLocale('is')
on /en/about
I'd like to go to /about
not /is/about
.
I am using gatsby-plugin-layout
in my web app to avoid unnecessary re-loads and to give the user a better experience animated route transitions, etc. I am noticing that after installing gatsby-plugin-intl
all my routes are now fully re-loading, breaking the experience.
Does this plugin not work with gatsby-plugin-layout
?
Do I need to do anything special to make it work?
Hi, thank you for working on this, I have been using this to i18n a Gatbsy site. Everything works in the development server, but when I build, the page is blank.
Viewing the source shows some content but I don't understand why this is happening.
This happens building the gatsby-starter-default-intl
in your example folder with no changes.
I seem to have to gatsby clean && gatsby develop
in order to get changes to my translation files (`*.json) to be picked up - is that expected, or am I doing it wrong?
Narrowing it down slightly, instead of gatsby clean
I can do rm .cache/redux.state
followed by a restart of gatsby develop
Dear @wiziple,
As per Google, here, there are 3 ways to indicate the localization of the content of a page; for Gatsby, the Html Tag is used. However, when navigating to a localized page the html lang tag stays the same.
I can see that, the showcase page, krashna.nl has achieved this successfully; can this functionality be implemented as a showcase in the gatsby-starter-default-intl example?
Best,
Alexandros
How does one use this plugin while having all contents stored in a contentful CMS? How will it be possible to query the preferred locale based on the user's language selection?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.