{"id":22831546,"url":"https://github.com/phrase/phraseappxcode","last_synced_at":"2025-10-07T00:02:53.443Z","repository":{"id":29395467,"uuid":"32930694","full_name":"phrase/PhraseAppXcode","owner":"phrase","description":"Plugin to sync localization files easily between Phrase and Xcode","archived":false,"fork":false,"pushed_at":"2019-10-02T12:04:02.000Z","size":98,"stargazers_count":14,"open_issues_count":0,"forks_count":2,"subscribers_count":21,"default_branch":"master","last_synced_at":"2025-05-06T19:06:54.617Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://phrase.com","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phrase.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-26T14:02:24.000Z","updated_at":"2021-06-03T18:43:52.000Z","dependencies_parsed_at":"2022-09-06T17:01:08.043Z","dependency_job_id":null,"html_url":"https://github.com/phrase/PhraseAppXcode","commit_stats":null,"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/phrase/PhraseAppXcode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phrase%2FPhraseAppXcode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phrase%2FPhraseAppXcode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phrase%2FPhraseAppXcode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phrase%2FPhraseAppXcode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phrase","download_url":"https://codeload.github.com/phrase/PhraseAppXcode/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phrase%2FPhraseAppXcode/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278698811,"owners_count":26030399,"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","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-12-12T20:26:32.791Z","updated_at":"2025-10-07T00:02:53.399Z","avatar_url":"https://github.com/phrase.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Phrase for Xcode\n\nThis plugin integrates [Phrase](https://phrase.com/) into Xcode. Current version is `1.1.0`.\n\n**Please note that plugins are not supported by Xcode 8.** The last version to be supported is **7.3**. For those that have already upgraded, please use the **[Phrase CLI tool](https://phrase.com/en/cli)** ([Github](https://github.com/phrase/phraseapp-client)). \n\nThere is a chance to rollout a native Mac App or use Xcode Source Editor Extensions in the future. Keep in mind that this is not scheduled or planned yet.\n\n## Installation\n\nDownload the latest release from\n[Github](https://github.com/phrase/PhraseAppXcode/releases/latest) and unzip\nthe file in the `~/Library/Application Support/Developer/Shared/Xcode/Plug-ins`\ndirectory (assuming the plugin archive was downloaded to `~/Downloads`):\n\n```\ncd ~/Library/Application\\ Support/Developer/Shared/Xcode/Plug-ins\nunzip ~/Downloads/PhraseAppXcodePlugin.xcplugin.zip\n```\n\nAfter starting Xcode it will ask, whether \"the unsafe bundle should be loaded\".\nIt should be. Afterwards you are ready to go. To uninstall, just delete the\nplugin from the mentioned path (and restart Xcode).\n\nThis is tested on OS X 10.10 with Xcode 7.3.\n\n\n## Configuration\n\nOpen the plugin window first. Click the **Window \u003e Phrase** menu entry. The\nPhrase plugin window will open. From here you can configure the plugin,\nselect a project, and push and pull locales.\n\nThe plugin relies on the [Phrase CLI tool](https://phrase.com/en/cli) to\nbe installed. Point the file selector in the top of the plugin window to this\nlocation:\n\n![Phrase CLI tool configuration](example_config.png)\n\nThe plugin is going to guess the location, but might fail to do so. If so,\nmanually select the CLI tool path. The file must be executable and the file\npointed to must have the \"phraseapp\" prefix.\n\n\n## Usage\n\nThe plugin is actually pretty simple. For each workspace opened in Xcode the\ncombobox in the plugin window will have an entry. The **Push** and **Pull**\nbuttons are active if the CLI tool path was properly configured and the project\nhas a Phrase configuration file (named `.phraseapp.yml`) in its root\ndirectory.\n\nOn **Push** and **Pull** the respective output will be sent to the text area in\nthe lower part of the window.\n\n![Phrase CLI tool configuration](example_push.png)\n\nIn this example the workspace \"MyTest1\" was selected and pushed. For a\ndescription of the output generated see the following section.\n\n\n## Workflow\n\nThe internationalization and localization workflow Apple proposes has made the\nfollowing steps and assumptions:\n\n* It is assumed that all development is done in one language, English by\n  default (this can be changed and is described below in the \"Change Default\n  Locale\" subsection). All strings should be in this language and are considered\n  final. It is called the \"development language\" in the following.\n* There is a tool in **Editor \u003e Export For Localization** that will extract all\n  strings from user-interface elements (located in storyboards for example) and\n  usages of the `NSLocalizedString` macro in code. These strings are collected\n  in a `XLIFF` file that can be used to hand over to translators.\n* There is of course a function to reimport the translators' results\n  into the source code under the **Editor \u003e Import Localizations...** menu\n  item. This will read a `XLIFF` file and extract the configured translations.\n  The resulting translations are kept in `strings` files for each source of\n  strings (storyboards or code that is) and each target locale.\n\nInto this workflow Phrase is integrated. Please note, if you don't want to\nfollow this workflow for whatever reason, the plugin is still usable for you.\nXcode's export and import actions are only triggered if the Phrase\nconfiguration contains an `XLIFF` source (and respective targets). So it can be\nused with any other configuration too!\n\nThe following subsections describe two variants of the XLIFF based workflow.\n\n\n### The Simple Workflow\n\nThe simpler workflow comes with the following limitation: The development\nlanguage is only handled in Xcode, i.e. it is not possible for product managers\n(or whoever might want to) to change these text fragments directly in\nPhrase.\n\nThere will be a solution for this limitation, but it requires a slightly more\ncomplicated setup, so let's start simple.\n\n\n#### Configuration\n\nAfter creating a project make sure you configure **Base Internationalization**\nand all required target languages in your project's **Info** configuration\nview.\n\nAdditionally some files must be generated for the automatic import to work\nproperly. Use the following command and afterwards add the generated files to\nthe project within Xcode (clicking the **Add files to \"[project name]\"...***\npoint of the projects context menu).\n\n\tfor locale in \u003clocales\u003e; do\n\t\techo '/* No Localized Strings */' \u003e \u003cproject_name\u003e/$locale.lproj/Localizable.strings\n\t\techo '/* No Localized Strings */' \u003e \u003cproject_name\u003e/$locale.lproj/InfoPlist.strings\n\tdone\n\nNext we'll need to configure the Phrase tools to support export and import\nof the strings to be translated. The following example will assume the Xcode\nexport and import will use the `i18n` directory to place and find the `xliff`\nfiles. The development language is assumed to be English. Make sure you replace\nthe placeholders (in square brackets) for `access_token`, `project_id` and\n`locale_id` with the respective values of your setup. Put this template into\nthe `.phraseapp.yml` file into your project's root directory.\n\n\tphraseapp:\n\t  access_token: [access_token]\n\t  project_id: [project_id]\n\t  push:\n\t    sources:\n\t    - file: i18n/en.xliff\n\t      params:\n\t        locale_id: [locale_id]\n\t        file_format: xlf\n\t        update_translations: true\n\t  pull:\n\t    targets:\n\t    - file: i18n/\u003clocale_name\u003e.xliff\n\t      params:\n\t        file_format: xlf\n\t    - file: [project_name]/\u003clocale_name\u003e.lproj/Localizable.stringsdict\n\t      params:\n\t        file_format: stringsdict\n\nWith this configuration in place the project is ready to use with Phrase, as\ndescribed in the next subsection.\n\n\n#### Usage\n\nIf you're using Phrase's Xcode plugin the export and import is as easy as\nopening the Phrase window from **Window \u003e Phrase**, selecting the\nrespective project from the dropdown, and using the **Push** or **Pull**\nbutton.\n\nIf you want to use the command line for a more manual approach or integration\ninto some build tool use the following steps for export:\n\n\txcodebuild -exportLocalizations -localizationPath i18n\n\tphraseapp push\n\nAnd for import of the given locales (`de`, `es`, and `fr` in this example):\n\n\tphraseapp pull\n\tfor locale in de es fr; do xcodebuild -importLocalizations -localizationPath i18n/$locale.xliff; done\n\nKeep in mind that changing strings in the default locale in Phrase will\nresult in disaster. It must be convention to never change these values in\nPhrase, but only in the code itself. The effect would be that Xcode doesn't\nimport those strings any more (mismatch between source locale string in\nthe `XLIFF` file and the string in the code).\n\nIf you want to pluralize a key, this is possible by setting the according flag\non the key and providing the basic translations. The resulting translated\npluralizations are pulled into `.stringsdict` files. For more complicated\npluralization features it might be necessary to also push the source locale's\n`.stringsdict` file.\n\n\n### The Manage All Keys In Phrase Workflow\n\nThis is a more advanced workflow that will allow to change strings from the\ndevelopment language in Phrase.\n\nThis requires some additional steps as we must make sure the development\nlanguage doesn't block the layering of different locales, like keys should be\ntaken from the most specific locale, like en-US first, then general en and last\nfrom the development locale. We'll introduce an artificial locale for this.\n\n\n#### Change Default Locale\n\nClose the project in Xcode and open up a terminal window. Go to the projects\nroot folder and edit the following two files:\n\n* `\u003cproject_name\u003e/Info.plist`: set the `CFBundleDevelopmentRegion` variable to\n  `i-default`.\n* `\u003cproject_name\u003e.xcodeproj/project.pbxproj`: change the `en` item of the\n  `knownRegions` list to `i-default`. Change the `developmentRegion` value from\n  `en` to `i-default`. (see http://eschatologist.net/blog/?p=224 ).\n\nOpen the project again.\n\n\n#### Configuration\n\nThis configuration will use the new base locale. Everything else is unchanged.\nThe base locale in Phrase should be named (aka `locale_name`) \"i-default\"\nand have the locale-code \"en\". Having multiple locales with the same code is\nperfectly fine.\n\n\tphraseapp:\n\t  access_token: [access_token]\n\t  project_id: [project_id]\n\t  push:\n\t    sources:\n\t    - file: i18n/i-default.xliff\n\t      params:\n\t        locale_id: [locale_id]\n\t        file_format: xlf\n\t        update_translations: true\n\t  pull:\n\t    targets:\n\t    - file: i18n/\u003clocale_name\u003e.xliff\n\t      params:\n\t        file_format: xlf\n\t    - file: [project_name]/\u003clocale_name\u003e.lproj/Localizable.stringsdict\n\t      params:\n\t        file_format: stringsdict\n\n\n#### Usage\n\nAgain everything within the \"i-default\" locale should be considered fixed in\nPhrase and never be changed. After pushing the keys to Phrase the product\nmanager needs to approve the translations, by moving them to the \"standard\"\nlocale (like \"en\" in the given example). Translators must base their work on\nthis verified locale. Everything else is analogous to the simple workflow.\n\n\n### Output Of Actions\n\nThere are some errors that might appear when importing XLIFF files pulled from\nPhrase. Let's see an example:\n\n\t# Pull locales from Phrase\n\tDownloaded de to i18n/de.xliff\n\t\n\t# Import from XLIFF: i18n/de.xliff\n\tMyTest1/Base.lproj/Main.storyboard: Incoming development string \"Master2\" does not match \"Master\" (Key: \"RMx-3f-FxP.title\")\n\tglobal: File not found in the project\n\nThis happened when importing the German translations from the `de.xliff` file.\nTwo messages appear:\n\n* The `Incoming development string \"Master2\" does not match \"Master\"` message\n  is serious. This is an indicator for a translation in the development locale\n  being changed in Phrase. To fix go to Phrase and revert changes to the\n  named key.\n* The `File not found in the project` message isn't that serious and happens\n  when keys are added from something different than the development language\n  (like adding keys in Phrase or push different files from other projects).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphrase%2Fphraseappxcode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphrase%2Fphraseappxcode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphrase%2Fphraseappxcode/lists"}