Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

feat: multilingual option #725

Merged
merged 4 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
43 changes: 13 additions & 30 deletions src/main/java/com/crowdin/cli/properties/FileBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,7 @@
import java.util.Map;

import static com.crowdin.cli.BaseCli.RESOURCE_BUNDLE;
import static com.crowdin.cli.properties.PropertiesBuilder.CONTENT_SEGMENTATION;
import static com.crowdin.cli.properties.PropertiesBuilder.CUSTOM_SEGMENTATION;
import static com.crowdin.cli.properties.PropertiesBuilder.DEST;
import static com.crowdin.cli.properties.PropertiesBuilder.ESCAPE_QUOTES;
import static com.crowdin.cli.properties.PropertiesBuilder.ESCAPE_SPECIAL_CHARACTERS;
import static com.crowdin.cli.properties.PropertiesBuilder.EXPORT_QUOTES;
import static com.crowdin.cli.properties.PropertiesBuilder.EXCLUDED_TARGET_LANGUAGES;
import static com.crowdin.cli.properties.PropertiesBuilder.EXPORT_APPROVED_ONLY;
import static com.crowdin.cli.properties.PropertiesBuilder.FIRST_LINE_CONTAINS_HEADER;
import static com.crowdin.cli.properties.PropertiesBuilder.IGNORE;
import static com.crowdin.cli.properties.PropertiesBuilder.LABELS;
import static com.crowdin.cli.properties.PropertiesBuilder.LANGUAGES_MAPPING;
import static com.crowdin.cli.properties.PropertiesBuilder.MULTILINGUAL_SPREADSHEET;
import static com.crowdin.cli.properties.PropertiesBuilder.SCHEME;
import static com.crowdin.cli.properties.PropertiesBuilder.SKIP_UNTRANSLATED_FILES;
import static com.crowdin.cli.properties.PropertiesBuilder.SKIP_UNTRANSLATED_STRINGS;
import static com.crowdin.cli.properties.PropertiesBuilder.EXPORT_STRINGS_THAT_PASSED_WORKFLOW;
import static com.crowdin.cli.properties.PropertiesBuilder.SOURCE;
import static com.crowdin.cli.properties.PropertiesBuilder.TRANSLATABLE_ELEMENTS;
import static com.crowdin.cli.properties.PropertiesBuilder.TRANSLATE_ATTRIBUTES;
import static com.crowdin.cli.properties.PropertiesBuilder.TRANSLATE_CONTENT;
import static com.crowdin.cli.properties.PropertiesBuilder.TRANSLATION;
import static com.crowdin.cli.properties.PropertiesBuilder.TRANSLATION_REPLACE;
import static com.crowdin.cli.properties.PropertiesBuilder.TYPE;
import static com.crowdin.cli.properties.PropertiesBuilder.UPDATE_OPTION;
import static com.crowdin.cli.properties.PropertiesBuilder.IMPORT_TRANSLATIONS;
import static com.crowdin.cli.properties.PropertiesBuilder.checkForDoubleAsterisks;
import static com.crowdin.cli.properties.PropertiesBuilder.hasRelativePaths;
import static com.crowdin.cli.properties.PropertiesBuilder.*;

