Gatsby language localization Mdx files with gatsby-plugin-intl - reactjs

I am trying to localize pages with gatsby-plugin-intl. No problem for .js files as I described below but how should I make it for .mdx files?
import React from "react"
import { FormattedMessage, injectIntl, navigate } from "gatsby-plugin-intl"
const MyPage = ( {intl} ) => (
<Layout>
<h2><FormattedMessage id="TITLE"/></h2>
</Layout>
)
export default injectIntl(MyPage)
I am trying to make the similar logic here:
---
name: Settings
route: /documentation/settings
---
import { Playground, Props } from 'docz'
import { useIntl, Link, FormattedMessage } from "gatsby-plugin-intl"
const intl = useIntl()
## Settings
intl.formatMessage({ id: "TITLE"})

every think look right but you have an error on the mdx file
const intl = useIntl()
use the FormattedMessage components instead message
example
<FormattedMessage id="TITLE" />
or your components
<Yourcomponents title={useIntl().formatMessage({ id: "TITLE" })} />
don't use const

Related

Gatsby dynamic routes: 404 instead of component, can't configure

I made a simple site with Gatsby.js and can't configure dynamic routes.
I have index.js page (was automatically created by react), that looks like:
import * as React from 'react'
const IndexPage = () => {
return (
<Layout
pageTitle="Home Page"
>
Some text for my main page
</Layout>
)
}
export const Head = () => <title>Home Page</title>
export default IndexPage
Layout components includes Header that looks like:
import React, { useState, useEffect } from 'react';
import { Link } from 'gatsby';
const Header = () => {
return (
<Wrapper style={{ *some styles* }}>
<Link to="/">Index</Link>
<Link to="/projects">Projects</Link >
</Wrapper>
)
};
export default Header;
I have my Projects page that looks like this:
import * as React from 'react'
import { BrowserRouter, Route, Routes } from 'react-router-dom'
import Layout from '../layout'
const Projects = () => {
return (
<BrowserRouter>
<Layout>
<Wrapper>
<Routes>
<Route path="projects/:projectID/" component={ProjectDetails} />
</Routes>
<MyProjectLink to="/projects/1">
Project 1
</MyProjectLink>
<MyProjectLink to="/projects/2">
Project 2
</MyProjectLink>
</Wrapper>
</Layout>
</BrowserRouter>
)
}
export const Head = () => <title>Our Projects</title>
export default Projects
And I have my ProjectDetails component:
import React from 'react';
import { useParams } from 'react-router';
import Layout from '../../pages/layout';
const ProjectDetails = () => {
const { projectID } = useParams();
return (
<Layout>
<Wrapper>
<h2>Project {projectID}</h2>
</Wrapper>
</Layout>
);
}
export default ProjectDetails;
The problem is that when I navigate to localhost:8000/projects/1 (or "2", or "3", or "100500") I see a 404 page instead of my ProjectDetails component.
I've tried wrapping the index page to BrowserRouter and move the routes with my route there, but that's a dumb idea in my opinion (and it doesnt work).
Did I miss something? Some features of Gatsby (v5) that I don't know about? I'm new to Getsby and to be honest I thought that dynamic routes here work the same way as in React Router.
Gatsby extends its routing from React, however, the way to create routes is slightly different.
As far as I understand your code, you are trying to create a template page for projects: this can be simply done by creating a file inside /templates folder. A simple component like this should work:
const Projects = ({ data }) => {
return (
<Layout>
<Wrapper></Wrapper>
</Layout>
);
};
export const Head = () => <title>Our Projects</title>
export default Projects
This template, as long as you use it when creating pages (using either gatsby-node.js or File System Route API) will be used to hold each specific project data.
Each project data will be queried using GraphQL and held inside props.data but without knowing your source (can be markdown, JSON, CMS, etc) I can't provide a sample query.
Once Gatsby infers its GraphQL nodes from your data source, you can use it to get all projects, a specific project, or any other GraphQL data you need on any page/template (page query) or even using static queries.
The idea should be similar to:
// gatsby-node.js
projects.forEach(({ node }, index) => {
createPage({
path: node.fields.slug,
component: path.resolve(`./src/templates/project.js`),
context: {
title: node.title,
},
})
})
In your gatsby-node.js (or File System Route API) you get all projects, loop through them and createPage for each project. The path (URL) for each project will be the slug field (node.fields.slug) but you can use whatever you want. Gatsby will create dynamic pages based on this field.
Then you decide which component will be used as a template: path.resolve(`./src/templates/project.js`) in this case and finally, you populate the context to add a unique value (title in this case: again, this can be an id, the slug, etc). This value will be used to filter the node in the template.
In your Project template:
export const query = graphql`
query ($title: String) {
mdx(title: {eq: $title}) {
id
title
}
}
`
In this case, I'm using markdown-based sources (that's why the mdx node) and this node is filtered by the title ($title) using the context value. The data will be inside props.data of the template. Again, if you want to fetch all projects you will have available an allMarkdown or allMdx (or allJSON...) depending on the source node)

stories .mdx doesn't load properly in react storybook project

I am working on a storybook project and here is a story of a sample component (sample.stories.mdx):
import Sample from './index';
import { ComponentStory, ComponentMeta } from '#storybook/react';
import { Canvas, Meta, Story, ArgsTable } from '#storybook/addon-docs';
<Meta title='Molecules/Sample' component={Sample} />
export const Template = (props) => <Sample {...props} />;
export const props = {
label: 'Sample',
children: 'Click me'
};
<Canvas>
<Story name='Default' args={props}>
{Template.bind({})}
</Story>
</Canvas>
<ArgsTable story='Default' />
But every time I start the project, it shows the following error:
./components/molecules/Sample/Sample.stories.mdx: Module parse failed: Unexpected token (5:64)
You may need an appropriate loader to handle this file type, currently no loaders are
configured to process this file
Can anyone help? Is this mdx file correct?
Thanks in advance.

Import markdown files dynamically with Vite

I'm looking for a solution that lets me render markdown dynamically, based on the query string. At the moment I render markdown like this, in React + Vite:
import some other stuff...
import { useParams } from 'react-router-dom';
import { ReactComponent } from '../content/blog1.md';
const BlogPost = () => {
const params = useParams();
return (
<Base>
<PageTitle title={`title of blog ${params.blogId}`} />
<ReactComponent />
</Base>
);
};
export default BlogPost;
What I would like is to pass the blogId to the import path like:
import { ReactComponent } from `../content/blog${params.blogId}.md`
Such that the correct file is imported on each /blog/* route. I tried this by lazy loading the markdown like:
const path = `../content/blog${params.blogId}.md`;
const Markdown = React.lazy(() => import(path));
But this raises errors and when I log Markdown I see
{$$typeof: Symbol(react.lazy), _payload: {…}, _init: ƒ}
$$typeof: Symbol(react.lazy)
_init: ƒ lazyInitializer(payload)
_payload: {_status: -1, _result: ƒ}
Which appears to be empty. What would be a solution to accomplish this?
I had also issue when importing assets. In my case .md import failed.
import Article from './assets/article.md';
Failed to parse source for import analysis because the content
contains invalid JS syntax. You may need to install appropriate
plugins to handle the .md file format, or if it's an asset, add
"**/*.md" to assetsInclude in your configuration
So I solved it adding assetsInclude: ['**/*.md'] setting to vite.config.js (for my .md files)
export default defineConfig({
...
plugins: [react()],
assetsInclude: ['**/*.md']
...
})
Eventually this started to work:
import("./assets/article.md").then(res => {
fetch(res.default)
.then(response => response.text())
.then(text => console.log(text))
})
Docs are here:https://vitejs.dev/guide/assets.html
Hope it helps.
Cheers.

import components from create-react-library subfolder

I have been trying to use create-react-library and so far it works, but I can only import components successfully from index.js. If I try to make another file , I recieve an import error.
The file structure is as such
example
\ Node Module
\ public
\ src
| App.js
| index.js
...
src
\ Patterns
| index.js
| button.js
Currently I can only successfully import components from index.js of the main src. Is there a way to successfully import components from folders such as Patterns or another file?
\ App.js ( example )
Importing button gives me an error "Cant import button from neo"
import React from 'react'
import { ExampleComponent,Button} from 'neo'
import {Test} from 'neo/Patterns';
import 'neo/dist/index.css'
const App = () => {
return (
<>
<Test />
<Button text='Click me' />
<ExampleComponent text="Create React Library Example 😄" />
</>
)
}
export default App
Please check if this is what you're trying to achieve.
index.js will be exporting required components like this,
import ExampleComponent from './ExampleComponent/ExampleComponent';
// ExampleComponent is placed inside a folder named ExampleComponent
import Patterns from './Patterns/Patterns';
// Patterns is placed inside a folder named Patterns
export { ExampleComponent, Patterns };
Patterns.js can look like this,
import React from 'react'
const Patterns = () => {
return <div>Patterns Component sample</div>
}
export default Patterns;
ExampleComponent.js can look like this,
import React from 'react'
import styles from './styles.module.css'
const ExampleComponent = ({ text }) => {
return <div className={styles.test}>Example Component: {text}</div>
}
export default ExampleComponent;
In the consumer level (in this case, example folder), in any jsx, like App.js you can refer those exported components like,
import { ExampleComponent, Patterns } from 'neo'
return (
<Patterns />
)

How do I pass my components theme through storybook?

I need to pass a theme that is used in components but I get a syntax error.
My .storybook/config.js:
import { configure, addDecorator } from '#storybook/react'
import React from 'react'
import theme from '../src/theme'
import { ThemeProvider } from 'styled-components'
import '../src/styles/index.css'
addDecorator(story => <ThemeProvider theme={theme}>{story()}</ThemeProvider>)
function loadStories() {
const req = require.context('../src', true, /\.stories.js$/)
req.keys().forEach(filename => req(filename))
}
configure(loadStories, module)
Here's the full error:
Have you tried making the theme provider as a separate file without using the decorators? The below is a Styled-components and typescript implementation.
import React from 'react';
export const Container = ({ title, children }) => {
return (
<StoryWrapper>
<GlobalStyle theme={themes.default} />
<ThemeProvider theme={themes.default}>
<MainWrapper>
<Header>{title}</Header>
{children}
</MainWrapper>
</ThemeProvider>
</StoryWrapper>
);
};
I never used the add decorator feature and this was the config implementation I used, it is set up for tsx though.
import { addParameters, configure, addDecorator } from '#storybook/react';
import { withKnobs } from '#storybook/addon-knobs';
const req = require.context('../src', true, /.stories.tsx$/);
function loadStories(){
req.keys().forEach(req);
}
addDecorator(withKnobs);
configure(loadStories, module);
Seems like Babel is confused that you're using JSX in a JS file.
Try renaming config.js to config.jsx. The file extension should instruct babel to treat it as a JSX file.

Resources