5

I use ugettext_lazy as _ , and in a models file my string is represented in this way:


    s = _("firstline"  
          "secondline"  
          "thirdline")

But after running makemessages I found that in the .po file only "firstline" is marked for translation, the rest are absent. I wouldn't like to avoid using multilining, so is there any way to make translation work with this?

UPD:

Should complement my question: I need my multiline strings to be proceeded by django's makemessages

The best solution I can imagine so far, is


    s = str(_("firstline")) +  
          str(_("secondline") +  
          str(_("thirdline"))

Julie B
  • 51
  • 1
  • 5

3 Answers3

-1

Edit : Goodguy mentions that makemessages won't do Python parsing, hence not properly collect those kind of "multiline" strings.

The first part is actually true and I stand corrected on this (my bad) - BUT xgettext does the same adjacent strings concatenation has Python, as mentionned here :

Some internationalization tools -- notably xgettext -- have already been special-cased for implicit concatenation,

and here:

Note also that long strings can be split across lines, into multiple adjacent string tokens. Automatic string concatenation is performed at compile time according to ISO C and ISO C++; xgettext also supports this syntax.

and as a matter of fact me and half a dozen co-workers have been using this very pattern for years on dozen of projects.

s = _("firstline" "secondline" "thirdline")

Python xgettext will automatically concatenate literal strings separated only by blank spaces (space, newlines etc), so this is the exact equivalent of

s = _("firstlinesecondlinethirdline")

If you only get the first of those strings in your po file then the problem is elsewhere - either your snippet is NOT what you actually have in your code or your po file is not correctly updated or anything else... (broken xgettext version maybe ?).

NB : this :

s = str(_("firstline")) +  
      str(_("secondline") +  
      str(_("thirdline"))

is about the worse possible solution from the translator's point of view (and can even make your message just impossible to translate in some languages).

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
  • @JulieB it doesn't. What matters here is what you have _between_ the strings literals (and that they are literals as it doesn't work with variables, but then it would raise a SyntaxError). I've been using this very same pattern hundreds of times and believe me it JustWork. If you don't get any error at all but only find the first of your strings in your .po file then the problem is elsewhere. Please post the _exact_ code snippet (copy-pasted from your source code). – bruno desthuilliers Feb 13 '17 at 14:12
  • Also make sure that at this point in your code `_` is effectively bound to `ugettext` or `ugettext_lazy` - remember that Python functions are plain objects and live in the same namespaces as any other variables. – bruno desthuilliers Feb 13 '17 at 14:23
  • I've got the same thing with my very snippet from the question – Julie B Feb 13 '17 at 14:26
  • @JulieB which OS, which gettext version please ? – bruno desthuilliers Feb 14 '17 at 09:34
  • Centos 7, glad to tell you which gettext version if i knew how) – Julie B Mar 03 '17 at 10:05
  • @JulieB simply typing ` gettext --version` in your shell should do. – bruno desthuilliers Mar 03 '17 at 13:29
  • `gettext (GNU gettext-runtime) 0.18.2`. Shame on me, tried to do it using the python shell – Julie B Mar 06 '17 at 20:04
  • Ok you might possibly have a buggy version of xgtettext then, cf http://savannah.gnu.org/bugs/?35109 – bruno desthuilliers Mar 07 '17 at 08:20
  • f-strings do not work this way unfortunately... – Ron Jan 03 '22 at 13:05
  • This is a non-answer. Why mention everything that doesn't work and nothing that does work? – Cerin Aug 24 '23 at 01:10
-1

