Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug 1380356: Add ability to use localization as source lang for translation #1474

Merged
merged 33 commits into from Nov 28, 2019

Conversation

abowler2
Copy link
Collaborator

@abowler2 abowler2 commented Nov 6, 2019

Issue: Some localization communities have a hard time to directly translate from English, and prefer to do their work based on an existing translation.

This fix is working to add a Preferred Source Locale selection to allow users to select existing translations to work from.


Current status: I have added the new field to the UserProfile model and added the new setting to the UI of the Settings page.

However, the form is not functioning properly. It is currently rendering the correct selections in the menu, but any change made effects both the Custom Homepage selector and the Preferred source locale selector. Selections are not being saved in the model field for preferred_source_locale (the custom_homepage setting still saves when changes are made with the custom homepage selector).

If you could take a look at my current progress and help me to find my missteps or where I need to go from here that would be appreciated.

@mathjazz
Copy link
Collaborator

mathjazz commented Nov 6, 2019

Nice work so far!

The settings page will need a slight redesign, but for now I suggest we move the Preferred source locale selector under the Select your homepage selector - it's a similar UX and it's hard to predict which of the features will be used more often.

I would also change the label to "Select preferred source locale" and add the default value to the selector: "Default project locale".

You'll need to update the settings.js file to make sure it properly handles selectors. Similarly, you'll need to update settings.css to make sure styling of both selectors is consistent.

@abowler2
Copy link
Collaborator Author

abowler2 commented Nov 7, 2019

I made progress and am now able to save the preferred source locale. However, I have not been able to track down why when a selection is made it changes the selection for both items. This is only on the UI as the user's selections are being properly saved in the models. I tried giving unique class names to the elements, but that did not alter the behavior.

If you have a moment to take a look and offer suggestions on this I would appreciate it.

In the meantime, I'll continue to work on it as well as move forward with the next step of using this setting to determine which strings to render in the translation panel.

Copy link
Collaborator

@mathjazz mathjazz left a comment

Choose a reason for hiding this comment

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

Nice work!

  1. To fix the problem with selectors, please look into the pontoon/teams/static/js/team_selector.js file (sorry for misleading you), which handles the actual menu selector. You'll need to make sure that the element we update is withing the selector by prepending something like $(this).parents(".locale-selector")....

  2. When I select a source locale and save it, the /settings page errors after a reload:
    'None' has no attribute 'serialize'

  3. There's no way to select "Default Project Locale" once you select another locale. Unlike what I said initially when you were creating a menu, the behaviour (and the model) of the preferred locale selector should be exactly the same as for the homepage selector.

pontoon/contributors/static/css/settings.css Outdated Show resolved Hide resolved
pontoon/contributors/static/css/settings.css Outdated Show resolved Hide resolved
pontoon/contributors/static/css/settings.css Outdated Show resolved Hide resolved
@abowler2
Copy link
Collaborator Author

abowler2 commented Nov 7, 2019

Nice work!

1. To fix the problem with selectors, please look into the `pontoon/teams/static/js/team_selector.js` file (sorry for misleading you), which handles the actual menu selector. You'll need to make sure that the element we update is withing the selector by prepending something like `$(this).parents(".locale-selector")...`.

Thank you!

2. When I select a source locale and save it, the /settings page errors after a reload:
   `'None' has no attribute 'serialize'`

I just realized this myself 😞

3. There's no way to select "Default Project Locale" once you select another locale. Unlike what I said initially when you were creating a menu, the behaviour (and the model) of the preferred locale selector should be exactly the same as for the homepage selector.

OK, I originally had appended it but then since it is a Foreignkey was pretty sure it would cause an issue. Should I change the model for preferred_source_locale to CharField and then mimic the behavior of the Homepage selector then?
If so, do you want me to revert the last migration or just migrate the changes?

@mathjazz
Copy link
Collaborator

mathjazz commented Nov 7, 2019

