Skip to content

i18n improvements for units of measure#262

Merged
nthykier merged 31 commits intosingularity:masterfrom
gunchleoc:ngettext
Jun 23, 2020
Merged

i18n improvements for units of measure#262
nthykier merged 31 commits intosingularity:masterfrom
gunchleoc:ngettext

Conversation

@gunchleoc
Copy link
Contributor

@gunchleoc gunchleoc commented May 27, 2020

  • Plural support for time units
  • Localized formatting support for percent unit
  • Only supports messages.po for now, because pgettext will only become widely available with Python 3.8 and we need context for the data.

Notes:

  1. I left the money alone, because ngettext does not support floating point plurals
  2. In order to do a minimal change, I have hard-coded the plural rules. Parsing them safely and correctly is quite a lot of code (c.f. https://github.com/python/cpython/blob/3.8/Lib/gettext.py#L65). The only other option would be to switch our backend from polib to gettext.
  3. The catalogs need regenerating. I did not include them here except for gd because the resulting diff was quite big.

If translators aren't available, I can source translations for languages I don't speak from https://unicode-org.github.io/cldr-staging/charts/37/summary/root.html

@codecov-commenter
Copy link

codecov-commenter commented May 27, 2020

Codecov Report

Merging #262 into master will decrease coverage by 0.24%.
The diff coverage is 7.69%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #262      +/-   ##
==========================================
- Coverage   45.90%   45.65%   -0.25%     
==========================================
  Files          44       44              
  Lines        6915     6959      +44     
==========================================
+ Hits         3174     3177       +3     
- Misses       3741     3782      +41     
Impacted Files Coverage Δ
singularity/code/i18n.py 27.86% <6.97%> (-10.89%) ⬇️
singularity/code/g.py 67.59% <11.11%> (-0.64%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7f9993a...acf3e39. Read the comment docs.

@nthykier
Copy link
Member

Thanks for looking at this. I appreciate the effort and have been considering when we would need to use ngettext (apparently, a long time ago). I definitely want to support that.

However, I do not think that the get_plural_index method is sustainable, so I would like a different approach. AFAIR, polib can convert the .po file to a .mo file, which we can pass directly to gettext.GNUTranslations (probably with some io.BytesIO-magic to make it look like a handle). I think that would give us to best of both worlds (namely that we work entirely with po-files in the source tree and trivially pick up changes while still have a future proof handling of indexing).

If you have time and the energy to look at it, you are welcome to take a stab at it as it will be a few days before I have time to sit down and code this.

@gunchleoc gunchleoc marked this pull request as draft May 28, 2020 07:19
@gunchleoc
Copy link
Contributor Author

If we want to use native gettext, we should drop polib.

I have added tests to hit all 4 message catalogs, so I can work on this.

@nthykier
Copy link
Member

I think it will be easier to use polib.POFile to rewrite the MO file to a temporary file and then load it directly with gettext.GNUTranslations. It would also retain our current "simple" work flow for translators and testers (i.e. they do not have to worry about rebuilding translations).

@nthykier
Copy link
Member

I made a branch for this at https://github.com/singularity/singularity/tree/use-gettext-for-translations that on-the-fly compiles PO files into MO files and load them, in case you want to base your work on that.

@gunchleoc
Copy link
Contributor Author

Thanks!

I had already gotten to writing the MO someplace, but not to loading it yet. And I did go with polib in the end - msgfmt.py is not available on my system, so that would be something too complicated for translators to figure out.

We should think about packaging the files for release though instead of rewriting them every time the game starts.

@gunchleoc
Copy link
Contributor Author

I have tested your branch and I'd prefer to stick to standards, creating a proper LC_MESSAGES directory for each locale to house the translations. This is what experiences translators expect.

How about storing a shasum of the po files to check whether a mo file needs writing? Such an approach would also incur less writing to hard disk, which will extend the lifetimes of SSDs.

…s the plural translations while saving the mo file
@gunchleoc
Copy link
Contributor Author

Well, we can forget about using polib. The save_as_mofile function omits the plural strings from the mo file, so we lose the translations.

Our best bet for updating the mo files from within the program is a subprocess call to the gettext library on the operating system. This will mean jumping through hoops if we're not on Linux. So, I guess we just have to bite the bullet and require from translators that they run the update script, and include the mo files in the packaging.

@gunchleoc
Copy link
Contributor Author

gunchleoc commented Jun 6, 2020

Seems like polib is not the culprit. I deleted the plural strings from my translation file, ran utils/gettext-singularity and translated the plural forms with Virtaal, then used Virtaal to generate the .mo file. This will also omit the plural translations in the mo file.

Then I tried poedit in my Windows VM and have the same problem.

@gunchleoc
Copy link
Contributor Author

Looks like the plural forms not showing in the .mo file is a display in Virtaal - it suddenly started working today with an .mo file generated out of Virtaal. I'll look into generating the files again now and then I'll need to change our calls for the data functions.

@nthykier Do you know off the top of your head which functions added extra modifiers to the _ calls? There is no previous test coverage for them, and they will not work with standard gettext. I don't want to miss any.

@nthykier
Copy link
Member

nthykier commented Jun 7, 2020

Great it started working. :)

I have tried to fix all uses of _ with extra parameters in the master branch now (with enforcement so that new/unfixed usage will raise an exception).

@gunchleoc
Copy link
Contributor Author

Thanks!

I have now gone through all the translatable strings that have a { in them, that should cover it.

Next step will be to deal with all textdomains and hunt down any strings that need pluralization.

@nthykier
Copy link
Member

nthykier commented Jun 7, 2020

FYI: I have "cherry-picked" some of your fixes to _-calls to master that I overlooked.

@gunchleoc
Copy link
Contributor Author

OK, some new problems:

  1. We can't use message contexts without forcing everybody on Python 3.8 or newer, so we'll have to continue using our old code for data translations and use gettext for UI translations only. Meh.

  2. Language switching doesn't work. It refuses to load anything except for the system locale. The official documentation is here: https://docs.python.org/3.8/library/gettext.html#changing-languages-on-the-fly but I have had no luck with it.

@gunchleoc
Copy link
Contributor Author

I started the locale switching from scratch today and it's working now.

The only thing that's still broken at this point is that it fails with the test suite, so I have to catch a missing key there. It's working fine though when I run the game. I don't like having special code just to make the test suite happy, that smells like a bug to me.

try:
    main_localedir = dirs.get_writable_file_in_dirs('locale', 'i18n')
except KeyError:
    # Catch KeyError: 'i18n'
    # Which happens with the test suite only
    main_localedir = 'singularity/locale'

@nthykier
Copy link
Member

Have you tried if you can reproduce the issue -s ? By default the game is running without it but the test (effectively) defaults to -s

@gunchleoc
Copy link
Contributor Author

@nthykier Running ./run_singularity.sh -s without catching the KeyError works fine.

@gunchleoc gunchleoc marked this pull request as ready for review June 22, 2020 05:02
@nthykier nthykier self-requested a review June 22, 2020 06:10
Copy link
Member

@nthykier nthykier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks good, but it needs a rebase before it can be merged (due to conflicts in merging).

@gunchleoc
Copy link
Contributor Author

Generally looks good, but it needs a rebase before it can be merged (due to conflicts in merging).

$ git checkout ngettext 
Switched to branch 'ngettext'
Your branch is up to date with 'gc/ngettext'.
$ git merge master
Already up to date.

So, I don't know where you are getting the conflicts from.

I don't like rebasing branches with conflicts that have more than 1 commit in them, because I have to resolve the same conflict again and again as it steps through the commits. It's easier to just use the Squash option when merging.

@nthykier nthykier merged commit b82db8e into singularity:master Jun 23, 2020
@gunchleoc gunchleoc deleted the ngettext branch June 23, 2020 08:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants