Skip to content

Commit fc0e761

Browse files
committed
Update sync behaviour
1 parent f2fc978 commit fc0e761

5 files changed

Lines changed: 133 additions & 13 deletions

File tree

pontoon/sync/core/__init__.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
Entity,
1212
Locale,
1313
Project,
14+
ProjectLocale,
1415
TranslatedResource,
1516
Translation,
1617
User,
@@ -50,10 +51,30 @@ def sync_project(
5051
log.error(f"{log_prefix} {e}")
5152
raise e
5253

53-
locale_map: dict[str, Locale] = {
54-
lc.code: lc for lc in project.locales.order_by("code")
55-
}
54+
locale_map: dict[str, Locale]
55+
if project.set_locales_from_repo:
56+
if not paths.locales:
57+
errmsg = "No locales found in repo"
58+
log.error(f"{log_prefix} {errmsg}")
59+
raise Exception(errmsg)
60+
locales = Locale.objects.filter(code__in=paths.locales).order_by("code")
61+
locale_map = {lc.code: lc for lc in locales}
62+
63+
# Update project locales
64+
ProjectLocale.objects.filter(project=project).exclude(
65+
locale__in=locales
66+
).delete()
67+
for locale in locales:
68+
# The implicit pre_save and post_save signals sent here are required
69+
# to maintain django-guardian permissions.
70+
ProjectLocale.objects.get_or_create(project=project, locale=locale)
71+
ProjectLocale.objects.filter(project=project, readonly=True).update(
72+
readonly=False
73+
)
74+
else:
75+
locale_map = {lc.code: lc for lc in project.locales.order_by("code")}
5676
paths.locales = list(locale_map.keys())
77+
5778
added_entities_count, changed_paths, removed_paths = sync_resources_from_repo(
5879
project, locale_map, checkouts.source, paths, now
5980
)

pontoon/sync/core/entities.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ def update_translated_resources(
375375
_, locales = paths.target(resource.path)
376376
for lc in locales:
377377
locale = locale_map.get(lc, None)
378-
if is_translated_resource(paths, resource, locale):
378+
if is_translated_resource(project, paths, resource, locale):
379379
assert locale is not None
380380
key = (resource.pk, locale.pk)
381381
if key in prev_tr_keys:
@@ -403,16 +403,21 @@ def update_translated_resources(
403403

404404

405405
def is_translated_resource(
406+
project: Project,
406407
paths: L10nConfigPaths | L10nDiscoverPaths,
407408
resource: Resource,
408409
locale: Locale | None,
409410
) -> bool:
410411
if locale is None:
411412
return False
412413

413-
if resource.format == Resource.Format.GETTEXT:
414-
# For gettext, only create TranslatedResource
415-
# if the resource exists for the locale.
414+
if (
415+
isinstance(paths, L10nDiscoverPaths)
416+
and project.set_locales_from_repo
417+
and project.set_translated_resources_from_repo
418+
):
419+
# With `set_translated_resources_from_repo`,
420+
# only create TranslatedResource if the resource exists for the locale.
416421
target, _ = paths.target(resource.path)
417422
if target is None:
418423
return False

pontoon/sync/core/translations_from_repo.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,15 @@ def sync_translations_from_repo(
5353
"""(removed_resource_count, updated_translation_count)"""
5454
co = checkouts.target
5555
source_paths: set[str] = set(paths.ref_paths) if checkouts.source == co else set()
56-
del_count = delete_removed_gettext_resources(project, co, paths, source_paths)
56+
del_count = (
57+
delete_removed_resources(project, co, paths, source_paths)
58+
if (
59+
isinstance(paths, L10nDiscoverPaths)
60+
and project.set_locales_from_repo
61+
and project.set_translated_resources_from_repo
62+
)
63+
else 0
64+
)
5765

5866
changed_target_paths = [
5967
path
@@ -83,10 +91,10 @@ def write_db_updates(
8391
add_translation_memory_entries(project, new_translations + updated_translations)
8492

8593

86-
def delete_removed_gettext_resources(
94+
def delete_removed_resources(
8795
project: Project,
8896
target: Checkout,
89-
paths: L10nConfigPaths | L10nDiscoverPaths,
97+
paths: L10nDiscoverPaths,
9098
source_paths: set[str],
9199
) -> int:
92100
rm_t = Q()
@@ -95,7 +103,7 @@ def delete_removed_gettext_resources(
95103
removed_target_paths = (
96104
path
97105
for path in (join(target.path, co_path) for co_path in target.removed)
98-
if path not in source_paths and splitext(path)[1] in {".po", ".pot"}
106+
if path not in source_paths
99107
)
100108
for target_path in removed_target_paths:
101109
ref = paths.find_reference(target_path)
@@ -104,7 +112,7 @@ def delete_removed_gettext_resources(
104112
locale_code = get_path_locale(path_vars)
105113
if locale_code is not None:
106114
db_path = relpath(ref_path, paths.ref_root)
107-
if not project.configuration_file and db_path.endswith(".pot"):
115+
if db_path.endswith(".pot"):
108116
db_path = db_path[:-1]
109117
rm_t |= Q(entity__resource__path=db_path, locale__code=locale_code)
110118
rm_tr |= Q(resource__path=db_path, locale__code=locale_code)

pontoon/sync/tests/test_e2e.py

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
ChangedEntityLocale,
1818
Entity,
1919
Locale,
20+
ProjectLocale,
2021
Repository,
2122
TranslatedResource,
2223
Translation,
@@ -242,7 +243,11 @@ def test_add_resources():
242243
assert {
243244
(tr.resource.path, tr.locale.code)
244245
for tr in TranslatedResource.objects.filter(resource__project=project)
245-
} == {("file.ftl", "de-Test"), ("file.xliff", "de-Test")}
246+
} == {
247+
("file.ftl", "de-Test"),
248+
("file.po", "de-Test"),
249+
("file.xliff", "de-Test"),
250+
}
246251

247252
# Add an XLIFF translation
248253
TranslationFactory.create(
@@ -848,3 +853,82 @@ def test_add_project_locale():
848853
tr.locale.code: tr.total_strings
849854
for tr in TranslatedResource.objects.filter(resource__project=project)
850855
} == {"fr-Test": 1, "de-Test": 1}
856+
857+
858+
@pytest.mark.django_db
859+
def test_locales_from_repo():
860+
mock_vcs = MockVersionControl(changed=[])
861+
with mock_setup(mock_vcs) as (repo, _):
862+
LocaleFactory.create(code="fr-Test", name="Test French")
863+
864+
# Database setup
865+
project = ProjectFactory.create(
866+
name="test-repo-locales",
867+
locales=[],
868+
repositories=[repo],
869+
set_locales_from_repo=True,
870+
system_project=False,
871+
)
872+
873+
# Filesystem setup
874+
makedirs(repo.checkout_path)
875+
build_file_tree(
876+
repo.checkout_path,
877+
{
878+
"en-US": {"messages.json": '{ "key": { "message": "Entity" } }'},
879+
"de-Test": {"messages.json": "{}"},
880+
"fr-Test": {"messages.json": "{}"},
881+
},
882+
)
883+
884+
sync_project_task(project.pk)
885+
886+
assert {
887+
pl.locale.code for pl in ProjectLocale.objects.filter(project=project)
888+
} == {"de-Test", "fr-Test"}
889+
assert {
890+
tr.locale.code: tr.total_strings
891+
for tr in TranslatedResource.objects.filter(resource__project=project)
892+
} == {"fr-Test": 1, "de-Test": 1}
893+
894+
895+
@pytest.mark.django_db
896+
def test_locales_from_config():
897+
mock_vcs = MockVersionControl(changed=[])
898+
with mock_setup(mock_vcs) as (repo, _):
899+
LocaleFactory.create(code="fr-Test", name="Test French")
900+
901+
# Database setup
902+
project = ProjectFactory.create(
903+
name="test-config-locales",
904+
configuration_file="l10n.toml",
905+
locales=[],
906+
repositories=[repo],
907+
set_locales_from_repo=True,
908+
system_project=False,
909+
)
910+
911+
# Filesystem setup
912+
makedirs(repo.checkout_path)
913+
build_file_tree(
914+
repo.checkout_path,
915+
{
916+
"foo": {"en": {"messages.json": '{ "key": { "message": "Entity" } }'}},
917+
"l10n.toml": dedent("""\
918+
locales = ["de-Test", "fr-Test"]
919+
[[paths]]
920+
reference = "foo/en/**"
921+
l10n = "foo/{locale}/**"
922+
"""),
923+
},
924+
)
925+
926+
sync_project_task(project.pk)
927+
928+
assert {
929+
pl.locale.code for pl in ProjectLocale.objects.filter(project=project)
930+
} == {"de-Test", "fr-Test"}
931+
assert {
932+
tr.locale.code: tr.total_strings
933+
for tr in TranslatedResource.objects.filter(resource__project=project)
934+
} == {"fr-Test": 1, "de-Test": 1}

pontoon/sync/tests/test_translations_from_repo.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ def test_remove_po_target_resource():
358358
name="test-rm-po",
359359
locales=[locale],
360360
repositories=[repo],
361+
set_locales_from_repo=True,
362+
set_translated_resources_from_repo=True,
361363
visibility="public",
362364
)
363365
res = {}

0 commit comments

Comments
 (0)