OK, I originally had appended it but then since it is a Foreignkey was pretty sure it would cause an issue. Should I change the model for preferred_source_locale to CharField and then mimic the behavior of the Homepage selector then?

Sadly, yes.

If so, do you want me to revert the last migration or just migrate the changes?

I'll leave that to you. If possible, remove the migration and add a new one, and before you do so, make sure you unapply the current migration.

@abowler2
Copy link
Collaborator Author

abowler2 commented Nov 8, 2019

All seems to be working as expected now on the first parts of this task. Please let me know if there are any changes or adjustments needed.

Working on the next step now, or after I fix that failing test anyway 😃

@abowler2
Copy link
Collaborator Author

abowler2 commented Nov 8, 2019

So, I actually don't know why that test failed. All tests pass locally, and I'm not entirely sure what the error message is......

@adngdb
Copy link
Collaborator

adngdb commented Nov 8, 2019

@abowler2 It seems it was a random artifact from travis, or pytest, or anything. @mathjazz restarted the build and it's now passing. :)

@abowler2
Copy link
Collaborator Author

My attempt to access the data in the preferred_source_locale field on the frontend has not been successful (it comes back as undefined). I would appreciate it if you could take a look at what I have and advise on whether I'm on the right track or not and if so, where I need to make changes in order to get that data.

Of course, if I'm completely off track then if you could please provide information on how to go about accessing the data I would appreciate it.

Copy link
Collaborator

@mathjazz mathjazz left a comment

Choose a reason for hiding this comment

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

Nice work @abowler2! All the issues pointed out in #1474 (review) are addressed. I left a few notes.

In b67fd68 I don't see getUserPreferredLocale ever being called. But I'm not even sure we need to make that call from the translate app? Regarding step #3 in the bug we might be good by just changing the backend code:
https://github.com/mozilla/pontoon/blob/master/pontoon/base/views.py#L260
https://github.com/mozilla/pontoon/blob/master/pontoon/base/models.py

pontoon/base/forms.py Outdated Show resolved Hide resolved
pontoon/base/forms.py Outdated Show resolved Hide resolved
frontend/src/core/user/actions.js Outdated Show resolved Hide resolved
pontoon/contributors/templates/contributors/settings.html Outdated Show resolved Hide resolved
pontoon/contributors/templates/contributors/settings.html Outdated Show resolved Hide resolved
pontoon/contributors/static/css/settings.css Show resolved Hide resolved
pontoon/teams/static/js/team_selector.js Outdated Show resolved Hide resolved
pontoon/contributors/templates/contributors/settings.html Outdated Show resolved Hide resolved
frontend/src/core/user/reducer.js Outdated Show resolved Hide resolved
pontoon/contributors/views.py Outdated Show resolved Hide resolved
@abowler2
Copy link
Collaborator Author

abowler2 commented Nov 14, 2019

In b67fd68 I don't see getUserPreferredLocale ever being called.

I had been using a console.log() in the Translation.js file to show all the values in the user object, as it had user imported, in order to check if the value was being accessed. It would show the property but then have its value as undefined

However, as you stated that I may not even need to use the call in the translate app, it might not matter.

Copy link
Collaborator

@mathjazz mathjazz left a comment

Choose a reason for hiding this comment

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

Very nice work!

pontoon/contributors/templates/contributors/settings.html Outdated Show resolved Hide resolved
pontoon/contributors/views.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@mathjazz mathjazz left a comment

Choose a reason for hiding this comment

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

Nice work! The selected preferred source locale appears in the UI!

I've left a few notes on how to speed up the code and get rid of that JS error.

Once that's done we'll address the issue with plurals.

I also realized we'll need to fix how Machinery works, because we only store en-US strings as source in Translation Memory. We'll need to always pass en-US via get-entities and use them in Machinery.

