react-pdf icon indicating copy to clipboard operation
react-pdf copied to clipboard

RTL support

Open hmz22 opened this issue 2 years ago • 8 comments

Hi Dear; When use this library and using Arabic or Persian language direction problem, Please add RTL support for text and style direction: "rtl"

hmz22 avatar Nov 02 '21 16:11 hmz22

Hi @hmz22 How did you get the text in the right Unicode with this library? I got something like: image

askariali avatar Nov 16 '21 18:11 askariali

Hi @hmz22 How did you get the text in the right Unicode with this library? I got something like: image

It worked! Just by adding format: "truetype" in the font registration section, and giving it to the Page element in the StyleSheet section.

Font.register({
	family: "iranyekan",
	format: "truetype", // 1
	src: iranyekanwebregularfanum,
	fontStyle: "normal",
	fontWeight: "normal",
});

then:

const styles = StyleSheet.create({
	page: {
		fontFamily: "iranyekan", // 2
	}
});

then:

// component code
return (
      <Document>
	      <Page size="A5" orientation="landscape" style={styles.page}> {/* 3 */}
	      </Page>
      </Document>
);

askariali avatar Nov 16 '21 18:11 askariali

when pdf downloaded the arabic shown as a numbers and squares what is the problem

sadam-hussien avatar Feb 09 '22 20:02 sadam-hussien

Hi @hmz22, did you find a workaround for this issue?

kassah-mahmoud avatar Feb 16 '22 08:02 kassah-mahmoud

image Having the same issue here

kassah-mahmoud avatar Feb 16 '22 08:02 kassah-mahmoud

Any updates? has anyone found a solution?

ItaiPendler avatar May 15 '22 14:05 ItaiPendler

Any updates? has anyone found a solution?

Hi, I found a way Test the code below, it might work for you too

const [splitedText, setSplitedText] = useState([]) useEffect(()=>{ const _splitedText = text.split(" "); setSplitedText(_splitedText) },[]) store the list of words in the array now we need styles to show the all word correctly inside a <View> tag const styles = StyleSheet.create({ flexRowReverse: { flexDirection: "row-reverse" }, flexWrap: { flexWrap: "wrap" }, ml1: { marginLeft: "2pt" } }) then map splitedText inside View tag <View style={[styles.flexRowReverse, styles.flexWrap]}> {splitedText.map((word, idx) => { return ( <Text style={styles.ml1} key={idx}> {word} </Text> ); })} </View>

X3rom-S avatar Jun 29 '22 15:06 X3rom-S

Any updates? has anyone found a solution?

Hi, I found a way Test the code below, it might work for you too.

Store the list of words in the array

const [splitedText, setSplitedText] = useState([])
useEffect(()=>{
   const _splitedText = text.split(" ");
   setSplitedText(_splitedText)
},[])

now we need styles to show the all word correctly inside a <View> tag

const styles = StyleSheet.create({
  flexRowReverse: {
      flexDirection: "row-reverse"
  },
  flexWrap: {
      flexWrap: "wrap"
  },
  ml1: {
      marginLeft: "2pt"
  }
})

then map splitedText inside View tag

<View style={[styles.flexRowReverse, styles.flexWrap]}>
      {
          splitedText.map((word, idx) => {
              return (
                <Text style={styles.ml1} key={idx}>
                  {word}
                </Text>
              );
          })
      }
</View>

X3rom-S avatar Jun 29 '22 15:06 X3rom-S

Using @X3rom-S 's idea here I created a component for RTL Text:

  • The idea: reverses the sentence (mainly) by using flexDirection: "row-reverse"
  • Takes new lines ("\n") into account
  • Notice: style on the text is different bcos each word is a <Text> so I added supports for textAlign: "center" by passing textAlign="center"
import { Text, View } from '@react-pdf/renderer';
import { FC } from 'react';


interface RtlTextProps {
    containerStyle?: any | any[];
    textAlign?: "center";
    children: string;
}

/**
 * When using <Text> component and the text is longer than 1 line, the hebrew text (and arabic I THINK) is rendered wrong.
 * This component fixes that.
 */
export const RtlText: FC<RtlTextProps> = ({ children: text, ...props }) => {
    const { containerStyle: containerStyleProp, textAlign } = props;

    const sentences = text.split("\n");
    if (sentences.length > 1) {
        // each "sentence" doesn't have "\n"s in it
        return <>{sentences.map((sentence, i) => <RtlText key={i} {...props} >{sentence}</RtlText>)}</>
    }

    const words = text.split(" ");

    const TextStyle: Record<string, any> = { marginLeft: "2pt" }; //! couldn't get the `style` interface! https://github.com/diegomura/react-pdf/issues/2291

    const ContainerStyle = Array.isArray(containerStyleProp) ? containerStyleProp : [containerStyleProp]
    ContainerStyle.push({ flexWrap: "wrap", flexDirection: "row-reverse" });

    if (textAlign === "center") {
        ContainerStyle.push({ justifyContent: "center" });
    }

    return (
        <View style={ContainerStyle}>
            {
                words.map((word, index) => <Text style={TextStyle} key={index}>{word}</Text>)
            }
        </View>
    );
};

Usage example:

<RtlText textAlign={"center"} >
    {text}
</RtlText>

Related: #1394

shanike avatar May 08 '23 17:05 shanike

<Text style={{ textAlign: "right" }}>اهلا انا عربي </Text> worked fine with me despite the view this text was inside

mzaien avatar Jul 12 '23 07:07 mzaien

Any plans to support this? It would be fantastic.

Kluckmuck avatar Sep 26 '23 07:09 Kluckmuck