@Data
public class FileBean {
Expand All @@ -48,6 +21,7 @@ public class FileBean {
private String source;
private String translation;
private List<String> ignore;
private Boolean multilingual;
private String dest;
private String type;
private String updateOption;
Expand Down Expand Up @@ -98,6 +72,7 @@ public FileBean buildFromMap(Map<String, Object> map) {
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setTranslateAttributes, map, TRANSLATE_ATTRIBUTES);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setTranslateContent, map, TRANSLATE_CONTENT);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setContentSegmentation, map, CONTENT_SEGMENTATION);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setMultilingual, map, MULTILINGUAL);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setMultilingualSpreadsheet, map, MULTILINGUAL_SPREADSHEET);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setSkipTranslatedOnly, map, SKIP_UNTRANSLATED_STRINGS);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setSkipUntranslatedFiles, map, SKIP_UNTRANSLATED_FILES);
Expand All @@ -120,7 +95,9 @@ public void populateWithDefaultValues(FileBean bean) {
//Translation
if (bean.getTranslation() != null) {
bean.setTranslation(Utils.normalizePath(bean.getTranslation()));
if (!PlaceholderUtil.containsLangPlaceholders(bean.getTranslation()) && bean.getScheme() != null) {
if (!PlaceholderUtil.containsLangPlaceholders(bean.getTranslation())
&& (bean.getScheme() != null
|| (bean.getMultilingual() != null && bean.getMultilingual()))) {
bean.setTranslation(Utils.noSepAtStart(bean.getTranslation()));
} else {
bean.setTranslation(Utils.sepAtStart(bean.getTranslation()));
Expand All @@ -135,6 +112,10 @@ public void populateWithDefaultValues(FileBean bean) {
}
bean.setIgnore(ignores);
}
//Multilingual
if (bean.getMultilingual() == null) {
bean.setMultilingual(Boolean.FALSE);
}
//dest
if (StringUtils.isNotEmpty(bean.getDest())) {
bean.setDest(bean.getDest().replaceAll("[/\\\\]+", Utils.PATH_SEPARATOR_REGEX));
Expand Down Expand Up @@ -179,7 +160,9 @@ public List<String> checkProperties(FileBean bean) {
errors.add(RESOURCE_BUNDLE.getString("error.config.double_asterisk"));
}

if (!PlaceholderUtil.containsLangPlaceholders(bean.getTranslation()) && bean.getScheme() == null) {
if (!PlaceholderUtil.containsLangPlaceholders(bean.getTranslation())
&& bean.getScheme() == null
&& (bean.getMultilingual() == null || !bean.getMultilingual())) {
errors.add(RESOURCE_BUNDLE.getString("error.config.translation_has_no_language_placeholders"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public abstract class PropertiesBuilder<T extends Properties, P extends Params>

public static final String IGNORE = "ignore";

public static final String MULTILINGUAL = "multilingual";

public static final String DEST = "dest";

public static final String TYPE = "type";
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/messages/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ params.source=Path to the source files
params.translation=Path to the translation files
params.dest=Specify file name in Crowdin
params.preserve-hierarchy=Choose whether to save the directory hierarchy in the Crowdin project
params.multilingual=Specify whether file format is multilingual
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
params.multilingual=Specify whether file format is multilingual

params.skipUntranslatedStrings=Skip untranslated strings in exported files (does not work with .docx, .html, .md and other document files)
params.skipUntranslatedFiles=Omit downloading not fully translated files
params.keepArchive=Do not remove the downloaded archive with translations after it's extracting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import static com.crowdin.cli.BaseCli.RESOURCE_BUNDLE;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

Expand Down Expand Up @@ -181,6 +182,21 @@ public void testBuildNoConfigFileAndNoToken() {

}

@Test
public void testNoTranslationLangPlaceholder() {
ParamsWithFiles params = new ParamsWithFiles() {{
setIdParam("666");
setTokenParam("123abc456");
setSourceParam(Utils.regexPath(Utils.normalizePath("/Localizable.xcstrings")));
setTranslationParam("Localizable.xcstrings");
}};

Exception actualException = assertThrows(RuntimeException.class, () ->
propertiesBuilders.buildPropertiesWithFiles(out, null, null, params));

assertTrue(actualException.getMessage().contains(RESOURCE_BUNDLE.getString("error.config.translation_has_no_language_placeholders")));
}

@Test
public void testPropertiesWithTarget() {
File configFile = new File("folder/crowdinTest.yml");
Expand Down
12 changes: 4 additions & 8 deletions website/docs/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Visit the [KB article](https://developer.crowdin.com/pseudolocalization/) to rea

**Escape Quotes**

The `escape_qutes` option defines whether a single quote should be escaped by another single quote or backslash in exported translations. You can add the `escape_quotes` per-file option. Acceptable values are `0`, `1`, `2`, `3`. Default is `3`.
The `escape_quotes` option defines whether a single quote should be escaped by another single quote or backslash in exported translations. You can add the `escape_quotes` per-file option. Acceptable values are `0`, `1`, `2`, `3`. Default is `3`.

- `0` - do not escape
- `1` - escape single quote with another single quote
Expand Down Expand Up @@ -168,24 +168,20 @@ Example of the configuration:
]
```

#### Apple Strings Catalog
### Multilingual Support
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### Multilingual Support
### Multilingual Files


Apple Strings Catalog is a natively supported file format by Crowdin, you can use it without any additional installation. Since this file format is **multilingual** (contains multiple languages in one file), you can omit the language placeholders in the `translation` pattern:
For multilingual file formats (contains multiple languages in one file), you can use the `multilingual` option in the configuration. With this option you can omit the language placeholders in the `translation` pattern:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
For multilingual file formats (contains multiple languages in one file), you can use the `multilingual` option in the configuration. With this option you can omit the language placeholders in the `translation` pattern:
For multilingual file formats (containing multiple languages in one file) you can use the `multilingual` option in the configuration. This option allows you to omit the language placeholders in the `translation` pattern:


```yml title="crowdin.yml"
"files": [
{
"source": "Localizable.xcstrings",
"translation": "Localizable.xcstrings",
"scheme": ""
"multilingual": true
}
]
```

:::caution
Note the `scheme` option in the configuration above. It's needed to indicate that this file is multilingual for correct file processing.
:::

### Configure export options for each file group

There is a way to specify export options for each file-group in the `crowdin.yml` configuration file:
Expand Down
Loading