@@ -999,6 +1005,7 @@ def user_data(request):
'force_suggestions': user.profile.force_suggestions,
},
'preferred_locales': user.profile.sorted_locales_codes,
'preferred_source_locale': user.profile.preferred_source_locale,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do we need that?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, we don't need that. That was from when I was trying to access the preferred_source_locale from the frontend. I removed it.

pontoon/base/models.py Outdated Show resolved Hide resolved
pontoon/base/models.py Outdated Show resolved Hide resolved
pontoon/base/models.py Outdated Show resolved Hide resolved
pontoon/base/models.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@mathjazz mathjazz left a comment

Choose a reason for hiding this comment

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

Thanks for the update! Getting there!

I've added notes on how to handle plurals. Please also fix the tests. And then I think the only thing that remains is to make Machinery use the en-US original.

for entity in entities:
translation_array = []
string = entity.string
string_plural = entity.string_plural
Copy link
Collaborator

Choose a reason for hiding this comment

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

String is a generic term, also used in translations. Let's call it original instead.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: I'd also add a blank line between translation_array and string.


if entity.string_plural == "":
if string_plural == "":
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: '' (single quotes).

translation = entity.get_active_translation().serialize()
translation_array.append(translation)
if preferred_source_locale != '' and entity.alternative_originals:
string = entity.alternative_originals[0].string
Copy link
Collaborator

Choose a reason for hiding this comment

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

Now to handle plurals, we should actually move this block below the if string_plural == '' - else block and then use the last available plural form for the pluralized string:

if string_plural != '':
    string_plural = entity.alternative_originals[-1].string

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This works for all the files I have in my Test project except the amo.po file. It works when only changing original to the alternative_original but the plural form causes an error with the JSON. ("The response content is not JSON-compatible")

When I try to simulate the query in the shell I get an AssertionError: Negative indexing is not supported.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hm, I'm not able to reproduce your issues.

What do you mean by "changing original to the alternative_original"?

I've made the following change:

diff --git a/pontoon/base/models.py b/pontoon/base/models.py
index 105a600a7..820741e54 100644
--- a/pontoon/base/models.py
+++ b/pontoon/base/models.py
@@ -2621,6 +2621,11 @@ class Entity(DirtyFieldsMixin, models.Model):
                     translation = entity.get_active_translation(plural_form).serialize()
                     translation_array.append(translation)
 
