Problem
Translation workflows scattered mutable global state (UPDATES and add_or_update) across workflow YAML and shell scripts, with no shared initialization, validation, or write contracts. Direct array mutation made duplicate entries possible and left Weblate payload assembly (trigger_weblate) duplicated inline in the workflow.
Acceptance Criteria
Implementation Notes
lib.sh documents and owns the translation state contract: UPDATES (ordered, deduplicated submodule basenames) and add_or_update (lang_code → space-separated names for Weblate)
is_valid_submodule_name enforces basename-only names matching ^[a-z][a-z0-9._-]*$; invalid writes surface via phase_err
trigger_weblate was lifted from start-translation.yml into translation.sh, parameterized with lang_code instead of relying on a workflow-scoped $LANG_CODE
References
.github/workflows/assets/lib.sh
.github/workflows/assets/translation.sh
.github/workflows/add-submodules.yml
.github/workflows/start-translation.yml
tests/helpers/common.bash
tests/test_lib.bats
Problem
Translation workflows scattered mutable global state (
UPDATESandadd_or_update) across workflow YAML and shell scripts, with no shared initialization, validation, or write contracts. Direct array mutation made duplicate entries possible and left Weblate payload assembly (trigger_weblate) duplicated inline in the workflow.Acceptance Criteria
UPDATESandadd_or_updateare initialized viainit_translation_state/init_add_or_update_langin all workflows and testsrecord_submodule_updateandrecord_add_or_update_submodule, with deduplication and name validationtrigger_weblatelives intranslation.sh, validatesadd_or_updatebefore POST, and acceptslang_codeas a parameterImplementation Notes
lib.shdocuments and owns the translation state contract:UPDATES(ordered, deduplicated submodule basenames) andadd_or_update(lang_code → space-separated names for Weblate)is_valid_submodule_nameenforces basename-only names matching^[a-z][a-z0-9._-]*$; invalid writes surface viaphase_errtrigger_weblatewas lifted fromstart-translation.ymlintotranslation.sh, parameterized withlang_codeinstead of relying on a workflow-scoped$LANG_CODEReferences
.github/workflows/assets/lib.sh.github/workflows/assets/translation.sh.github/workflows/add-submodules.yml.github/workflows/start-translation.ymltests/helpers/common.bashtests/test_lib.bats