dynamic i18n resource route prefix path

I already configured the router package (react-router-dom v6) to add a "lang" path prefix to my app, so I can have these routes for example: - /en/posts - /es/posts - /fr/posts - etc... But now I have to configure the resources property in the <Refine> component, and I don't know how I can make these two things work together, as it seems that these paths must be static. I still don't understand fully in which circumstances these paths are used by Refine, as I don't use them in my menu navigation components. I also tried searching here and in github but didn't find anything related.
16 Replies
kapa.ai
kapa.ai13mo ago
Hi @rhengles. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Refine's resources prop allows you to define the resources and their action paths. These paths are used by Refine to generate breadcrumbs, menus, handle redirections, and infer the current resource and action. However, the route management is handled by your preferred framework, in this case, react-router-dom v6. To achieve the desired behavior with language prefixes, you can define your resources with dynamic paths using the language prefix. Here's an example:
const App = () => {
const lang = "en"; // Replace this with the logic to get the current language

return (
<BrowserRouter>
<Refine
dataProvider={dataProvider}
routerProvider={routerProvider}
resources={[
{
name: "posts",
list: `/${lang}/posts`,
create: `/${lang}/posts/create`,
},
{
name: "categories",
list: `/${lang}/categories`,
show: `/${lang}/categories/show/:id`,
},
]}
>
<Routes>
<Route path={`${lang}/posts`}>
<Route index element={<PostList />} />
<Route path="create" element={<PostCreate />} />
</Route>
<Route path={`${lang}/categories`}>
<Route index element={<CategoryList />} />
<Route path="show/:id" element={<CategoryShow />} />
</Route>
</Routes>
</Refine>
</BrowserRouter>
);
};
const App = () => {
const lang = "en"; // Replace this with the logic to get the current language

return (
<BrowserRouter>
<Refine
dataProvider={dataProvider}
routerProvider={routerProvider}
resources={[
{
name: "posts",
list: `/${lang}/posts`,
create: `/${lang}/posts/create`,
},
{
name: "categories",
list: `/${lang}/categories`,
show: `/${lang}/categories/show/:id`,
},
]}
>
<Routes>
<Route path={`${lang}/posts`}>
<Route index element={<PostList />} />
<Route path="create" element={<PostCreate />} />
</Route>
<Route path={`${lang}/categories`}>
<Route index element={<CategoryList />} />
<Route path="show/:id" element={<CategoryShow />} />
</Route>
</Routes>
</Refine>
</BrowserRouter>
);
};
In this example, the lang variable is used to dynamically set the language prefix in the resource paths. You should replace the lang variable with the logic to get the current language in your application.
kapa.ai
kapa.ai13mo ago
Keep in mind that Refine doesn't restrict you to use the router in a specific way, and it's up to you to decide how you want to use it. You can define your routes the way you want, then pass the routerProvider prop to the Refine component and use the resources prop to define the resources and their action paths (source (https://refine.dev/docs/packages/documentation/routers/react-router-v6)). For more information on resources and their usage, you can refer to the Understanding Resources (https://refine.dev/docs/tutorial/understanding-resources/index) section in the Refine documentation. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
Resources | refine
In Unit 2.4, we defined a resource to create our CRUD pages with the Inferencer component but did not explain how it works. We will take care of that in this unit and thoroughly explain the resources prop of the `` component using mock components.
kapa.ai
kapa.ai13mo ago
<@246421183484919808> kapa.ai is still learning and improving, please let us how it did by reacting below
fair-rose
fair-rose13mo ago
Hey @rhengles, The menu item's route comes from your resource list definition. So, If you defined the resource's list path like kapa.ai answer, it should work as expected.
conscious-sapphire
conscious-sapphire13mo ago
@kapa.ai Thank you! This doc page: https://refine.dev/docs/tutorial/understanding-resources/index Says this:
```js
({ name: "blog_posts", edit: "/blog-posts/edit/:id/:version", }) `` > These additional parameters, except for the id parameter, can be passed to the components or hooks using meta properties. The existing parameters in the URL will be used by default when handling the navigation. I don't know where or how these meta` properties are defined, and there are no other mentions on that page and I didn't find any relevant links on that page.
Resources | refine
In Unit 2.4, we defined a resource to create our CRUD pages with the Inferencer component but did not explain how it works. We will take care of that in this unit and thoroughly explain the resources prop of the `` component using mock components.
kapa.ai
kapa.ai13mo ago
Let me check the knowledge base for you. One moment! :books:
kapa.ai
kapa.ai13mo ago
---------------------- You can use the meta property in hooks and components to pass additional parameters to the redirection path after the form is submitted or when generating the redirection path. The meta property is used for various purposes, such as passing additional information to data provider methods, generating GraphQL queries, and providing additional parameters to the redirection path (source (https://refine.dev/docs/api-reference/core/hooks/useForm)). Here's an example of how to use the meta property with the useForm hook:
import { useForm } from "@pankod/refine";

const MyFormComponent = () => {
const { formProps } = useForm({
meta: {
version: "1.0",
},
});

// ...
};
import { useForm } from "@pankod/refine";

const MyFormComponent = () => {
const { formProps } = useForm({
meta: {
version: "1.0",
},
});

// ...
};
In this example, the version property is passed in the meta object. When the form is submitted, the version property will be used to fill in the path parameters for the redirection. For more information on how to use the meta property, you can refer to the General Concepts - meta (https://refine.dev/docs/api-reference/general-concepts/#meta) section in the Refine documentation. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
General Concepts | refine
- refine core is fully independent of UI. So you can use core components and hooks without any UI dependency.
kapa.ai
kapa.ai13mo ago
<@246421183484919808> kapa.ai is still learning and improving, please let us how it did by reacting below
conscious-sapphire
conscious-sapphire13mo ago
@salihozdemir Thank you, but the problem is that the lang is dynamic, and as far as I understand, I need to use useParams() to get the lang, but this hook must be called inside the <Route path=":lang"> AFAICT @kapa.ai Yeah this useForm() hook is unrelated, but this General Concepts link is good
kapa.ai
kapa.ai13mo ago
Let me check the knowledge base for you. One moment! :books:
kapa.ai
kapa.ai13mo ago
---------------------- I apologize for the confusion. The meta property is used for various purposes, such as passing additional information to data provider methods, generating GraphQL queries, and providing additional parameters to the redirection path. You can find more information on how to use the meta property in the General Concepts - meta (https://refine.dev/docs/api-reference/general-concepts/#meta) section in the Refine documentation. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
General Concepts | refine
- refine core is fully independent of UI. So you can use core components and hooks without any UI dependency.
kapa.ai
kapa.ai13mo ago
<@246421183484919808> kapa.ai is still learning and improving, please let us how it did by reacting below
conscious-sapphire
conscious-sapphire13mo ago
@kapa.ai Thank you, but the problem is that the :lang parameter is dynamic, and as far as I understand, I need to use useParams() hook from "react-router-dom" v6 to get the :lang value, but this hook must be called inside the <Route path=":lang"> as far as I understand, which is itself a child of the <Refine> component. Maybe I do need to create my own provider so I can send this lang parameter up the component tree ?
kapa.ai
kapa.ai13mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- You're correct that you need to use the useParams() hook from react-router-dom v6 to get the :lang value. To pass the lang parameter up the component tree, you can create a custom context provider. Here's an example of how you can achieve this: 1. Create a LanguageContext:
import { createContext, useContext } from "react";

const LanguageContext = createContext();

export const useLanguage = () => useContext(LanguageContext);

export const LanguageProvider = ({ children, lang }) => (
<LanguageContext.Provider value={lang}>{children}</LanguageContext.Provider>
);
import { createContext, useContext } from "react";

const LanguageContext = createContext();

export const useLanguage = () => useContext(LanguageContext);

export const LanguageProvider = ({ children, lang }) => (
<LanguageContext.Provider value={lang}>{children}</LanguageContext.Provider>
);
2. Wrap your Refine component with the LanguageProvider:
import { LanguageProvider } from "./LanguageContext";

const App = () => {
// ...

return (
<BrowserRouter>
<Routes>
<Route path=":lang" element={<LanguageWrapper />}>
{/* Your other routes */}
</Route>
</Routes>
</BrowserRouter>
);
};

const LanguageWrapper = () => {
const { lang } = useParams();

return (
<LanguageProvider lang={lang}>
<Refine
dataProvider={dataProvider}
routerProvider={routerProvider}
resources={[
{
name: "posts",
list: `/:lang/posts`,
create: `/:lang/posts/create`,
},
{
name: "categories",
list: `/:lang/categories`,
show: `/:lang/categories/show/:id`,
},
]}
>
{/* Your other components */}
</Refine>
</LanguageProvider>
);
};
import { LanguageProvider } from "./LanguageContext";

const App = () => {
// ...

return (
<BrowserRouter>
<Routes>
<Route path=":lang" element={<LanguageWrapper />}>
{/* Your other routes */}
</Route>
</Routes>
</BrowserRouter>
);
};

const LanguageWrapper = () => {
const { lang } = useParams();

return (
<LanguageProvider lang={lang}>
<Refine
dataProvider={dataProvider}
routerProvider={routerProvider}
resources={[
{
name: "posts",
list: `/:lang/posts`,
create: `/:lang/posts/create`,
},
{
name: "categories",
list: `/:lang/categories`,
show: `/:lang/categories/show/:id`,
},
]}
>
{/* Your other components */}
</Refine>
</LanguageProvider>
);
};
3. Use the useLanguage hook to get the current language in your components:
import { useLanguage } from "./LanguageContext";

const MyComponent = () => {
const lang = useLanguage();

// ...
};
import { useLanguage } from "./LanguageContext";

const MyComponent = () => {
const lang = useLanguage();

// ...
};
This way, you can access the lang parameter from the useLanguage hook in any component that is a child of the LanguageProvider. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai13mo ago
<@246421183484919808> kapa.ai is still learning and improving, please let us how it did by reacting below
fair-rose
fair-rose13mo ago
For similar logic, you can check this example: https://refine.dev/docs/examples/multi-tenancy/strapi-v4/