+            if preferred_source_locale != '' and entity.alternative_originals:
+                string = entity.alternative_originals[0].string
+                if string_plural != '':
+                    string_plural = entity.alternative_originals[-1].string
+
             entities_array.append({
                 'pk': entity.pk,
                 'original': string,

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ahh, OK. I had them set up as stand-alone if statements instead of nesting the plurals if statement. It is working fine now ~ Thank you.

@abowler2
Copy link
Collaborator Author

Made requested updates and fixed tests.

Working on how to set Machinery to use en-US original now. Let me know if there is anything in particular I need to know to complete this.

@mathjazz
Copy link
Collaborator

mathjazz commented Nov 22, 2019

Very nice work, thanks!

To fix Machinery, I think you'll need to replace selectedEntity.original in fetchHelpersData with selectedEntity.machineryOriginal, which you'll need to pass from Entity.map_entities() for every entity.

@abowler2
Copy link
Collaborator Author

That seems to have worked! Thanks

Let me know if anything further is needed.

@abowler2 abowler2 changed the title [WIP] Fix bug 1380356 Add ability to use a localization as alt source lang for translation Fix bug 1380356 Add ability to use a localization as alt source lang for translation Nov 25, 2019
Copy link
Collaborator

@mathjazz mathjazz left a comment

Choose a reason for hiding this comment

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

Excellent work!

A nice addition would be to also show the original source (i.e. machinery_original) in the Locales tab. Could you try adding that as well?

@@ -2628,6 +2628,7 @@ def map_entities(cls, locale, preferred_source_locale, entities, visible_entitie
'pk': entity.pk,
'original': original,
'original_plural': original_plural,
'machineryOriginal': entity.string,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: we use snake_case in python, so machinery_original.

@abowler2
Copy link
Collaborator Author

I'll definitely work on showing the original source in the Locals tab, and let you know if I have questions.

@mathjazz mathjazz changed the title Fix bug 1380356 Add ability to use a localization as alt source lang for translation Fix bug 1380356: Add ability to use localization as source lang for translation Nov 26, 2019
@abowler2
Copy link
Collaborator Author

A nice addition would be to also show the original source (i.e. machinery_original) in the Locales tab. Could you try adding that as well?

I pushed what I have so far for this....but I just want to say right off that while it is working...it's pretty ugly 🤣
In order to refactor it I needed some info (and I also wanted to be sure I'm even on the right track with it).

  1. There is no ForeignKey between Locale and Entity, and I couldn't find a common field. Also, the entity does not exist in Translation so making use of the existing code does not work. Given this, I hard coded the pk in order to access the properties for the original source. If there is a way for this to be dynamic, or if there is another way to go about this, please let me know.

  2. For the original source to display the same as the other translations, I had to rename the keys in the dict, and I'm not sure if there is a more efficient way to do this.

  3. I was unsure how to add the original source in a way that would allow it to be sorted within the other translations, so I prepended it to the beginning.

  4. When the Locale/code link is clicked on the frontend it gives a 404-error as this was manually entered so it is not a valid link. How should this be handled?

I think that sums up the current issues.

TIA 😄

Copy link
Collaborator

@mathjazz mathjazz left a comment

Choose a reason for hiding this comment

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

@abowler2 Thanks for looking into it, but I suggest we postpone this to a followup PR. I'll file a bug describing how to implement passing original source string into other locales panel. It requires one other refactor, and to avoid making too big PRs, I suggest we do it separately.

Please revert your last commit and address a few more nits I found and we're good.


def __init__(self, *args, **kwargs):
super(UserPreferredSourceLocaleForm, self).__init__(*args, **kwargs)
preferred_source_locales = list(Locale.objects.all().values_list('code', 'name'))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: We should actually call this all_locales, same as above.

@@ -2205,6 +2208,20 @@ def prefetch_active_translations(self, locale):
)
)

def prefetch_alternative_originals(self, code):
"""
Prefetch active translations for given preferred source locale.
Copy link
Collaborator

Choose a reason for hiding this comment

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

active -> approved

locale,
preferred_source_locale,
entities_to_map,
visible_entities
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: please add comma at the end of the line. That code style allows us to add/remove parameters by making 1-line diffs.

"""Save preferred source locale """
form = forms.UserPreferredSourceLocaleForm(
request.POST,
instance=request.user.profile
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: comma at the end of the line.

@mathjazz
Copy link
Collaborator

Bug filed:
https://bugzilla.mozilla.org/show_bug.cgi?id=1600134

You can also split it in two patches if you want (refactor + displaying source string).

Copy link
Collaborator

@mathjazz mathjazz left a comment

Choose a reason for hiding this comment

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

Excellent job, April!

Most of our users don't need this feature, but those how do, need it desperately. Thank you!

@mathjazz mathjazz merged commit a2cd5f8 into mozilla:master Nov 28, 2019
@abowler2 abowler2 deleted the preferred-source branch November 28, 2019 19:39
abowler2 added a commit to abowler2/pontoon that referenced this pull request Dec 10, 2019
…ozilla#1474)

* Add ability for users to select a preferred source locale
* Whenever translation to that locale are available,
  use it as source in string list and source string panel
* Keep using original string as the source for Machinery
* Remove `marked` and `marked_plural` from Entity data
abowler2 added a commit to abowler2/pontoon that referenced this pull request Dec 11, 2019
…ozilla#1474)

* Add ability for users to select a preferred source locale
* Whenever translation to that locale are available,
  use it as source in string list and source string panel
* Keep using original string as the source for Machinery
* Remove `marked` and `marked_plural` from Entity data
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.

None yet

3 participants