python-openxml / python-docx

Create and modify Word documents with Python
MIT License
4.36k stars 1.08k forks source link

rtl support in headers #387

Open antonays opened 7 years ago

antonays commented 7 years ago

I am trying to figure out how to add rtl support in headers. Following this post and explicitly defining a style on the header paragraph does work, but it seem to overwrite the header style. So my question would probably be, how to apply two styles? or create a "hybrid" still that will be both rtl and keep the heading style.

Trying this run = paragraph.add_run() run.font.rtl=True

Does not have any effect, rtl seems to only work when setting the paragraph style.

scanny commented 7 years ago

I'll need more of your code (like 10-line minimal example) to tell.

But the general gist would be to manually (using Word) change the header style in the template document before opening it with python-docx, and then apply that header style without modification.

antonays commented 7 years ago

Thanks @scanny for your reply,

What i'm trying to do is to generate docx files using python with python-docx. Everything is cool except that i need the document to be in Hebrew, which creates a bunch of problem with text direction and alignment.

I apply a header in this way p = doc.add_heading(text, level=level) p.alignment = WD_ALIGN_PARAGRAPH.RIGHT

This gives the header just as expected, it has the correct style in word and it has the blue color and shows up in the TOC and all. However, if the given text is in Hebrew, then the text in Word appears word-wise reversed, that means that the last word in the sentence will show up first.

Instead, applying in this way: rtlstyle = document.styles.add_style('rtl', WD_STYLE_TYPE.CHARACTER) rtlstyle.font.rtl = True p = doc.add_heading(text, level=level) p.alignment = WD_ALIGN_PARAGRAPH.RIGHT p.style = rtlstyle

Gives a paragraph with correct Hebrew (not reversed), but loses the properties of the header, doesn't appear in TOC etc...

Using a similar approach on just a normal paragraph, p = doc.add_paragraph(style = rtlstyle) r = p.add_run() paragraph_format = p.paragraph_format paragraph_format.right_indent = Pt(rightIntend) font = r.font font.name = 'Arial' font.size = Pt(size) font.rtl = True font.bold = True r.add_text(text)

Works well and give the paragraph correctly organized as Hebrew should be, But, applying text formatting options like size and bold, seem to have no effect if the text is in Hebrew. If it is in English, all works well. That is, if the text is Hebrew, no matter what size of font i define or what font face, it will always be 'Droid Sans Hebrew' (In LibreOffice), size 11, no bold and no nothing.

I thought that maybe its a problem with LibreOffice so tried also on MS Word 365 with the same results.

I'm sorry but i didn't understand your suggestion.

scanny commented 7 years ago

Ok, a couple things.

  1. in Word, the terms "header" and "heading" are both meaningful. A header runs across the top of the page within the top margin area, usually having document title and page number, that sort of thing. A heading (or more precisely a "section heading") is the bold (or whatever) short–ish text title that introduces a new section.

    I think what you're talking about here is headings, so lets keep the terminology straight. My prior response was based on the idea you needed something on headers, because that was what you asked for.

  2. It matters whether all headings will be in Hebrew (RTL) or whether they're mixed RTL and LTR. So let me know and we'll go from there.

  3. You'll need to read and understand this section in the docs (on styles) and the one that follows it (by hitting the "Next" button) before we proceed. My earlier suggestions might suddenly make more sense after :)
    http://python-docx.readthedocs.io/en/latest/user/styles-understanding.html

antonays commented 7 years ago

Ok, Classic case of READ THE DOCS FIRST for me..

I ended up fixing it by defining a new style that inherits a basic Heading rtlheading1style = doc.styles.add_style('rtlheading1', WD_STYLE_TYPE.PARAGRAPH) rtlheading1style.base_style = doc.styles['Heading 1'] rtlheading1style.font.rtl = True p = doc.add_heading(text, level=level) p.style = doc.styles['rtlheading1']

one comment though - attaching a style object with p.style = rtlheading1 did not work for me, only referring to the dictionary doc.styles worked.

Thanks a lot @scanny for pointing out the right direction!

I do however have one more issue, Applying any change on the settings of the style, for example: rtlheading1style.font.name = 'Arial' rtlheading1style.font.size = Pt(16) still has no effect, and i always get the default font and size.

masoudpz commented 6 years ago

when i changed font to rtl , font size and font name changed to default, like antonays;s issue, how can i fix this problem?

scanny commented 6 years ago

@masoudpz You'll need to take the time to give us more to go on. Include the shortest segment of code that reproduces this behavior and describe the behavior you're seeing along with what you expect.

lemontree210 commented 3 years ago

As for .font.bold not showing in resulting document with right-to-left-text, I think I have figured this out.

If you produce a bold run of right-to-left text (through .font.rtl = True and .font.bold = True), in the resulting Word document you will see that the 'Bold' property is toggled on for this particular piece of text (the Bold button is pressed), but the text is not shown in bold. (BTW, if you upload the same document to Google Docs, text will be bold!)

I tried to at least solve this with VBA and finally found out that for the right-to-left text, the right property to make the font bold is (in VBA) .Font.BoldBi, not Font.Bold.

Once I apply .Font.BoldBi = True to a selection in VBA, it finally shows in bold.

So I guess there is no way to make right-to-left text bold purely with python-docx. At least not that I know of.