{"id":19585487,"url":"https://github.com/applanga/applanga-cli","last_synced_at":"2025-04-27T11:33:39.630Z","repository":{"id":40633445,"uuid":"137918973","full_name":"applanga/applanga-cli","owner":"applanga","description":"Applanga Localization Command Line Interface","archived":false,"fork":false,"pushed_at":"2025-03-27T10:16:17.000Z","size":140,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-04T23:51:10.883Z","etag":null,"topics":["android","android-app","android-locale","android-localization","android-xml","app-localization","applanga","applanga-cli","cli","command-line","command-line-tool","homebrew","ios","ios-app","ios-stringsdict","iosapp","language","localization","stringsdict","translation"],"latest_commit_sha":null,"homepage":"https://www.applanga.com/docs-integration/cli","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/applanga.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-06-19T16:42:11.000Z","updated_at":"2025-03-27T10:16:19.000Z","dependencies_parsed_at":"2023-12-07T14:26:04.961Z","dependency_job_id":"350449b3-fc13-49e2-afa6-674299949054","html_url":"https://github.com/applanga/applanga-cli","commit_stats":null,"previous_names":[],"tags_count":51,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/applanga%2Fapplanga-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/applanga%2Fapplanga-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/applanga%2Fapplanga-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/applanga%2Fapplanga-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/applanga","download_url":"https://codeload.github.com/applanga/applanga-cli/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251129746,"owners_count":21540709,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-app","android-locale","android-localization","android-xml","app-localization","applanga","applanga-cli","cli","command-line","command-line-tool","homebrew","ios","ios-app","ios-stringsdict","iosapp","language","localization","stringsdict","translation"],"created_at":"2024-11-11T07:54:21.081Z","updated_at":"2025-04-27T11:33:39.570Z","avatar_url":"https://github.com/applanga.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Applanga Localization Command Line Interface (CLI)\n\n***\n*Version:* 1.0.106\n\n*Website:* \u003chttps://www.applanga.com\u003e\n\n*Changelog:* \u003chttps://www.applanga.com/changelog/cli\u003e\n***\n\n## Table of Contents\n\n  1. [Installation](#installation)\n  2. [Initialization](#initialize-project)\n  3. [Usage](#push-and-pull-translation-files)\n  4. [Configuration](#configuration)\n  5. [Configuration Examples](#configuration-examples)\n\t- [Android Examples](#android-configuration-examples)\n\t- [iOS Examples](#ios-configuration-examples)\n\n## Installation\n\n##### Manual\n\n1. [Download and extract](https://github.com/applanga/applanga-cli/releases/latest) the latest client binary for your platform.\n\t\n2. Store the binary at a location where it can be found and executed by the system or adjust your [PATH](https://en.wikipedia.org/wiki/PATH_(variable)) accordingly.\n\n3. You should now be able to execute it on the command-line like:\n\n```sh\n\tapplanga --help\n```\nor\n\n```sh\n\tapplanga.exe --help\n```\n\n##### Homebrew\n\nOn OSX we provide a homebrew tap to make the installation easier and up-to-date:\n\n```sh\n\tbrew tap applanga/cli\n\tbrew install applanga\n```\n\nTo update to the latest version call:\n\n```sh\n\tbrew upgrade applanga\n```\n\n###### Installing on Mac pre-MacOS 11\nPlease note that in order to run the latest Applanga CLI version on macOS you need to have at least macOS 11 (Big Sur) installed. If you have an older macOS you can use [Applanga CLI 1.0.51](https://github.com/applanga/applanga-cli/releases/tag/1.0.51) but be aware that not all features and fixes are available in that version. Please check the [Applanga CLI 1.0.51 README](https://github.com/applanga/applanga-cli/blob/1.0.51/README.md) and [CHANGELOG](https://www.applanga.com/changelog/cli) for more details.\n\nIn order to install this via brew you need to run:\n\t\n```sh\n\tbrew tap applanga/cli\n\tbrew install applanga@1.0.51\n```\n\n##### Github\n\nTo automate localization through Github please check the [Applanga Github Workflow Documentation](https://www.applanga.com/docs/integration-documentation/github-action).\n\n## Initialize Project\n\nTo initialize a new project the API token is needed. It can be found under **Project Settings** on the [Applanga Dashboard](https://dashboard.applanga.com).\n\nThe project can then be initialized by running the following in the project directory:\n\n```sh\n\tapplanga init\n```\n\nIn the dialog that appears, project data like the API token and the type of project will be requested.\nIt will then save all the data to a configuration file in the current directory with the name `.applanga.json`\n\n\n## Push and Pull Translation Files\n\nThe translations can simply be pushed to and pulled from Applanga with the corresponding commands.\n\nTo pull translations from Applanga into local files:\n\n```sh\n\tapplanga pull\n```\n\n###### *NOTE: The CLI communicates with the [Applanga API](https://www.applanga.com/docs-integration/api) through our CDN to make sure the data is always reachable, but that also means changes (including pushes) are only available to pull after a 10 minute delay even if changes are already visible on the [Dashboard](https://dashboard.applanga.com)!*\n\nTo push existing local translations to Applanga:\n\n```sh\n\tapplanga push\n```\n\nThe default config usually just pushes the source language and pulls all target languages. For some initial setup cases, you may need to push target values as well. For this case, there is the **pushtarget** command. It behaves the same as the push command, but this command pushes all files that are set as targets in the config. If you want to override already existing translations on the backend, you’ll need to combine this with the `--force` command. Exception for this is the `xliff` file format. For this format `--force` is disabled. If you want to override existing values/translations please provide the `onlyIfTextEmpty` option and set it to `false`\n\n```sh\n\tapplanga pushtarget\n```\n\nFor cases where you need to pull the source language changes from the dashboard into your source file you can use the **pullsource** command. It behaves the same as pull, but only pulls source files. Please be aware that local changes that are not yet pushed to Applanga will be overwritten.\n\n```sh\n\tapplanga pullsource\n```\n\n\n\n### Push Options\n\n - **--force**\n \nBy default values are only pushed if they do not yet exist on the dashboard. This prevents accidental overwrite of translations. If you want to push locally changed files you can do so with the `--force` option. But be cautious with this option as it might overwrite values set by a translator on the dashboard; be sure to pull before you push. \n\nFor the xliff file format, the only way to override existing values or translations is by providing the onlyIfTextEmpty option and setting it to false. It's important to note that the --force option should not be used in conjunction with the xliff file format and the onlyIfTextEmpty option set to false, as the --force option is disregarded in this context.\n\n```sh\n\tapplanga push --force\n```\n\n - **--draft**\n \nYou can push values into the draft field to review them on the dashboard before you release/publish them using the `--draft` option. This is optional and only recommended if you plan to incorporate review of content on the Applanga dashboard. \n\n```sh\n\tapplanga push --draft\n```\n\n\n\n## Configuration\n\nBy default, the configuration file (`.applanga.json`) is read from the current folder. However, it is also possible to set an additional path to check for with the environment variable `APPLANGA_CONFIG`. If set, this location will also be checked.\nAdditionally, the configuration file can be located in the home folder set in the environment variable `HOME` under Linux/Mac and `HomePath` under Windows.  \nIf you do not want to have your `access_token` token stored in the config and committed to your scm you can remove it from the config and instead provide it as environment variable called `APPLANGA_ACCESS_TOKEN`.\n\n\n### Project Structure\n\nThe most basic configuration file generated after `applanga init` will look similar to this e.g. for a **.po** file:\n\n```json\n{\n\t\"app\": {\n\t\t\"access_token\": \"5b1f..!..2ab\",\n\t\t\"base_language\": \"en\", \n\t\t\"pull\": {\n\t\t\t\"target\": [\n\t\t\t\t{\n\t\t\t\t\t\"exclude_languages\": [\"en\"],\n\t\t\t\t\t\"file_format\": \"gettext_po\", \n\t\t\t\t\t\"path\": \"./\u003clanguage\u003e.po\",\n\t\t\t\t\t\"tag\": \"app:language.po\"\n\t\t\t\t}\n\t\t\t]\n\t\t}, \n\t\t\"push\": {\n\t\t\t\"source\": [\n\t\t\t\t{\n\t\t\t\t\t\"language\": \"en\",\n\t\t\t\t\t\"file_format\": \"gettext_po\", \n\t\t\t\t\t\"path\": \"./en.po\",\n\t\t\t\t\t\"tag\": \"app:language.po\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t}\n}\n```\nIf you are using multiple files, file formats on platforms that have different folders for their base languages, or more complex folder structures like [iOS](#ios-configuration-examples) or [Android](#android-configuration-examples) you'll need to modify the config as shown in the [configuration examples](#configuration-examples).\n\n### Target/Source Properties\n\n\nThere are a few mandatory and several optional properties that you can use to customize the cli to match your specific project setup.\n\n#### Mandatory Properties:\n\n- **\"file_format\"**\n\n\tThe file format specifies the format of the file that you want to push or pull which typically depends on the platform that you are localizing.\n\n\tFor a detailed format description check out the [Applanga File Format Documentation.](https://www.applanga.com/docs/formats)\n\t\n\tCurrently, the following formats are supported:\n\n\t - android_xml : [Android XML ](https://www.applanga.com/docs/formats/android_xml) (.xml)\n\t - angular_translate_json : [Angular Translate](https://www.applanga.com/docs/formats/angular_translate_json) (.json)\n\t - chrome_i18n_json : [Chrome i18n](https://www.applanga.com/docs/formats/chrome_i18n_json) (.json)\n\t - csv : [CSV](https://www.applanga.com/docs/formats/csv) (.csv)\n\t - ember_i18n_json_module : [Ember i18n JSON Module](https://www.applanga.com/docs/formats/ember_i18n_json_module) (.js)\n\t - ini : [INI](https://www.applanga.com/docs/formats/ini) (.ini)\n\t - gettext_po : [Gettext PO File](https://www.applanga.com/docs/formats/gettext_po) (.po)\n\t - gettext_pot : [Gettext POT File](https://www.applanga.com/docs/formats/gettext_pot) (.pot)\n\t - go_i18n_json : [go-i18n](https://www.applanga.com/docs/formats/go_i18n_json) (.json)\n\t - i18next_json : [i18next](https://www.applanga.com/docs/formats/i18next_json) (.json)\n\t - ios_strings : [iOS strings](https://www.applanga.com/docs/formats/ios_strings) (.strings)\n\t - ios_stringsdict : [iOS stringsdict](https://www.applanga.com/docs/formats/ios_stringsdict) (.stringsdict)\n\t - java_properties : [JAVA properties](https://www.applanga.com/docs/formats/java_properties)(.properties)\n\t - mozilla_i18n_json : [Mozilla i18n](https://www.applanga.com/docs/formats/mozilla_i18n_json) (.json)\n\t - mozilla_properties : [Mozilla properties](https://www.applanga.com/docs/formats/mozilla_properties) (.properties)\n\t - nested_json : [Nested JSON](https://www.applanga.com/docs/formats/nested_json)(.json)\n\t - node_2_json : [i18n-node-2](https://www.applanga.com/docs/formats/node_2_json) (.json)\n\t - react_nested_json : [React Nested JSON](https://www.applanga.com/docs/formats/react_nested_json) (.json)\n\t - react_simple_json : [React Simple JSON](https://www.applanga.com/docs/formats/react_simple_json) (.json)\n\t - ruby_on_rails_yaml : [Ruby on Rails YAML](https://www.applanga.com/docs/formats/ruby_on_rails_yaml) (.yaml)\n\t - symfony_yaml : [Symfony YAML](https://www.applanga.com/docs/formats/symfony_yaml) (.yaml)\n\t - symfony2_yaml : [Symfony 2 YAML](https://www.applanga.com/docs/formats/symfony2_yaml) (.yaml)\n\t - arb : [Flutter](https://www.applanga.com/docs/formats/arb) (.arb)\n\t - laravel_php : [PHP Laravel](https://www.applanga.com/docs/formats/laravel_php) (.php)\n\t - qt_ts : [Qt Linguist](https://www.applanga.com/docs/formats/ts) (.ts)\n\t - microsoft_resw: [Microsoft Resw](https://www.applanga.com/docs/formats/microsoft_resx) (.resw)\n\t - microsoft_resx: [Microsoft Resx](https://www.applanga.com/docs/formats/microsoft_resx) (.resx)\n\t - toml : [Toml](https://www.applanga.com/docs/formats/toml) (.toml)\n\t - tsv : [TSV](https://www.applanga.com/docs/formats/tsv) (.tsv)\n\t - xliff: [Xliff](https://www.applanga.com/docs/formats/xliff) (.xliff)\n\t - xls: [Microsoft Excel](https://www.applanga.com/docs/formats/xls) (.xls or .xlsx)\n\n\t***Example:*** `\"file_format\": \"android_xml\"`\n\n- **\"path\"**\n\n\tIn the \"source\" block it defines the files to upload and in \"target\" block the files to download.\nIt is possible to set the variable `\u003clanguage\u003e` in the path. In the \"source\" block it will look for local files which have the language code set at its location (like: \"en\") and then upload the file for the found language. In the \"target\" block it will replace it with the name of the languages which exist on Applanga and create the files accordingly.\n\n\t***Example:*** `\"path\": \"./app/src/main/res/values-\u003clanguage\u003e/strings.xml\"`\n\n#### Optional Properties:\n\n- **\"branch_id\"**:\n\t\n\tDefines the branch to use for the configuration. If the branch_id is not set, the \"main\" branch will be used. This will only work for Projects where branching is enabled. You can find the branch id in the **Project Settings** page.\n\n\tTo learn more about branching, please see the [Branching Documentation.](www.applanga.com/docs/advanced-features/branching)\n\n\t***Example:*** `\"branch_id\": \"\u003cbranch_id\u003e\"`\n\n\n- **\"tag\"**\n\n\tThis option is needed if you have multiple local files which is common for [iOS](#ios-app-with-pluralization-stringsdict-and-storyboard-strings) and [Android](#android-app-with-multiple-files-submodule-library). If defined in the \"source\" block, it will set the specified tag to all strings that are uploaded from the given \"path\". In the \"target\" block, it will only download translations which have this tag applied.\n\tThis option also allows you to upload and download only a subset of all available strings to or from certain files. In addition to a single tag, you can also provide an array if you want to pull elements that are tagged differently into one file or if you want to add multiple tags for certain files on push.\n\t\n\t**Warning**: \n\t\n\tIf you’re pushing the same file in multiple languages you need to make sure that all of them contain the same keys or some Tags will be deleted or mixed up.\n\t\n\tAll related plurals must be included in the uploaded file to ensure they share an identical tag. This includes adding all plural forms required by other languages even if the uploaded language does not use those forms. This ensures that all plurals are tagged appropriately and exported across languages.\n\t\n\t***Example (Single Tag):*** `\"tag\": \"main page\"`\n\t\n\t***Example (Tag Array):*** `\"tag\": [\"main page\", \"other page\"]`\n\n- **\"keepTagIds\"** *(push commands only)*\n\n\tThis option is only considered when you provide the 'tag' option. If you wish to retain all entries tagged with the current Tag, even if they are not included in the uploaded file, then set this option to true.\n\n\t***Example:*** `\"keepTagIds\": true`\n\n- **\"language\"**\n\n\tThe language of the file is only needed if there is no placeholder `\u003clanguage\u003e` defined in \"path\" e.g. for your base **\"./values/\"** or **\"./Base.lproj/\"** folder.\n\n\t***Example:*** `\"language\": \"en\"`\n\n- **\"exclude_languages\"**\n\n\tIf you are using the placeholder `\u003clanguage\u003e` to download a file for all languages in the project, this option allows you exclude some languages from being pushed or pulled.\n\n\t***Example:*** `\"exclude_languages\": [\"en\", \"de-AT\"]`\n\n- **\"export_empty\"** *(pull commands only)*\n\n\tThis option pulls translations that are empty on the Applanga dashboard (by default empty translations are skipped on pull.) This property is evaluated in the \"target\" block. (Except in **\"target\"** for the **pullsource** command).\n\tThis setting makes sense if you want the empty strings in your base language, but not in the translations so they can fall back to the base strings. This option is also helpful if you use the cli to pull files that you want to send to translators.\n\n\t***Example:*** `\"export_empty\": true`\n\n- **\"disable_plurals\"**\n\t\n\tThis option is only supported when `file_format` is set to `nested_json`, `react_nested_json`, `ruby_on_rails_yaml`, `symfony_yaml`, `symfony2_yaml`, `ember_i18n_json_module` or `node_2_json`. It can be set to `true` or `false`. When set to `true` it means plural keys (`'zero', 'one', 'two', 'few', 'many', 'other'`) will be handled as regular keys and will not undergo any special transformation. For example, if this option is set to `true` when `applanga push` is executed for a `nested_json` file that contains the following content\n\n\t```json\n\t{\n\t\t\"some\": {\n\t\t\t\"sub\": {\n\t\t\t\t\"other\": \"foo\"\n\t\t\t}\n\t\t}\n\t}\n\t``` \n\n\twhen the operation completes, the resulting string key will be `some.sub.other` instead of `some.sub[other]`. Then for \n\t`applanga pull`, if `disable_plural` is set to `true` then keys like `some.sub[other]` with value as `foo` will become\n\n\t```json\n\t{\n\t\t\"some.sub[other]\": \"foo\"\n\t}\n\t``` \n\n\tinstead of \n\n\t```json\n\t{\n\t\t\"some\": {\n\t\t\t\"sub\": {\n\t\t\t\t\"other\": \"foo\"\n\t\t\t}\n\t\t}\n\t}\n\t```\n\n\t***Example:*** `\"disable_plural\": true`\n\n- **\"ignore_duplicates\"** *(pull commands only)*\n\n\tThis option, if set to `true`, the cli will skip duplicate keys whenever `applanga pull` is executed. For instance if we have keys and values as follows `test = “teststring”`, `test.sub1 = “subteststring1“` and `test.sub2 = “subteststring2“` when we try to pull files then the key `test = “teststring\"` and its value will be excluded from the imported file if this option is set to `true`. But when set to `false` the pull operation will fail and the cli will log an error to console stating which keys conflict.\n\n\t***Example:*** `\"ignore_duplicates\": true`\n\n\n- **\"languageMapping\"**\n\n\tIf you use the `\u003clanguage\u003e` wildcard this option allows you to specify a map from Applanga language codes to different language codes that you use in your local folders or filenames. The example below maps “nb-NO” which is the language code as it's defined on the Applanga dashboard to “no_NO” as defined in a local project.\n\n\t***Example:***\n\t```json\n\t\"languageMap\": {\n\t\t\"nb-NO\": \"no_NO\",\n\t\t\"zh-Hans\": \"zh_CN\"\n\t}\n\t```\n\t\n- **\"includeMetadata\"** *(pull commands only)*\n\n\tThis option is by default set to `true`, if false, metadata information will be excluded from the given target.\n\n\t***Example:*** `\"includeMetadata\": false`\n\t\n- **\"includeInvisibleId\"**  *(pull commands only)*\n\n\tThis option is by default set to `false`. If set to `true` an invisible Id will be added in front of each translation value. The invisible Id consists of zero width invisible unicode characters to prevent issues with the look of your application. This allows Applanga to enable additional features like the live web preview of your application. \n\t\n\t**Warning**:\n\t\n\tThis option should only be used in an application during the development process, not in a production settings!\n\n- **\"convert_placeholder\"** *(pull commands only)*\n\n\tIf you use string formatters or placeholders in your strings as part of your project, you can use this option to convert the placeholders between iOS and Android platforms. If convert_placeholder is set to `true`, the CLI will convert and export your string whenever `applanga pull` is executed. For example, if you have a project in IOS where your string is `\"Hello %@\"` use convert_placeholder key to convert it to the Android format `\"Hello %s\"`.\n\n\t***Example:*** `\"convert_placeholder\": true`\n\n\tConvert placeholder works in conjunction with \"file_format\" key. To generate the file and convert from iOS to Android, you must specify \"android_xml\" and to change from Android to iOS it must be \"ios_strings\" or \"ios_stringsdict\".\n\n\n\t***Example:*** \n\t\n\tiOS to Android: \t`\"file_format\":\"android_xml\"`\n\n\tAndroid to iOS:  `\"file_format\":\"ios_strings\"`\n\n\n\n\t***iOS to Android conversion rules***\n\t- Length format is converted to  \"%d\".\n\n\t- Unsupported conversion types by default are converted to \"%s\".\n\n\t- Float \"%f\", double \"%g\"  and \"%p\" are converted to \"%d\".\n\n\t- All Instances of \"%@\" are converted to \"%s\".\n\t\n\t- Positional Arguments \"%1$@\" are converted to \"%1$s\"\n\n\t- Objective C integer types like \"%i\" and \"%u\" are converted to \"%d\".\n\n\t- If it is the same pattern, it will keep the original.  \n\n\t***Android to iOS conversion rules***\n\n\t- Unsupported conversion types are converted to the default \"%@\" type.\n\n\t- Date/Time conversion types like \"%1$te\" are converted to \"%1$@\"\n\n\t- Positional Arguments \"%1$s\" are converted to \"%1$@\"\n\t\n\t- Relative positional arguments like \"%1$s %\u003cs\" are converted to \"%1$@ %1$@\"\n\n\t- All instances of \"%s\" are converted to \"%@\".\n\n\t- If it is the same pattern, it will keep the original.  \n\n- **\"key_prefix\"**\n\n\tIf you need to import multiple files with similar keys, but different text, this option allows you to add prefixes to the keys on push and remove prefixes on pull.\n\n\t**Note**: \n\n\tThe `key_prefix` text property cannot be longer than 50 characters and can only contain letters, numbers, spaces, underscores, and dashes. \n\n\t***Example:*** `\"key_prefix\": \"added_prefix1-\"`\n\n\n- **\"sort_by_key\"** *(pull commands only)*\n\n\tThe keys in files downloaded on pull or **pullsource** command are sorted alphabetically. This option is by default set to `false`.\n\n\t***Example:*** `\"sort_by_key\": true`\n\n- **\"remove_cr_char\"**\n\n\tIf the value is set to `true` the line endings in uploaded content will follow the Unicode and Mac new line format containing just the line feed character (LF, escape sequence \\n). If present, any carriage return characters (CR, the escape sequence \\r) will be removed. \n\n\tIn download when the option set to `true`, the downloded files will contain only the Unicode/Mac new line character (LF).\n\t\n\t***Example:*** `\"remove_cr_char\": true`\n\n- **\"includeStatus\"** *(pull commands only)*\n\n\tThe option is applicable only to file formats: csv, tsv, xls and xliff. If the value is set to `true`, the downloded files will contain the current statuse and the lastest comment for a particular string. This options by default is set to `false`.\n\t\n\t***Example:*** `\"includeStatus\": true`\n\n- **\"excludeBaseLang\"** *(pull commands only)*\n\n\tThe option is applicable only to file formats: csv, tsv, and xls. If the value is set to `true`, the downloaded files do not containe the base language column. This options by default is set to `false`.\n\t\n\t***Example:*** `\"excludeBaseLang\": true`\n\n- **\"skipNonStringValues\"** *(push commands only)*\n\n\tThe option is applicable only to json file formats. This option by default is set to `false`.\n\n\tIf you are uploading a json file where any key is not a string, you will by default get an error during pushing, since non string content is not allowed.\n\tWith this option set to `true` non string values are ignored during import and no error is returned.\n\n\t***Example:*** `\"skipNonStringValues\": true`\n\n- **\"excludeHeaderRow\"**\n\n\tThe option is applicable only to file formats: csv, tsv, and xls. This options by default is set to `false`.\n\t\n\tIf the value is set to `true` for pull command, the downloaded file does not containe the usual header row that describes what is in which column (e.g. ID, en, description, etc). Instead, the exported content should start in row 1 without the header row. \n\n\tFor pull command, for the `true` value the translation data is read from file from the first raw (there is no header). Otherwise the first row is not included in scope and treated as a header. \n\t\n\t***Example:*** `\"excludeHeaderRow\": true`\n\n- **\"columnDescription\"**  *(push commands only, **mandatory for csv, tsv, and xls**)* \n\n\tThe option is applicable only to file formats: csv, tsv, and xls. For these file formats the option must be provided. or the import will fail. It should contain an object linking columns numbers to the type of data found in them. The columns are numberd from 0 (A -\u003e 0, B -\u003e 1, etc.). The data types are:\n\n\t- entry `KEY`\n\t- exact language code (i.e. `en`) or language placeholder `\u003clanguage\u003e`\n\t- entry `DESCRIPTION`\n\t- string max `LENGTH`\n\t- `METADATA_` keyword followed by the metadata name\n\n\tA minimum the `KEY` and any other column must be specified.\n\n\t***Example:*** \n    ```json\n    \"columnDescription\": {\n        \"KEY\": 0,\n        \"da\": 2,\n        \"DESCRIPTION\": 4,\n        \"LENGTH\": 5,\n        \"METADATA_product name\": 6,\n        \"METADATA_project\": 7\n    }\n    ```\n\n- **sheetName**  *(push commands only)*\n\n\tThe option is applicable only to xls file formats. For multi-sheet Excel files, the data is imported only from one sheet. The option needs to be given for the data to be imported from a specific sheet. Otherwise by defualt the first sheet is imported.\n\n\t***Example:*** `\"sheetName\": \"Latest Sources\"`\n\n\n### Xliff specific options\n\nThe following options will only work if the file_format is set to `xliff` (see [Applanga Xliff Format Documentation](https://applanga.com/docs/formats/xliff) for more information of the xliff format).\n\n\n- **\"xliffStatus\"**  *- deprecated*\n\t\n\tUse **importStatus** option for push commands or **includeStatus** in pull commands\n\n- **\"importStatus\"** *(push commands only)*\n\n\tThe statuses in the xliff file will be imported into Applanga. This options by default is set to  `false`.\n\n\t***Example:*** `\"importStatus\": true`\n\n- **\"createUnknownCustomStates\"** *(push commands only)*\n\t\n\tDefault value is `false`. If set to true custom statuses provided inside the xliff format will be imported into Applanga. The option only works if **importStatus** is also set to `true`.\n\n\t***Example:*** `\"createUnknownCustomStates\": true`\n\n- **\"includeContextUrl\"** *(pull commands only)*\n\n\tThe downloaded xliff file will include contextUrl's for screenshots of the project\n\n\t***Example:*** `\"includeContextUrl\": true`\n\n- **\"importSourceLanguage\"** *(push commands only)*\n\n\tIf the source language varies from the base language of the project you can specify this parameter to have a correct import adjusting for the varying base language. Default is `false`. To upload with a specified source language set this to the language iso name of the language. \n\n\t***Example:*** `\"importSourceLanguage\": \"en\"`\n\n- **\"skipLockedTranslations\"** *(push commands only)*\n\t\n\tDefault is `false`. If set to true all entries inside the uploaded file, that are locked in your application, will be ignored.\n\n\t***Example:*** `\"skipLockedTranslations\": true`\n\n- **\"skipEmptyTranslations\"** *(push commands only)*\n\n\tDefault is `false`. By default entries inside the file that are empty will be ignored in the `xliff` format. If this option is true, empty entries inside the file will be created in the Project. Empty entries will never overwrite entries that already exist within the Project.\n\n\n\t***Example:*** `\"skipEmptyTranslations\": true`\n\n- **\"onlyAsDraft\"** *(push commands only)*\n\t\n\tDefault is `false`. If set to true all values inside the xliff will only be applied to draft values of the application. If your application is a Branching application, this value will be ignored.\n\n\t***Example:*** `\"onlyAsDraft\": true`\n\t\n- **\"onlyIfTextEmpty\"** *(push commands only)*\n\n\tThe pushed file will only overwrite keys that do have an empty text value in Applanga. This overrides the --force option of the commandline. Default is set to `true`.\n\n\t***Example:*** `\"onlyIfTextEmpty\": true`\n\n- **\"importIntoGroup\"** *(push commands only)*\n\n\tDefault is `false`. By default all Keys will be pushed into the groups they currently are assigned to. If true all pushed keys in the file will be but into the 'main' group.\n\n\t***Example:*** `\"importIntoGroup\": true`\n\n# Configuration Examples\n---\n## Android Configuration Examples\n\n### Basic Android App\nThe base Android strings are located in `./app/src/main/res/values/strings.xml`, other languages are located in `./app/src/main/res/values-\u003clanguage\u003e/strings.xml`. The following example shows the usage for a basic Android project with english set as base language.\n\n```json\n{\n\t\"app\": {\n\t\t\"access_token\": \"5b1f..!..2ab\", \n\t\t\"base_language\": \"en\", \n\t\t\"pull\": {\n\t\t\t\"target\": [\n\t\t\t\t{\n\t\t\t\t\t\"exclude_languages\": [\"en\"],\n\t\t\t\t\t\"file_format\": \"android_xml\",\n\t\t\t\t\t\"path\": \"./app/src/main/res/values-\u003clanguage\u003e/strings.xml\",\n\t\t\t\t\t\"tag\": \"app:strings.xml\"\n\t\t\t\t}\n\t\t\t]\n\t\t}, \n\t\t\"push\": {\n\t\t\t\"source\": [\n\t\t\t\t{\n\t\t\t\t\t\"language\": \"en\",\n\t\t\t\t\t\"file_format\": \"android_xml\", \n\t\t\t\t\t\"path\": \"./app/src/main/res/values/strings.xml\",\n\t\t\t\t\t\"tag\": \"app:strings.xml\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t}\n}\n```\n\n### Android App with Multiple Files \u0026 Submodule / Library\n\nApps can have strings in multiple files or in shared libraries. You can specify multiple files in the`.applanga.json` but to be able to upload and download the subset of strings to the correct file you need to use the **\"tag\"** property so that Applanga can properly identify which strings belong to which files.\n\n```json\n{\n\t\"app\": {\n\t\t\"access_token\": \"5b1f..!..2ab\", \n\t\t\"base_language\": \"en\", \n\t\t\"pull\": {\n\t\t\t\"target\": [\n\t\t\t\t{\n\t\t\t\t\t\"exclude_languages\": [\"en\"],\n\t\t\t\t\t\"file_format\": \"android_xml\",\n\t\t\t\t\t\"tag\": \"app:strings.xml\",\n\t\t\t\t\t\"path\": \"./app/src/main/res/values-\u003clanguage\u003e/strings.xml\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"exclude_languages\": [\"en\"],\n\t\t\t\t\t\"file_format\": \"android_xml\",\n\t\t\t\t\t\"tag\": \"module:other.xml\",\n\t\t\t\t\t\"path\": \"./app/src/main/res/values-\u003clanguage\u003e/other.xml\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"exclude_languages\": [\"en\"],\n\t\t\t\t\t\"file_format\": \"android_xml\",\n\t\t\t\t\t\"tag\": \"module:strings.xml\",\n\t\t\t\t\t\"path\": \"./mylibrary/src/main/res/values-\u003clanguage\u003e/strings.xml\"\n\t\t\t\t}\n\t\t\t]\n\t\t}, \n\t\t\"push\": {\n\t\t\t\"source\": [\n\t\t\t\t{\n\t\t\t\t\t\"language\": \"en\",\n\t\t\t\t\t\"file_format\": \"android_xml\",\n\t\t\t\t\t\"tag\": \"app:strings.xml\",\n\t\t\t\t\t\"path\": \"./app/src/main/res/values/strings.xml\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"language\": \"en\",\n\t\t\t\t\t\"file_format\": \"android_xml\",\n\t\t\t\t\t\"tag\": \"app:other.xml\",\n\t\t\t\t\t\"path\": \"./app/src/main/res/values/other.xml\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"language\": \"en\",\n\t\t\t\t\t\"file_format\": \"android_xml\",\n\t\t\t\t\t\"tag\": \"module:strings.xml\", \n\t\t\t\t\t\"path\": \"./mylibrary/src/main/res/values/strings.xml\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t}\n}\n```\n\n## iOS Configuration Examples\n\n### Basic iOS App\nIf Base Localization is enabled, the base iOS strings are located in `./Base.lproj/Localizable.strings`, other languages are located in `./\u003clanguage\u003e.lproj/Localizable.strings`. The following example shows the usage for a basic iOS project with english set as base language.\n\n```json\n{\n\t\"app\": {\n\t\t\"access_token\": \"5b1f..!..2ab\", \n\t\t\"base_language\": \"en\", \n\t\t\"pull\": {\n\t\t\t\"target\": [\n\t\t\t\t{\n\t\t\t\t\t\"exclude_languages\": [\"en\"],\n\t\t\t\t\t\"file_format\": \"ios_strings\",\n\t\t\t\t\t\"path\": \"./\u003clanguage\u003e.lproj/Localizable.strings\",\n\t\t\t\t\t\"tag\": \"app:Localizable.strings\"\n\t\t\t\t}\n\t\t\t]\n\t\t}, \n\t\t\"push\": {\n\t\t\t\"source\": [\n\t\t\t\t{\n\t\t\t\t\t\"language\": \"en\",\n\t\t\t\t\t\"file_format\": \"ios_strings\", \n\t\t\t\t\t\"path\": \"./Base.lproj/Localizable.strings\",\n\t\t\t\t\t\"tag\": \"app:Localizable.strings\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t}\n}\n```\n\n### iOS App with Pluralization .stringsdict and Storyboard .strings\nIf you turn on localization for your storyboards, you will end up with a .strings file for every storyboard in every language and since strings on the Applanga dashboard are merged to one big list you need to use the config **\"tag\"** property to tag the strings for the specific files on push and pull so you can identify them later on.\nTo extract the .strings from your storyboard you can use the following command: \n\n```sh\nibtool MainStoryboard.storyboard --generate-strings-file MainStoryboard.strings\n```\n\nFor Pluralization, apple introduced the [.stringsdict File Format](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html) which you can also conveniently push and pull with the Applanga command line interface. A .stringsdict file always needs an accompanying .strings file so you can use the same **tag** for both.\n\n```json\n{\n\t\"app\": {\n\t\t\"access_token\": \"5b1f..!..2ab\", \n\t\t\"base_language\": \"en\", \n\t\t\"pull\": {\n\t\t\t\"target\": [\n\t\t\t\t{\n\t\t\t\t\t\"exclude_languages\": [\"en\"],\n\t\t\t\t\t\"file_format\": \"ios_strings\",\n\t\t\t\t\t\"tag\": \"app:Localizable.strings\",\n\t\t\t\t\t\"path\": \"./\u003clanguage\u003e.lproj/Localizable.strings\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"exclude_languages\": [\"en\"],\n\t\t\t\t\t\"file_format\": \"ios_stringsdict\",\n\t\t\t\t\t\"tag\": \"app:Localizable.strings\",\n\t\t\t\t\t\"path\": \"./\u003clanguage\u003e.lproj/Localizable.stringsdict\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"exclude_languages\": [\"en\"],\n\t\t\t\t\t\"file_format\": \"ios_strings\",\n\t\t\t\t\t\"tag\": \"storyboard:Localizable.strings\",\n\t\t\t\t\t\"path\": \"./\u003clanguage\u003e.lproj/MainStoryboard.strings\"\n\t\t\t\t}\n\t\t\t]\n\t\t}, \n\t\t\"push\": {\n\t\t\t\"source\": [\n\t\t\t\t{\n\t\t\t\t\t\"language\": \"en\",\n\t\t\t\t\t\"file_format\": \"ios_strings\",\n\t\t\t\t\t\"tag\": \"app:Localizable.strings\",\n\t\t\t\t\t\"export_empty\": true,\n\t\t\t\t\t\"path\": \"./Base.lproj/Localizable.strings\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"language\": \"en\",\n\t\t\t\t\t\"file_format\": \"ios_stringsdict\",\n\t\t\t\t\t\"tag\": \"app:Localizable.strings\",\n\t\t\t\t\t\"path\": \"./Base.lproj/Localizable.stringsdict\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"language\": \"en\",\n\t\t\t\t\t\"file_format\": \"ios_strings\",\n\t\t\t\t\t\"tag\": \"storyboard:Localizable.strings\",\n\t\t\t\t\t\"path\": \"./Base.lproj/MainStoryboard.strings\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t}\n}\n```\n\n## Update Applanga Settings File\n\nTo update the Applanga Settingsfile within a project, simply execute the following command:\n\n```sh\n\tapplanga updateSettingsfiles\n```\n\nThe above command will recursively check and update any Applanga Settingsfile if there are new versions found.\n\n### Php Laravel App with language mapping\nThe following example shows the usage for a basic Laravel project with english set as base language. Note that Laravel uses a different pattern for [short keys](https://laravel.com/docs/8.x/localization#using-short-keys) than Applanga. In order to circumvent this issue, a custom language mapping is set via the **languageMap** key.\n\n\n```json\n{\n\t\"app\": {\n\t\t\"access_token\": \"5b1f..!..2ab\",\n\t\t\"base_language\": \"en\",\n\t\t\"pull\": {\n\t\t\t\"target\": [\n\t\t\t\t{\n\t\t\t\t\t\"exclude_languages\": [\"en\"],\n\t\t\t\t\t\"file_format\": \"laravel_php\",\n\t\t\t\t\t\"path\": \"./\u003clanguage\u003e.php\",\n\t\t\t\t\t\"tag\": \"app:language.php\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"push\": {\n\t\t\t\"source\": [\n\t\t\t\t{\n\t\t\t\t\t\"language\": \"en\",\n\t\t\t\t\t\"file_format\": \"laravel_php\",\n\t\t\t\t\t\"path\": \"./en.php\",\n\t\t\t\t\t\"tag\": \"app:language.php\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t},\n\t\"languageMap\": {\n\t\t\"nb-NO\": \"no_NO\",\n\t\t\"zh-Hans\": \"zh_CN\"\n\t}\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapplanga%2Fapplanga-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapplanga%2Fapplanga-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapplanga%2Fapplanga-cli/lists"}