JiriTrecak / Laurine

Laurine - Localization code generator written in Swift. Sweet!
MIT License
1.25k stars 77 forks source link

Plural support #9

Closed JiriTrecak closed 8 years ago

JiriTrecak commented 8 years ago

Introduction & My approach

Hello guys, I am glad you are enjoying this project so much - it is trending, people write about it, and I really strive to make it the ultimate solution for translations in the application.

Now, the base is already great, but what is really missing is support for Plurals. You probably know how it is done in the iOS - instead of writing it to .strings, you generate .stringsdict (plist, really) that contains rules for how the word should change with different number of X.

I am not the biggest fan of that approach, but it is what it is and we have to work with what we have (plus there is probably not better solution, I know). I would like to know feedback about this topic. My idea is following:

The output would then look like this:

Localizations.Profile.Friends(1) // 1 Friend
Localizations.Profile.Friends(2) // 2 Friends
Localizations.Profile.Friends(10) // 10 Friends

What do you say? What are your opinions about this?

Possible enhancement for future version

Now as I mentioned, I am really not the biggest fan of .stringdict file - it is complicated to write. So I was thinking that it could be possible to write plural localizations directly from strings. Obviously, I would never want to build that decision engine, that is way out of scope of this project and would be completely pointless, but, imagine following. Instead of writing everything to .stringdict, write it to .strings as following:

"Localizations.Profile.Friends[one]" = "%d Friend";
"Localizations.Profile.Friends[few]" = "%d Friends";
"Localizations.Profile.Friends[many]" = "%d Friends";

key in [] is the same key that you would use in dictionary to write rule. Except you would not need the dictionary, because that would be built dynamically by the system and then fed to iOS localization engine (if that is possible, which I am, so far, unsure of.

Do you think we could change the base format of the localizations and do you think it is viable, or it seems like too much over-engineering and we should just stick with .stringdict?

Thank you for your feedback!

Frizlab commented 8 years ago

I actually wrote a very complete (maybe a bit over engineered) solution to support custom replacements and automatic attributed strings directly in strings files (no stringsdic)……… but I cannot divulge the source as I do not own it :( The plural is handled (in part) this way: #n# <mouse:mice> (and for weird languages with more than 2 forms it works too: #n# <singular:dual:plural> etc.) I am not using the system component to make the actual pluralization though; instead there’s a special key in my localization files to “describe” the different sort of plural that exist in the language and which form to use for which number.

My guess is the best solution for your project would be the latest described, if it is actually possible to feed a dictionary to the pluralization engine. If it not possible, the first solution will be a reliable solution.

Having a way to be able to just do Localizations.Profile.Friends(n) is just awesome!

JiriTrecak commented 8 years ago

Just so all know the progress, I am going with following solution:

Definition in .strings:

"Localizations.Profile.Friends{one}" = "%d Friend";
"Localizations.Profile.Friends{other}" = "%d Friends";

or with parameters:

"Localizations.Profile.Friends{other}" = "%d Friends of %@";

Actual code:

Localizations.Profile.Friends(count: n)

or with parameters:

Localizations.Profile.Friends(count: n, value1: "Jiri")

I got inspiration from library from Mattt (https://github.com/mattt/TTTLocalizedPluralString), it is very nicely done and basically goes around iOS localization engine - because it implements the rules on its own. By using this system, I can actually create what I wrote above. This is coming to version 0.3, in version 0.4 I will extend this system to include gender as well, so it will become:

Localizations.Profile.Friends(count: n, gender: .Male, value1: "Jiri")

Does that sound awesome enough? ^^

pfandrade commented 8 years ago

Why is this needed?

If you have a key in your .strings file like so:

"Localizations.Profile.Friends" = "%d Friend(s)";

It will get picked up by Laurine. The you create your .stringsdict and just use the "Localizations.Profile.Friends" as the key. At runtime the .stringsdict will be checked first and your pluralization will be done by whatever is defined in the .stringsdict

Isn't this sufficient?

JiriTrecak commented 8 years ago

After thinking if that is the best solution, I figured this is - thank you. I will add information about this into README and also modify the example so it contains this example as well.