Skip to content

Implement translation versioning and prevent regressions across releases #1359

Description

@NathanLovato

The translation pipeline was originally designed to build translated lesson files so that localized lessons would remain stable when the English source changed, until the corresponding community translation was updated.

We have the code to build translated lesson files but localized lessons get rebuilt each release and will have regressions.

The intended behavior instead is:

  • A French lesson is fully translated and published.
  • The English lesson receives text fixes or wording improvements.
  • The existing French lesson remains available until translators update it.
  • Once approved, the updated translation is merged and the french lesson is re-generated.

The current implementation does not provide this yet.

Currently it works like this:

  • We store PO files copied overt from the learn-gdscript-translations repo.
  • On export we always rebuild translated lesson BBCode files from the current English lesson and current PO files.
    • It generates files like lesson.fr.bbcode and lesson.meta on export.
  • Fall back to English whenever a current source string has no valid translation.
  • We ignore generated translated lesson files in Git, we don't track them
  • We don't save:
    • Which source lesson version a translation targets.
    • Previously generated localized lesson files across releases.
  • We also don't compare the current generated result with the previous published result.

TL;DR a small English edit can make the next build contain English sentences inside an otherwise translated lesson unnecessarily and a larger rewrite can cause an entire previously translated lesson to be replaced by a partially translated version.

The separate translation repository does preserve the history of PO files, but this history is not currently connected to application releases. It's just for tracking and managing translation files change history.

Issue #1305 established the general translation architecture and pipeline for Learn GDScript (and GDQuest). We generate translated lesson files, we have our internal tool for managing translations, we track translation completion, etc.

This issue is there to complete the pipeline and address the missing versioning and stability. In short we should move and complete generic translation management into Ladle while leaving Learn GD and BBCode-specific translation management in this codebase.

Ladle should provide generic operations that work with PO/POT files and project-generated manifests:

  • Parsing po and pot files + detect and report parse errors
  • Synchronize po files with pots
  • Count entries: translated, missing, fuzzy entries in absolute and %
  • Compare two translation snapshots of a given piece of content
  • Generate source content and pot/po catalog hashes
  • Generate and validate translation manifests
  • Detect translation regressions
  • Produce reports that work for CI

Learn GDScript should keep only the app-specific parts of the pipeline:

  • Extracting translatable strings from BBCode lesson ASTs + Godot resources and generating pot files
  • Analyze and validate the bbcode parts/structure of the translated lessons
  • Maybe it needs to generate its own manifest, TBD
  • Convert source lessons and PO translations into translated BBCode.
  • Validate the generated translated BBCode with the lesson parser.

The release CI pipeline should:

  • Pin the application source revision.
  • Pin the translation repository revision or snapshot.
  • Generate translated lessons.
  • Compare the candidate result with the previous approved result.
  • Refuse to publish regressions unless explicitly overridden.
  • Record the source and translation revisions used by the release.

Extra goals to consider:

  • Finding an easy workflow for testing translations for contributors outside the team and documenting it. This means we cannot rely on ladle too much.
  • Removing the presence of the PO file copies directly within the learn gdscript repository and automatically reference them from the translation repository.

In the short term

In the short term I want to find a good patch to prevent translation regressions when making small tweaks to the English version, it should not cause loss of translations in the translated languages. This would allow iterating over the lesson material quickly.

A simple way to do that is to check in all the generated translated lessons into source control with a manifest that tracks the progression for each part of the application in each lesson. Then when we make a release in the CI, we build the lessons with the new translations and discard the new translated lesson file if the progress is less than the pre the checked in version.

This can even be done outside of the CI manually as some of the lesson generation is done now.

The manifest should have this information:

  • Locale
  • Stable lesson ids
  • Translatable string count
  • Count of valid translated strings
  • Completion percentage per lesson and part of the app
  • Translation snapshot/translation repository revision used

This could be in JSON so it's compatible with ladle. Example:

{
  "commit_hash_learn_gdscript": "abc123",
  "commit_hash_learn_gdscript_translations": "48b3418",
  "lessons": {
    "function-parameters": {
      "fr": {
        "count": 42,
        "total": 42,
        "percent": 1.0
      },
      "es": {
        "count": 38,
        "total": 42,
        "percent": 0.9048
      }
    }
  }
}

In the mid term

In the midterm, we need something more robust to complete the translation pipeline.

Each source lesson should have a stable identity and a source version (probably a hash or link to source revision and a human-entered version number to signal important changes).

We want to capture just enough information to determine when edits made to a lesson are completely incompatible with previous translations to flag this for retranslation. This is not going to happen often or soon, but we want to be able to rewrite a lesson or draw practices or add new ones to improve the learning experience and handle that gracefully on the localization side: It should be transparent to the users of the app who, for the most part, should be able still follow the previous translations when we edit the English version, even if lesson changes have yet to be translated.

I think we can start with a manual system to flag when a change requires prioritizing a retranslation, for example, if we completely swap a practice, to see how often this is needed, before thinking of an automated system to detect and flag that.

I tried to think already about keeping snapshots of the different revisions of translated lessons. For example, if you had a version one, version two, and version three of a given lesson and say only version 2 is fully translated to keep presenting version 2 to students until version 3 is fully translated. This could work by keeping the generated revisions of lessons in source control.

Either way the behavior we need is something like:

  • A previously approved/validated translated lesson remains available even when the English version of the lesson changes in new updates. A new version of the lesson does not automatically replace the old localized lesson.
  • The new translated lesson becomes active only after it is approved/validated (e.g. it is 100% complete).

We should also probably make sure when we get to this to not manually pull in translations anymore but store the commit hash of the translations in the translation repository to make the builds reproducible. Be it just generally to be able to roll back a release or roll back translations.

Tasks

TO DO: break this down into the broad implementation steps/goals needed.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions