Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,59 @@ public class LeveragingCommand extends Command {
arity = 1,
required = false,
description =
"Matching mode. "
+ "MD5 will perform matching based on the ID, content and comment. "
+ "EXACT match is only using the content.",
"""
Matching mode. \
MD5: match on all of the resource name, source content and comment. \
EXACT: match on the source (!) content. \
NAME: match on the resource name. \
TUIDS: only leverage between tmTextUnitIds specified in explicit mapping.""",
converter = CopyTmConfigModeConverter.class)
CopyTmConfig.Mode mode = CopyTmConfig.Mode.MD5;

@Parameter(
names = {"--preserve-status", "-ps"},
arity = 1,
required = false,
description =
"""
Controls whether to keep the leveraged translation's original status or downgrade \
it to TRANSLATION_NEEDED. \
A match is 'unique' when exactly one candidate text unit matched (no ambiguity). \
A match is 'high-precision' when matched on both name and content (or full MD5). \
PRECISION (default): preserve status only when the match is both unique and \
high-precision. Matches on name-only or content-only are always downgraded, \
even if unique. Low risk. \
UNIQUE: preserve status for any unique match, regardless of its precision. \
Useful when e.g. migrating between naming schemes. Medium risk. \
ALL: always preserve the original status, even for ambiguous matches. High risk - \
this will arbitrarily pick one of several candidates.""",
converter = PreserveStatusModeConverter.class)
CopyTmConfig.PreserveStatusMode preserveStatusMode = CopyTmConfig.PreserveStatusMode.PRECISION;

@Parameter(
names = {"--overwrite-mode", "-om"},
arity = 1,
required = false,
description =
"""
Controls when existing translations may be overwritten based on status comparison. \
ALL (default): overwrite regardless of status. \
HIGHER_STATUS: overwrite only when the candidate status is strictly higher \
(e.g. TRANSLATION_NEEDED -> REVIEW_NEEDED, REVIEW_NEEDED -> APPROVED). \
HIGHER_OR_EQUAL_STATUS: same as HIGHER_STATUS but also overwrite when statuses are equal. \
FOR_TRANSLATION: leverage into locales with no translation or with TRANSLATION_NEEDED status. \
NONE: never overwrite; only leverage into locales that have no translation at all.""",
converter = OverwriteModeConverter.class)
CopyTmConfig.OverwriteMode overwriteMode = CopyTmConfig.OverwriteMode.ALL;

@Parameter(
names = {"--tuids-mapping"},
required = false,
description =
"Text unit mapping (by tmTextUnitId) for TUIDS mode, format: \"1001:2001;1002:2002\" "
+ "(\"source_tm_text_unit_id:target_tm_text_unit_id;...\" with source_tm_text_unit_id unique. "
+ "Use multiple calls to copy the same source to multiple targets)",
"""
Text unit mapping (by tmTextUnitId) for TUIDS mode. \
Format: "1001:2001;1002:2002" ("source_tm_text_unit_id:target_tm_text_unit_id;..."). \
Note: source_tm_text_unit_id should be unique. Use multiple calls to copy the same source to multiple targets.""",
converter = TmTextUnitMappingConverter.class)
Map<Long, Long> sourceToTargetTmTextUnitMapping;

