Subject: bug#26302: [website] translations

From: Ludovic Courtès <[email-masked]>
Date: Thu, 19 Sep 2019 13:50:10 +0200

Hi,

"pelzflorian (Florian Pelz)" <[email-masked]> skribis:

>> > +(define (sgettext x)
>> > +  "After choosing an identifier for marking s-expressions for
>> > +translation, make it usable by defining a macro with it calling
>> > +sgettext.  If for example the chosen identifier is G_,
>> > +use (define-syntax G_ sgettext)."
>> > +  (syntax-case x ()
>> > +    ((id exp)
>> > +     (let* ((msgid (sexp->msgid (syntax->datum #'exp)))
>> > +            (new-exp (deconstruct (syntax->datum #'exp)
>> > +                                  (gettext msgid))))
>> > +       (datum->syntax #'id new-exp)))))
>> 
>> For this and other similar macros you must use ‘define-syntax’, not
>> ‘define’, so that they are defined at expansion time, not at run time.
>
> As per the above docstring, I already have a definition
>
>   (define-syntax G_ sgettext)
>
> in (apps i18n).  Possibly I should just move it here.

Hmmm right.  It works, but it’s surprising and “borderline”.

If all you want is an alias, I’d recommend writing, say:

  (define-syntax sgettext …)
  (define-syntax G_
    (identifier-syntax sgettext))

>> (It doesn’t make any difference when you’re evaluating code since both
>> phases run in the same module, but it does make a difference when these
>> phases happen at different times, in different processes.)
>> 
>> Consequently, you must arrange for ‘sexp->msgid’ and ‘deconstruct’ to be
>> available at expansion time too.  This can be done by wrapping their
>> definition in ‘eval-when’:
>> 
>>   (eval-when (load expand eval)
>>     (define (sexp->msgid …) …)
>>     (define (deconstruct …) …))
>> 
>> But actually it’s not clear to me why these are macros.  I think they
>> could be regular procedures and it’d work just fine, no?
>> 
>
> I do not understand.  sexp->msgid and deconstruct are procedures, not
> syntax transformers.  I can add eval-when, but the current code runs
> as expected for me.

I tried to explain above but you can check the Guile manual on
‘eval-when’ (info "(guile) Eval When").  The example there hopefully
clarifies what the problem is.

>> > +(define %plural-numbers
>> > +  ;; Hard-coded list of input numbers such that for each language’s
>> > +  ;; plural formula, for each possible output grammatical number,
>> > +  ;; there is an n among %plural-numbers that yields this output
>> > +  ;; (cf. section Plural forms in the gettext manual), except 1 is
>> > +  ;; omitted from this list because it is a special case for
>> > +  ;; sngettext.  That is, calling ngettext with each number from
>> > +  ;; %plural-numbers and with 1 in any locale is guaranteed to return
>> > +  ;; each plural form at least once.  It would be more resilient
>> > +  ;; towards new languages if instead of hard-coding we computed this
>> > +  ;; from the Plural-Forms in the MO file header entry, but that is
>> > +  ;; not worth the incurred code complexity.
>> > +  '(0 2 3 11 100))
>> 
>> I don’t understand this: are these the only plural numbers in all
>> languages, or…?
>> 
>
> Yes, in all languages for which a plural= formula is documented in the
> gettext manual.
>
> For example, Arabic has
>
>           Plural-Forms: nplurals=6; \
>               plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 \
>               : n%100>=11 ? 4 : 5;
>
> with input plural numbers 0, 1, 2, 3, 11, 100 mapping to all outputs
> 0, 1, 2, 3, 4, 5.
>
> Maybe I should add this example to the code comment.

Oh I see.  Maybe just link to the relevant section of the manual ("info
(gettext) Plural forms").

I think you can go ahead and push this series to a branch, say
‘wip-i18n’ (the ‘wip-’ prefix meaning that you reserve the right to
rebase the branch as you will.)

We can then maybe set up a ‘static-web-site’ service on berlin, with
appropriate nginx rules, to build and publish the manual at a separate
URL so we can all test it.  See hydra/berlin.scm in maintenance.git.

Thoughts?

Thank you!

Ludo’.