Skip to content

Commit

Permalink
feat: multilingual option (#725)
Browse files Browse the repository at this point in the history
  • Loading branch information
katerina20 committed Feb 22, 2024
1 parent 3f79c48 commit 31e2053
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 38 deletions.
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
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 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 (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

0 comments on commit 31e2053

Please sign in to comment.