Expand Down Expand Up @@ -144,6 +184,8 @@ void copyTmBetweenRepositories() throws CommandException {
copyTmConfig.setTargetRepositoryId(targetRepository.getId());
copyTmConfig.setNameRegex(nameRegexParam);
copyTmConfig.setTargetBranchName(targetBranchNameParam);
copyTmConfig.setPreserveStatusMode(preserveStatusMode);
copyTmConfig.setOverwriteMode(overwriteMode);

if (mode != null) {
copyTmConfig.setMode(mode);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.box.l10n.mojito.cli.command;

import com.box.l10n.mojito.rest.entity.CopyTmConfig;

public class OverwriteModeConverter extends EnumConverter<CopyTmConfig.OverwriteMode> {

@Override
protected Class<CopyTmConfig.OverwriteMode> getGenericClass() {
return CopyTmConfig.OverwriteMode.class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.box.l10n.mojito.cli.command;

import com.box.l10n.mojito.rest.entity.CopyTmConfig;

public class PreserveStatusModeConverter extends EnumConverter<CopyTmConfig.PreserveStatusMode> {

@Override
protected Class<CopyTmConfig.PreserveStatusMode> getGenericClass() {
return CopyTmConfig.PreserveStatusMode.class;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public void copyTMModeMD5() throws Exception {

Repository sourceRepository = createTestRepoUsingRepoService();
Repository targetRepository =
repositoryService.createRepository(testIdWatcher.getEntityName("target-repoisotry"));
repositoryService.createRepository(testIdWatcher.getEntityName("target-repository"));

repositoryService.addRepositoryLocale(targetRepository, "fr-FR");
repositoryService.addRepositoryLocale(targetRepository, "fr-CA", "fr-FR", false);
Expand Down Expand Up @@ -108,9 +108,9 @@ public void copyTMModeMD5() throws Exception {
public void copyTMModeExact() throws Exception {

Repository sourceRepository =
repositoryService.createRepository(testIdWatcher.getEntityName("source-repoisotry"));
repositoryService.createRepository(testIdWatcher.getEntityName("source-repository"));
Repository targetRepository =
repositoryService.createRepository(testIdWatcher.getEntityName("target-repoisotry"));
repositoryService.createRepository(testIdWatcher.getEntityName("target-repository"));

repositoryService.addRepositoryLocale(sourceRepository, "fr-FR");
repositoryService.addRepositoryLocale(sourceRepository, "fr-CA", "fr-FR", false);
Expand Down Expand Up @@ -197,13 +197,171 @@ public void copyTMModeExact() throws Exception {
Assert.assertFalse(itTargetTranslations.hasNext());
}

@Test
public void copyTMModeName() throws Exception {

Repository sourceRepository =
repositoryService.createRepository(testIdWatcher.getEntityName("source-repository"));
Repository targetRepository =
repositoryService.createRepository(testIdWatcher.getEntityName("target-repository"));

repositoryService.addRepositoryLocale(sourceRepository, "fr-FR");
repositoryService.addRepositoryLocale(sourceRepository, "fr-CA", "fr-FR", false);
repositoryService.addRepositoryLocale(sourceRepository, "ja-JP");

repositoryService.addRepositoryLocale(targetRepository, "fr-FR");
repositoryService.addRepositoryLocale(targetRepository, "fr-CA", "fr-FR", false);
repositoryService.addRepositoryLocale(targetRepository, "ja-JP");

getL10nJCommander()
.run(
"push",
"-r",
sourceRepository.getName(),
"-s",
getInputResourcesTestDir("source").getAbsolutePath());

getL10nJCommander()
.run(
"push",
"-r",
targetRepository.getName(),
"-s",
getInputResourcesTestDir("source3").getAbsolutePath());

Asset asset =
assetClient.getAssetByPathAndRepositoryId("source-xliff.xliff", sourceRepository.getId());
importTranslations(asset.getId(), "source-xliff_", "fr-FR");
importTranslations(asset.getId(), "source-xliff_", "ja-JP");

List<TMTextUnitVariant> initialTargetTranslations =
tmTextUnitVariantRepository.findByTmTextUnitTmRepositoriesOrderByContent(targetRepository);

assertEquals("There must be only english for now", 5, initialTargetTranslations.size());

getL10nJCommander()
.run(
"leveraging-copy-tm",
"-s",
sourceRepository.getName(),
"-t",
targetRepository.getName(),
"-m",
"NAME");

List<String> targetTranslations =
tmTextUnitVariantRepository
.findByTmTextUnitTmRepositoriesOrderByContent(targetRepository)
.stream()
.sorted(
Comparator.comparing(
TMTextUnitVariant::getLocale, Comparator.comparing(Locale::getBcp47Tag))
.thenComparing(TMTextUnitVariant::getContent))
.map(TMTextUnitVariant::getContent)
.peek(t -> logger.info("target translation: {}", t))
.collect(Collectors.toList());

List<String> expectedTargetTranslations =
Arrays.asList(
"1 hour",
"1 month",
"100 char limit:",
"15 min",
"one day",
"1 heure",
"1 jour",
"1 mois",
"15 min",
"Description de 100 caract\u00e8res\u00a0:",
"100\u6587\u5b57\u306e\u8aac\u660e\uff1a",
"15\u5206",
"1\u304b\u6708",
"1\u65e5",
"1\u6642\u9593");

Assert.assertEquals(
"All target text units should have translations leveraged by name",
expectedTargetTranslations,
targetTranslations);
}

@Test
public void copyTMModeNamePreserveStatus() throws Exception {

Repository sourceRepository =
repositoryService.createRepository(testIdWatcher.getEntityName("source-repository"));
Repository targetRepository =
repositoryService.createRepository(testIdWatcher.getEntityName("target-repository"));

repositoryService.addRepositoryLocale(sourceRepository, "fr-FR");
repositoryService.addRepositoryLocale(sourceRepository, "fr-CA", "fr-FR", false);
repositoryService.addRepositoryLocale(sourceRepository, "ja-JP");

repositoryService.addRepositoryLocale(targetRepository, "fr-FR");
repositoryService.addRepositoryLocale(targetRepository, "fr-CA", "fr-FR", false);
repositoryService.addRepositoryLocale(targetRepository, "ja-JP");

getL10nJCommander()
.run(
"push",
"-r",
sourceRepository.getName(),
"-s",
getInputResourcesTestDir("source").getAbsolutePath());

getL10nJCommander()
.run(
"push",
"-r",
targetRepository.getName(),
"-s",
getInputResourcesTestDir("source3").getAbsolutePath());

Asset asset =
assetClient.getAssetByPathAndRepositoryId("source-xliff.xliff", sourceRepository.getId());
importTranslations(asset.getId(), "source-xliff_", "fr-FR");
importTranslations(asset.getId(), "source-xliff_", "ja-JP");

getL10nJCommander()
.run(
"leveraging-copy-tm",
"-s",
sourceRepository.getName(),
"-t",
targetRepository.getName(),
"-m",
"NAME",
"--preserve-status",
"ALL");

List<TMTextUnitVariant> targetTranslations =
tmTextUnitVariantRepository
.findByTmTextUnitTmRepositoriesOrderByContent(targetRepository)
.stream()
.filter(v -> !v.getLocale().getBcp47Tag().equals("en"))
.sorted(
Comparator.comparing(
TMTextUnitVariant::getLocale, Comparator.comparing(Locale::getBcp47Tag))
.thenComparing(TMTextUnitVariant::getContent))
.collect(Collectors.toList());

Assert.assertFalse("Should have copied translations", targetTranslations.isEmpty());

for (TMTextUnitVariant variant : targetTranslations) {
Assert.assertEquals(
"Status should be preserved as APPROVED with ALL",
TMTextUnitVariant.Status.APPROVED,
variant.getStatus());
}
}

@Test
public void copyTMModeTUIDs() throws Exception {

Repository sourceRepository =
repositoryService.createRepository(testIdWatcher.getEntityName("source-repoisotry"));
repositoryService.createRepository(testIdWatcher.getEntityName("source-repository"));
Repository targetRepository =
repositoryService.createRepository(testIdWatcher.getEntityName("target-repoisotry"));
repositoryService.createRepository(testIdWatcher.getEntityName("target-repository"));

repositoryService.addRepositoryLocale(sourceRepository, "fr-FR");
repositoryService.addRepositoryLocale(sourceRepository, "fr-CA", "fr-FR", false);
Expand Down Expand Up @@ -298,9 +456,9 @@ public void copyTMModeTUIDs() throws Exception {
public void copyTMModeTargetBranchName() throws Exception {

Repository sourceRepository =
repositoryService.createRepository(testIdWatcher.getEntityName("source-repoisotry"));
repositoryService.createRepository(testIdWatcher.getEntityName("source-repository"));
Repository targetRepository =
repositoryService.createRepository(testIdWatcher.getEntityName("target-repoisotry"));
repositoryService.createRepository(testIdWatcher.getEntityName("target-repository"));

repositoryService.addRepositoryLocale(sourceRepository, "fr-FR");
repositoryService.addRepositoryLocale(sourceRepository, "fr-CA", "fr-FR", false);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:okp="okapi-framework:xliff-extensions" version="1.2">
<file original="" source-language="en" datatype="x-undefined">
<body>
<trans-unit id="" resname="100_character_description_" datatype="php">
<source>100 character description:</source>
</trans-unit>
<trans-unit id="" resname="15_min_duration" datatype="x-javascript+php">
<source>15 min</source>
<note>File lock dialog duration</note>
</trans-unit>
<trans-unit id="" resname="duplicate_source" datatype="x-javascript+php">
<source>15 min</source>
</trans-unit>
<trans-unit id="" resname="1_day_duration" datatype="x-javascript+php">
<source>1 day</source>
<note>File lock dialog duration</note>
</trans-unit>
<trans-unit id="" resname="1_hour_duration" datatype="x-javascript+php">
<source>1 hour</source>
<note>File lock dialog duration</note>
</trans-unit>
<trans-unit id="" resname="1_month_duration" datatype="x-javascript+php">
<source>1 month</source>
<note>File lock dialog duration</note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:okp="okapi-framework:xliff-extensions" version="1.2">
<file original="" source-language="en" datatype="x-undefined">
<body>
<trans-unit id="" resname="100_character_description_" datatype="php">
<source>100 char limit:</source>
</trans-unit>
<trans-unit id="" resname="15_min_duration" datatype="x-javascript+php">
<source>15 min</source>
<note>File lock dialog duration</note>
</trans-unit>
<trans-unit id="" resname="1_day_duration" datatype="x-javascript+php">
<source>one day</source>
<note>File lock dialog duration</note>
</trans-unit>
<trans-unit id="" resname="1_hour_duration" datatype="x-javascript+php">
<source>1 hour</source>
<note>File lock dialog duration</note>
</trans-unit>
<trans-unit id="" resname="1_month_duration" datatype="x-javascript+php">
<source>1 month</source>
<note>File lock dialog duration</note>
</trans-unit>
</body>
</file>
</xliff>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:okp="okapi-framework:xliff-extensions" version="1.2">
<file original="" source-language="en" target-language="fr-FR" datatype="x-undefined">
<body>
<trans-unit id="" resname="100_character_description_" datatype="php">
<source>100 character description:</source>
<target>Description de 100 caractères :</target>
</trans-unit>
<trans-unit id="" resname="15_min_duration" datatype="x-javascript+php">
<source>15 min</source>
<target>15 min</target>
<note>File lock dialog duration</note>
</trans-unit>
<trans-unit id="" resname="duplicate_source" datatype="x-javascript+php">
<source>15 min</source>
<target>15 min duplicated</target>
</trans-unit>
<trans-unit id="" resname="1_day_duration" datatype="x-javascript+php">
<source>1 day</source>
<target>1 jour</target>
<note>File lock dialog duration</note>
</trans-unit>
<trans-unit id="" resname="1_hour_duration" datatype="x-javascript+php">
<source>1 hour</source>
<target>1 heure</target>
<note>File lock dialog duration</note>
</trans-unit>
<trans-unit id="" resname="1_month_duration" datatype="x-javascript+php">
<source>1 month</source>
<target>1 mois</target>
<note>File lock dialog duration</note>
</trans-unit>
</body>
</file>
</xliff>
Loading
Loading