wordpress-mobile / WordPress-iOS

WordPress for iOS - Official repository
http://ios.wordpress.org/
GNU General Public License v2.0
3.7k stars 1.12k forks source link

Add support for plurals in translations #6327

Open akirk opened 7 years ago

akirk commented 7 years ago

@frosty In #6208 you introduced the construct:

    if (count == 1) {
        self.noResultsView.titleText = NSLocalizedString(@"You have 1 hidden WordPress site.", "Message informing the user that all of their sites are currently hidden (singular)");
        self.noResultsView.messageText = NSLocalizedString(@"To manage it here, set it to visible.", @"Prompt asking user to make sites visible in order to use them in the app (singular)");
    } else {
        self.noResultsView.titleText = [NSString stringWithFormat:NSLocalizedString(@"You have %lu hidden WordPress sites.", "Message informing the user that all of their sites are currently hidden (plural)"), count];
        self.noResultsView.messageText = NSLocalizedString(@"To manage them here, set them to visible.", @"Prompt asking user to make sites visible in order to use them in the app (plural)");
    }

Unfortunately this cannot be translated properly because some languages don't just have a different plural for count != 1 (for example Russian, they use one form for 1, 21, 31; another one for 2, 3, 4; and yet another one for 5, 6, …). Please see Handling Noun Plurals and Units of Measurement in the iOS docs on how this can be done universally. Thanks!

frosty commented 7 years ago

Just an update: we're waiting on some GlotPress changes so it can handle stringsDict files before we do anything about this on our side.

koke commented 7 years ago

More than supporting the specific format, I'm not sure if GlotPress can handle multiple files. @akirk if we were to import a file with just the plurals in a format that GlotPress understands, wouldn't that remove all the other originals from the project?

koke commented 7 years ago

One idea that's been growing on me today is to forget about adding new importers to GlotPress and handling everything on our side, merging all our strings into a big PO file, which GlotPress can understand perfectly.

Then we'd export each translation as a PO file as well, and use that and the original strings/stringsdict/xliff files generated by Xcode to generate the translated files that Xcode wants.

Also, neither genstrings or xcodebuild -exportLocalizations seem to be picking up plurals automatically, so we'd need to manually manage them or build a tool to extract them from the code.

koke commented 7 years ago

Some candidates for plural support (there might be more):

iconv -f utf-16le -t utf-8 WordPress/Resources/en.lproj/Localizable.strings | grep '^".*%[^"]*s\b'
"%@ comments" = "%@ comments";
"%@ days" = "%@ days";
"%@ followers" = "%@ followers";
"%@ levels" = "%@ levels";
"%@ links" = "%@ links";
"%@ of views" = "%@ of views";
"%@ posts on %@" = "%1$@ posts on %2$@";
"%@ views" = "%@ views";
"%@ views per visitor" = "%@ views per visitor";
"%@ visitors" = "%@ visitors";
"%@ was reconnected." = "%@ was reconnected.";
"%d accounts" = "%d accounts";
"%d days" = "%d days";
"%d hours" = "%d hours";
"%d months" = "%d months";
"%d pixels" = "%d pixels";
"%d years" = "%d years";
"%i menu area in this theme" = "%i menu area in this theme";
"%i menu areas in this theme" = "%i menu areas in this theme";
"%i menus available" = "%i menus available";
akirk commented 7 years ago

More than supporting the specific format, I'm not sure if GlotPress can handle multiple files. @akirk if we were to import a file with just the plurals in a format that GlotPress understands, wouldn't that remove all the other originals from the project?

Correct but not set in stone, this can be easily arranged that an imported file augments the existing strings and/or to import two files in one go. It could be done with a GlotPress plugin.

One idea that's been growing on me today is to forget about adding new importers to GlotPress and handling everything on our side, merging all our strings into a big PO file, which GlotPress can understand perfectly.

I like that a lot. A problem with generating the stringsdict on GlotPress side is that the PO way of defining plurals is with an "nplurals" formula, while stringsdict uses notions of one, some, few, many that would need to me mapped to the appriopriate plurals in each language which would require a whole new dependency of something like CLDR. This could be avoided with your approach.