I had a similar issue and solved it using standard Python multi-line but single-string format. For example for your string :

    s = _("firstline\
          secondline\ 
          thirdline")
PolRaguénès
  • 160
  • 3
  • 12
  • 1
    Unfortunately, this will (django 3.2.10) will add a massive amount of whitespaces so it's not a working solution for me... – Ron Jan 03 '22 at 07:32
-2

Update: The actual problem is that makemessages is not doing python (and JS and etc.) parsing, so it would not concatenate multiline strings as expected. Solution below will not work either (it won't see computed values).

Unfortunately, you have to find another way to format your message, preferably by splitting it into single-line parts.

Previous answer:

ugettext_lazy can only accept single argument so it's up to you how you want your translations to be.

If you are fine with "firstline" "secondline" "thirdline" being exported for translation as a single sentence you can do something like this:

s = _(' '.join(["firstline", "secondline", "thirdline"]))

If you want to keep them as a separate translation sentences when something like this may also work:

s = ' '.join(_(line) for line in ["firstline", "secondline", "thirdline"])

Or just call _ on every line and concatenate them

dmvrtx
  • 168
  • 1
  • 2
  • 7
  • The OP is sending a single argument - consecutive litteral strings separated only by blank spaces are merged together. – bruno desthuilliers Feb 13 '17 at 12:04
  • @brunodesthuilliers can you elaborate on the reasons to downvote answer? It explains to OP how to achieve three separate lines for translation and neither you nor me are aware of OP purposes to decide for them if this answer is worthless or helpful. – dmvrtx Feb 13 '17 at 12:13
  • the explanation is in my above comment - just juxtaposing strings - like in the OP's snippet - will _already_ concatenate them. This is a documented part of Python's grammar. – bruno desthuilliers Feb 13 '17 at 12:33
  • your comment is a correction to a first part of my comment. it has a valid point that snippet may not be complete, but wording of original post may suggest that the goal is to have translations of three separate lines in one call - which is what I suggest in the second part of my comment. IMO it's the decision of OP to decide which comment is helpful unless one of them is obvious fraud or scam. – dmvrtx Feb 13 '17 at 12:39
  • your answer __as currently written__ suggests that the OP's snippet is sending three distinct strings to `ugettext_lazy` - which is not the case - and that the solution is to manually join those strings - which is still not the case. IOW your answer (at least the main part of it) is actually just wrong. Remember that one of the goals behind SO is to build a __reliable__ QA database, not only to address the OP's specific question. From this POV, it's the whole community's duty to "decide" which answer is useful, and that's why we can up or down vote answers. – bruno desthuilliers Feb 13 '17 at 12:56
  • Wait, what part of my answer is *wrong*? You claim that given language constructions do not work? Or are.they just not according to _your_ taste? – dmvrtx Feb 13 '17 at 13:02
  • I state that adjacent ltteral string are automatically concatenated in a single one, so in the OP snippet `ugettext` only receives one single string (it's not a "claim", it's a fact), so your statement about having to manually concatenate those strings before is wrong, and your mention of `ugettext` "only accepting a single argument" is misleading in that it can be understood as "the OP's snippet actually passes three arguments", which is not the case. If you don't get what's wrong with your answer by now I'm sorry for you, but I won't try to explain it a fourth time. – bruno desthuilliers Feb 13 '17 at 13:15
  • As you've stated in your comment if concatenation is not happening, when snippet is not technically identical to OP's code. That's why I suggested other ways of solving "translate multiple lines" problem, to outline possible options. While I agree, that first option is superfluous I don't see how it makes whole answer wrong. What I see from your side is a very subjective judgement and your answer while being technically right is stating obvious without giving any further hints to develop for OP. But again, this is for OP to decide. – dmvrtx Feb 13 '17 at 14:04
  • The only useful hint here has already been given : post the _exact_ code, and if the problem is not with the real code, then it's elsewhere obviously so let's not waste time trying to fix something that is not broken. Nothing subjective here, only plain common sense and a bit of experience solving "things that should work but do not" problems. – bruno desthuilliers Feb 13 '17 at 14:20
  • Once again, "the only useful thing" is a very arrogant and subjective comment in this discussion. You may have a lot of experience solving things that do not work but it doesn't mean that you are right in downvoting answers that do not suit your views on the problem. This is a bad mark for SO community, because people will just stop answering questions to avoid losing reputation because of people like you. – dmvrtx Feb 13 '17 at 14:30
  • @brunodesthuilliers the only useful hint was to look into the `makemessages` code and understand that it does not do python parsing or JS parsing. From python point of view snippet is right, but `makemessages` sees only first string token in this case. – dmvrtx Feb 13 '17 at 15:37