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

Translate Experiment using a related "TranslatedContent" model #1204

Closed
3 of 4 tasks
drikusroor opened this issue Jul 29, 2024 · 5 comments
Closed
3 of 4 tasks

Translate Experiment using a related "TranslatedContent" model #1204

drikusroor opened this issue Jul 29, 2024 · 5 comments
Assignees

Comments

@drikusroor
Copy link
Contributor

drikusroor commented Jul 29, 2024

Is your feature request related to a problem? Please describe.
Right now, we don't have a clear way to provide translated / localised / internationalised experiments to users. The only option we currently have is to create a "new Experiment" for a new language and write the title, description, etc. in that language. However, the app's non-experiment-related or non-configurable content (button's, links, translation keys in the experiment blocks) might still show up in a different language.

Describe the solution you'd like
A better way, as discussed on Tuesday July 23, might be to create a new model (named ExperimentTranslatedContent or something) which contains all the textual content of an experiment for a given language. In pseudocode, that model would look something like this:

ExperimentTranslatedContent
- experiment (FK)
- index (integer)
- language ('en' | 'nl' | 'zh', etc.)
- title
- description
- content
- about_content

Which content should then be shown to the user?

Based on the preference from the client, in the form of a URL parameter (?lang=jp), we can serialise the experiment with the right language content and get a fallback in case the chosen language's content is not available.

Which fallback should then be chosen?

We could use the index to arrange the fallback priority order. In other words, if an ETC (Exp. Translated Content) for Dutch (nl) is listed on top (index = 0), it can be the fallback for an English ETC with index = 1.

Alternatively, we could think about a more elaborate system of fallbacks in the future if needed. An option could be a fallback_for property with an array of languages (en, nl) for an ETC and make Django check that list if it cannot find the content for a preferred language. E.g. the user prefers Catalan, but the Spanish ETC has fallback_for=[ca,pt] and therefore falls back to the Spanish ETC.

Requirements

  • Create a model named ExperimentTranslatedContent (see pseudocode above)
  • Make sure to use django-nested-admin to create a nested inline form.
  • Try to make at least one related ExperimentTranslatedContent mandatory in order to create/save an experiment. (An Experiment without content should not be possible).
  • Serialise the get_experiment's content according to the preferred language and make sure the json structure stays the same (so the frontend needs no revising)
  • The language in which the experiment will be returned should be based on the Accept-Language header supplied by the browser.
  • If an experiment's language content is not available for the language from the Accept-Language header, fallback to the highest available experiment language content bases on the index (index=0 would be first fallback).
  • The language ultimately selected (preferred or fallback) should be used for all (both experiment- and non-experiment-related) content by setting the language cookie to that language.

Good to know / Future tasks

We will most likely have to do this for ThemeConfig and Block as well. I'll list these as a "todo" list below, which allows us to create issues from them easily whenever we want to:

@BeritJanssen
Copy link
Collaborator

BeritJanssen commented Jul 30, 2024

Thank you for adding this!

Perhaps we can also leave the language parameter to another issue. It might actually be less frustrating that way, since we don't want users to just go ahead and change the parameter, right? Right now, if a user sees lang=en but they prefer Spanish, right might try to edit the lang parameter, while we might not have that translation option.

What I haven't really thought through yet are scenarios as follows:

  • an experiment has database translations in, say, Dutch and English
  • it uses questions which have also been translated to Spanish
  • we get a user whose browser settings indicate they prefer Spanish

Do we then (as was now the case) give them a mixture of English and Spanish? Do we "force" the language cookie to one of the translations available for the experiment? I guess the latter. We would then probably select the language cookie as follows:

  • check if any of the preferred languages of the user matches the ExperimentTranslatedContent, if so, select that language
  • otherwise, select fallback (probably English or Dutch in most cases)

There should be a mechanism to check, when entering a new ExperimentTranslatedContent, if all associated Block (rules), ThemeConfig, and Question objects also have that language available, and raise a warning to the user if that is not the case, listing the objects for which they should still add translations.

If we do implement the TranslatedContent models with fallback orders, I think an issue to allow users to switch languages would be something to implement soon after.

@drikusroor
Copy link
Contributor Author

drikusroor commented Jul 30, 2024

Thank you for adding this!

Perhaps we can also leave the language parameter to another issue. It might actually be less frustrating that way, since we don't want users to just go ahead and change the parameter, right? Right now, if a user sees lang=en but they prefer Spanish, right might try to edit the lang parameter, while we might not have that translation option.

Yes, good idea. I'll add it as a future task.

What I haven't really thought through yet are scenarios as follows:

  • an experiment has database translations in, say, Dutch and English
  • it uses questions which have also been translated to Spanish
  • we get a user whose browser settings indicate they prefer Spanish

Do we then (as was now the case) give them a mixture of English and Spanish? Do we "force" the language cookie to one of the translations available for the experiment? I guess the latter. We would then probably select the language cookie as follows:

  • check if any of the preferred languages of the user matches the ExperimentTranslatedContent, if so, select that language
  • otherwise, select fallback (probably English or Dutch in most cases)

There should be a mechanism to check, when entering a new ExperimentTranslatedContent, if all associated Block (rules), ThemeConfig, and Question objects also have that language available, and raise a warning to the user if that is not the case, listing the objects for which they should still add translations.

If we do implement the TranslatedContent models with fallback orders, I think an issue to allow users to switch languages would be something to implement soon after.

Yes, I was also thinking about this and I agree with your approach. I'll make this approach explicit in the requirements.

@drikusroor drikusroor self-assigned this Jul 31, 2024
drikusroor added a commit that referenced this issue Aug 2, 2024
…iew as this has been replaced at the experiment level per #1204
drikusroor added a commit that referenced this issue Aug 5, 2024
* feat: Add translated_content model with FK to experiment and add migrations

* fix: Fix reverse migration

* feat: Remove experiment fields and migrations

The commit removes the `name`, `description`, `consent`, and `about_content` fields from the `Experiment` model and updates the admin forms accordingly.

* refactor: Only show an empty form for a newly to be created experiment

* feat: Add fallback option to get_translated_content method

This commit adds a `fallback` parameter to the `get_translated_content` method in the `Experiment` model. When set to `True`, if no content is found for the specified language, it will return the primary content instead. If `fallback` is set to `False` and no content is found, a `ValueError` will be raised.

Refactor the `get_content` method to `get_translated_content` to better reflect its purpose.

* refactor: Rename primary_content to fallback_content

* fix(test): Fix & update tests after adding experiment translated content

* chore: Rename primary content to fallback content

* refactor: Use `get_language` instead of checking `request.LANGUAGE_CODE`

* refactor: Remove unnecessary code for setting language in get_block view as this has been replaced at the experiment level per #1204

* refactor: Moving setting the language cookie from `get_block` to `get_experiment`

* test: Add tests for getting the right language content based on the `Accept-Language` header's value

* refactor: Delete all experiment translated content

This commit modifies the migration file `0050_migrate_experiment_content_to_translatedmakemigrations.py` to delete all experiment translated content using the `ExperimentTranslatedContent.objects.all().delete()` method. This change is necessary to clean up the database and ensure that no translated content exists anymore after running the reverse migration.

* fix: Fix ci by changing `docker-compose` command to `docker compose`
@drikusroor
Copy link
Contributor Author

  • Translate ThemeConfig using a related "TranslatedContent" model

I don't think ThemeConfig contains any textual content shown to the user right? We might want to skip this one.

SocialMediaConfig, however, does contain textual content for sharing the Experiment so we might want to translate this. There are two ways we can do this:

  • Add it to ExperimentTranslatedContent
  • Modify the SocialMediaConfig model so that
    • The experiment OneToOne field becomes a FK, and
    • The language field gets added to it

@BeritJanssen
Copy link
Collaborator

ThemeConfig itself doesn't contain text, but FooterConfig does.

As for SocialMediaConfig, I think we could move the content field to ExperimentTranslatedContent indeed, and rename it to something like social_media_message?

@BeritJanssen
Copy link
Collaborator

Now that #1270 is closed, we can consider this done.

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

No branches or pull requests

2 participants