koke commented 7 years ago

Progress so far:

It looks like xgettext has some support for Objective-C (which also works on Swift). Unfortunately it doesn't pick up the existing translation comments. I decided to leave string extraction to genstrings for now and focus on plurals for the moment.

I have this new macro:

#define NSLocalizedStringPlural(singular, plural, number) NSLocalizedString(singular, @"")

What we can do with this, is to have genstrings skip the plurals, then do a second pass with xgettext to extract those. We'd have to specify translation comments gettext-style though:

// Translators: Message informing the user that all of their sites are currently hidden
self.noResultsView.titleText = NSLocalizedStringPlural(@"You have 1 hidden WordPress site.", @"You have %lu hidden WordPress sites.", count);
// Translators: Prompt asking user to make sites visible in order to use them in the app
self.noResultsView.messageText = NSLocalizedStringPlural(@"To manage it here, set it to visible.", @"To manage them here, set them to visible.", count);

And we can have xgettext generate a proper PO with that:

$ xgettext WordPress/Classes/ViewRelated/Blog/BlogListViewController.m -L ObjectiveC --from-code=utf-8 -o - -k -kNSLocalizedStringPlural:1,2 -cTranslators:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-02-24 17:24+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"

#. Translators: Message informing the user that all of their sites are currently hidden
#: WordPress/Classes/ViewRelated/Blog/BlogListViewController.m:269
#, c-format
msgid "You have 1 hidden WordPress site."
msgid_plural "You have %lu hidden WordPress sites."
msgstr[0] ""
msgstr[1] ""

#. Translators: Prompt asking user to make sites visible in order to use them in the app
#: WordPress/Classes/ViewRelated/Blog/BlogListViewController.m:271
msgid "To manage it here, set it to visible."
msgid_plural "To manage them here, set them to visible."
msgstr[0] ""
msgstr[1] ""

The next step would be to be able to convert that PO into a .stringsdict. This project might help with converting the plural forms from gettext to stringsdict, but we still need to figure out the right way to extract NSStringFormatValueTypeKey (i.e. if the format specifier is %d, %lu, %@,...).

Once we have that, I believe the rest will be easy, as the gettext tools to work with PO files are really good and support merging and comparing files really well. They even support reading and writing .strings files!

akirk commented 7 years ago

FYI work has commenced in https://github.com/GlotPress/GlotPress-WP/issues/666 to address that difference in plural definition which will allow the implementation of thr stringsdict format.

stale[bot] commented 6 years ago

This issue has been marked as stale and will be automatically closed. This happened because:

However, discussion is still welcome! If the issue is still valid, please leave a comment with a brief explanation so the issue can be reopened.

stale[bot] commented 5 years ago

This issue has been marked as stale because:

Please comment with an update if you believe this issue is still valid or if it can be closed. This issue will also be reviewed for validity and priority (cc @designsimply).

designsimply commented 5 years ago

@akirk just checking in on this issue, I noticed https://github.com/GlotPress/GlotPress-WP/issues/666 is still open, is that a blocker for this issue in the iOS app?

akirk commented 5 years ago

Correct, unfortunately GlotPress development seems to have halted for now. I'll see if we can get it moving again.

stale[bot] commented 4 years ago

This issue has been marked as stale because:

Please comment with an update if you believe this issue is still valid or if it can be closed. This issue will also be reviewed for validity and priority during regularly scheduled triage sessions.

designsimply commented 4 years ago

Still valid! @akirk may I check in with you again about the status of https://github.com/GlotPress/GlotPress-WP/issues/666? I'm asking because this issue is stale, not because it's prioritized. So an update to say it's still in progress is acceptable and that will make it so we put it on hold again but check back in on it in a year if it goes stale again. 🙂

stale[bot] commented 2 years ago

This issue has been marked as stale because:

Please comment with an update if you believe this issue is still valid or if it can be closed. This issue will also be reviewed for validity and priority during regularly scheduled triage sessions.