DDG

 view release on metacpan or  search on metacpan

lib/DDG/Manual/Translation.pod  view on Meta::CPAN

  <: l('Monthly newsletter:') :>

This defines a simple token with the text 'Monthy newsletter:'. So
I<gettext>, our translation storage actually has no data file for these so
called tokens itself, because the text data file only contains the token AND a
translation. But, to have a good normalization, we store this in our database
under the same fieldnames as expected by I<gettext>, so I display it to you now
like a "partly" I<po> file without the translation, this makes it easier to
understand it:

  msgid "Monthly newsletter:"

Those tokens we store in the database of our community platform at
L<https://dukgo.com/translate/do/index>. For the token itself, there exists no page,
but here is the page for this specific token in german:
L<https://dukgo.com/translate/tokenlanguage/26811>.

In the general translation interface of the community platform, you normally
see a list of those tokens, but we will explain the translation interface
later, not to make it too complex for the moment. You can see the text to translate
right next to the word "Singular" on top. Below you see the translations of other

lib/DDG/Manual/Translation.pod  view on Meta::CPAN

different kinds of context. I<gettext> offers here the option to give a so
called B<context> additional to a token, which allows us to give a bit more
"context" without changing the token itself. In the template it would look like
this:

  <: lp('size','Medium') :>

and in the I<gettext> storage:

  msgctxt "size"
  msgid "Medium"

This means that we want the token "Medium" in the context of "size". The
advantage here is now, if there would be for example:

  <: lp('weight','Medium') :>

Then there are 2 tokens in the system to translate, both with different
context. Here you can see the page for the German translation of this shown
token L<https://dukgo.com/translate/tokenlanguage/26671>. As you see, above the
word that has to be translated, you see B<Context>, which SHOULD not be taken as

lib/DDG/Manual/Translation.pod  view on Meta::CPAN

the option for dynamic numbered cases, which requires to decide for the proper
grammatical numbers case in the language, and replace the placeholder for the
number with the number given for the case. Here is an example for a numbered case
of a token in the template (or code, or JavaScript):

  <: ln("You have %d message.","You have %d messages.",$messages) :>

This is used to define a token which is based on the number for the specific
token. In the definition in the I<gettext> storage it ends like this:

  msgid "You have %d message."
  msgid_plural "You have %d messages."

Just to directly show that this can, of course, be combined with a B<context>:

  <: lnp("email","You have %d message.","You have %d messages.",$messages) :>

which ends up in this form in I<gettext>:

  msgctxt "email"
  msgid "You have %d message."
  msgid_plural "You have %d messages."

First, I<gettext> will check with the current plural definitions (see above),
what specific plural case is required for this translation. As mentioned on the
section L</Grammatical numbers>, some languages might have more than 2 forms
for this. But whatever it is, I<gettext> handles this with the translation
datafile for the given language. I will present a translated example later.

After I<gettext> has picked the correct translated text, it will put this
translation towards L<sprintf|https://duckduckgo.com/sprintf>, which replaces
the placeholders with the proper values.

lib/DDG/Manual/Translation.pod  view on Meta::CPAN


  lp('webelieve','%s believe in %s AND %s.',
    '<a href="/about">' + lp('webelieve','We') + '</a>',
    '<a href="/goodies">' + lp('webelieve','better search') + '</a>',
    '<a href="http://donttrack.us">' + lp('webelieve','no tracking') + '</a>'
  );

Which is written like this in gettext:

  msgctxt "webelieve"
  msgid "%s believe in %s AND %s."

  msgctxt "webelieve"
  msgid "We"

  msgctxt "webelieve"
  msgid "better search"

  msgctxt "webelieve"
  msgid "no tracking"

You can now imagine that without some more comments, it is very hard to get it
right to translate those texts. Best is if the user additionally has an URL to
see the tokens in action. Especially in the flow of all untranslated tokens,
which is what most users do to help us translating.

Most combined tokens are gathered under one specific B<msgctxt>, in the
translation interface. You can click on the context given in the interface to
reach a page with all tokens of this specific context. Still we try to add
comments to every token that describes the complete text context where the token
is used.

=head3 Token translation functions

  l(            msgid,                      ... )
  ln(           msgid, msgid_plural, count, ... )
  lp(  msgctxt, msgid,                      ... )
  lnp( msgctxt, msgid, msgid_plural, count, ... )

=head3 Token scraping

I<This section is only relevant for people who put tokens in the code or the
HTML, and can be skipped. Just go directly to L</Token translation storage>.>

For L</Locale::Simple>, we made a scraper which is able to parse through any
Javascript, Perl or Python scripts, to find those tokens. It is very primitive and
can't really fully parse any code. This makes it relevant to be careful about
the positions of the tokens:

lib/DDG/Manual/Translation.pod  view on Meta::CPAN

translation tokens. You can only use placeholders, but you are not allowed to
write code that gives out the token. You only work with the result.

=head3 Token translation storage

As described in the previous sections, the database of the community platform
stores all the translations, which then gets generated into the I<po> files used
by I<gettext> in our translation system. I show you here the German
translations of the examples from above, from the I<po> that gets generated:

  msgid "Monthly newsletter:"
  msgstr "Monatlicher Newsletter:"

  msgctxt "size"
  msgid "Medium"
  msgstr "Mittelgroß"

  msgid "Hello %s!"
  msgstr "Hallo %s!"

  msgctxt "email"
  msgid "You have %d message."
  msgid_plural "You have %d messages."
  msgstr[0] "Du hast %d Nachricht."
  msgstr[1] "Du hast %d Nachrichten."

  msgid "%2$s has %1$d message."
  msgid_plural "%2$s has %1$d messages."
  msgstr[0] "%2$s hat %1$d Nachricht."
  msgstr[1] "%2$s hat %1$d Nachrichten."

  msgid "From %s to %s"
  msgstr "Von %s nach %s"

The pirate translation of the B<"Hello %s!"> example would look like this:

  msgid "Hello %s!"
  msgstr "%s, ahoi! hrrr"

Our example to change the order of the placeholders would look like this:

  msgid "From %s to %s"
  msgstr "To %2$s from %1$s"

In the case of a language which has more than 2 plural forms (See
L</Grammatical numbers>), the number in the brackets will just get stacked up:

  msgid "You have %d message."
  msgid_plural "You have %d messages."
  msgstr[0] "Mas %d spravu."
  msgstr[1] "Mas %d spravy."
  msgstr[2] "Mas %d sprav."

Interesting sidenote, the highest amount of plural forms is 6. You can find
this in the L<Arabic language|https://duckduckgo.com/?q=arabic>.

In the case of the placeholder with an amount and a dynamic text, a translation
which uses the correct order, can of course then use the normal I<sprintf>
placeholders definition:

  msgid "%2$s has %1$d message."
  msgid_plural "%2$s has %1$d messages."
  msgstr[0] "%d Nachricht hat %s."
  msgstr[1] "%d Nachrichten hat %s."

=head3 Voting translations

On the community platform, you are able to vote for an existing translation,
instead of making your own translation. If you, by mistake, haven't seen the
existing translation, your translation will automatically get converted to a
note for this translation.



( run in 2.255 seconds using v1.01-cache-2.11-cpan-5735350b133 )