Open mirankorkmaz opened 2 years ago
@sagargulati I might be solving this issue tomorrow, I will let you know if I come up with a solution.
I'm also trying; let me know if you find a fix!
Not sure if this will help you guys and there is probably a better solution, but I had the same problem with react-pdf
and I solved it by wrapping react-pdf
Document
with react-i18next
I18nextProvider
.
const blob = await pdf(
<I18nextProvider i18n={i18next}>
<CVDocument values={formData} />
</I18nextProvider>
).toBlob();
And I have standard call to i18next.init
in index.js
of the react app project.
i18next.init({
interpolation: { escapeValue: false }, // React already does escaping
lng: 'en', // language to use
resources: {
en: {
main: main_en, // 'main' is our custom namespace
form: form_en,
},
sr: {
main: main_sr,
form: form_sr,
},
},
});
It doesn't seem to work inside the API /api/generate/pdf
endpoints
I managed to get it work with react-intl
I wouldn't recommend switching to react specific package while using a framework like next.js
react-intl is works with Next.js
too. I'm using it for a custom SSR setup and works without issues.
Can you share an example?
any update on this issue?
I'm working on a nextjs project and use next-i18next for i18n feature. About this issue, I try to work around by import the i18n json in pdf-related component directly: import de from '@public/locales/de/crf.json'; import en from '@public/locales/en/crf.json';
and pass locale/language in the component to get the corresponding translation by language:
locale === 'en' && en[your-translation-key
] || ''
locale === 'de' && de[your-translation-key
] || ''
still, hope there is a way to make translation work in pdf document.
any updates??
Haven't really touched my test-repository in two years but I quickly tried adding a document now with useTranslation from react-i18next
and it worked
https://github.com/mirankorkmaz/useTranslation-pdf-renderer
Again, have not been maintaining the repo so I don't know if the dependencies are up to date etc
When pdf is located on page its working, but when download it is not
const [instance] = usePDF({ document: <Pdf Lib={Lib} /> });
I see, made some changes now to my repository using usePDF if you want to clone it. Seems to be working. Can you provide more information about your setup if it doesn't work for you? @andreymaklakov
i18n config
import { initReactI18next } from 'react-i18next';
import i18n from 'i18next';
import Backend from 'i18next-http-backend';
import adminCommonRu from '../locales/ru/adminCommon.json';
import adminEmployeesRu from '../locales/ru/adminEmployees.json';
import adminProjectsRu from '../locales/ru/adminProjects.json';
import adminRolesRu from '../locales/ru/adminRoles.json';
import agentTicketRu from '../locales/ru/agentTicket.json';
import chatRu from '../locales/ru/chat.json';
import commonRu from '../locales/ru/common.json';
import customerCommonRu from '../locales/ru/customerCommon.json';
import customerTicketRu from '../locales/ru/customerTicket.json';
import pdfRu from '../locales/ru/pdf.json';
import profileRu from '../locales/ru/profile.json';
i18n.use(Backend)
.use(initReactI18next)
.init({
resources: {
ru: {
common: commonRu,
agentTicket: agentTicketRu,
profile: profileRu,
chat: chatRu,
customerCommon: customerCommonRu,
customerTicket: customerTicketRu,
adminCommon: adminCommonRu,
adminProjects: adminProjectsRu,
adminRoles: adminRolesRu,
adminEmployees: adminEmployeesRu,
pdf: pdfRu
}
},
fallbackLng: 'ru',
lng: 'ru',
debug: __IS_DEV__,
interpolation: {
escapeValue: false
},
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json'
}
});
export { i18n };
download button(lib loads on click)
import { FC, useCallback, useRef, useState } from 'react';
import { PdfLibType } from '@/entities/AgentTickets';
import { IconButton } from '@/shared/ui/IconButton';
import { OpenPdf } from './OpenPdf';
const getAsyncPdfLib = () => {
return Promise.resolve(import('@react-pdf/renderer'));
};
export const DownloadPdf: FC = () => {
const pdfLibRef = useRef<PdfLibType>();
const [isOpen, setIsOpen] = useState(false);
const handleOpen = () => {
getAsyncPdfLib().then((pdfLib) => {
pdfLibRef.current = pdfLib;
setIsOpen(true);
});
};
const handleClose = useCallback(() => {
setIsOpen(false);
}, []);
return (
<>
<IconButton
name="fileDownload"
width={25}
height={25}
onClick={handleOpen}
/>
{isOpen && pdfLibRef.current && (
<OpenPdf Lib={pdfLibRef.current} onClose={handleClose} />
)}
</>
);
};
pdf instance
import { FC, useEffect } from 'react';
import { Spinner } from '4game-ui';
import { Pdf, PdfLibType } from '@/entities/AgentTickets';
import styles from './DownloadPdf.module.css';
interface IProps {
Lib: PdfLibType;
onClose: () => void;
}
export const OpenPdf: FC<IProps> = (props) => {
const { Lib, onClose } = props;
const [instance] = Lib.usePDF({
document: <Pdf Lib={Lib} />
});
useEffect(() => {
if (instance.url) {
window.open(instance.url);
onClose();
}
}, [instance.url, onClose]);
if (instance.loading) {
return <Spinner size="large" className={styles.spinner} />;
}
return null;
};
import { FC } from 'react';
import { useTranslation } from 'react-i18next';
import { PdfLibType } from '../../model/types/pdf';
interface IProps {
Lib: PdfLibType;
}
export const Pdf: FC<IProps> = (props) => {
const { Lib } = props;
const { t } = useTranslation('pdf');
const styles = Lib.StyleSheet.create({
page: {
padding: 20
},
counter: {
marginBottom: 30,
paddingBottom: 10,
borderBottom: '1px solid black'
},
section: {}
});
return (
<Lib.Document>
<Lib.Page wrap style={styles.page}>
<Lib.Text
style={styles.counter}
render={({ pageNumber, totalPages }) =>
`${pageNumber} ${t('page')} / ${t('pages', { count: totalPages })}`
}
fixed
/>
<Lib.View style={styles.section}>
<Lib.Text>Section #1</Lib.Text>
</Lib.View>
<Lib.View style={styles.section}>
<Lib.Text>Section #2</Lib.Text>
</Lib.View>
</Lib.Page>
</Lib.Document>
);
};
@mirankorkmaz
without async lib load is the same
I have 1 !B@0=8F0 / 1 !B@0=8F0
in pdf
What does your public folder look like? Mine looks like this:
Also, I tried incorporating your solution and it still works. I'm suspecting it has something to do with the way you've set up your i18n config, or maybe the way you are trying to render
<Lib.Text
style={styles.counter}
render={({ pageNumber, totalPages }) =>
`${pageNumber} ${t('page')} / ${t('pages', { count: totalPages })}`
}
fixed
/>
Also what does your ruPdf look like? @andreymaklakov It shouldn't matter whether the lib import is a promise.
I use vite and do not have public folder, but its not an issue, I tried to put locales to common folder in your project and it still works. I setted up config in your project in the same way as mine, still works.
pdfRu is working everywhere except pdf
{
"page": "Страница",
"pages_one": "{{count}} Страница",
"pages_few": "{{count}} Страницы",
"pages_many": "{{count}} Страниц"
}
Translation before download is working and is correct, but when download or open pdf in new window its!B@0=8F0
I see the issue and you're right, it works everywhere except inside the PDF. It seems to be an issue rendering the Russian alphabet.
Add Font to your document. Font is imported from import { Font } from "@react-pdf/renderer";
export const Pdf: FC<IProps> = (props) => {
const { Lib } = props;
const { t } = useTranslation('pdf');
Font.register({
family: 'Roboto',
src: 'https://cdnjs.cloudflare.com/ajax/libs/ink/3.1.10/fonts/Roboto/roboto-light-webfont.ttf',
})
const styles = Lib.StyleSheet.create({
page: {
padding: 20,
fontFamily: 'Roboto',
},
counter: {
marginBottom: 30,
paddingBottom: 10,
borderBottom: '1px solid black'
},
section: {}
});
return (
<Lib.Document>
<Lib.Page wrap style={styles.page}>
<Lib.Text
style={styles.counter}
render={({ pageNumber, totalPages }) =>
`${pageNumber} ${t('page')} / ${t('pages', { count: totalPages })}`
}
fixed
/>
<Lib.View style={styles.section}>
<Lib.Text>Section #1</Lib.Text>
</Lib.View>
<Lib.View style={styles.section}>
<Lib.Text>Section #2</Lib.Text>
</Lib.View>
</Lib.Page>
</Lib.Document>
);
};
Thank you so much, I did not even thought the reason can be alphabet
I'm using the useTranslation hook in react to place inside my , however it isn't rendering out the text, only the name of variable I'm declaring. Is this a well known issue or should it supposed to work if done correct?