Structuring translations: How to keep the original files?

PhraseApp stores translatable resources as keys and values instead of keeping the original file structure. This way of dealing with localization data has some huge advantages:

  • File formats are interchangeable: You can upload iOS Localizable strings files into your project and download the same data for in Android XML or Gettext format - or both. There is no lock-in regarding the format!
  • Flexible Grouping: Instead of deciding which keys you want to store in which file you can group your translation keys/resources in a flexible way with our tagging system.

Uploading files: Staying flexible

When you upload a file into a project, we will extract all the new resources from that file and store them in your project. The format of the file you are uploading does not have to be the format you set up your project with in the first place. If you have provided tags for grouping your resources we will tag all your new keys with those tags.

Some formats such as Gettext provide additional valuable meta information such as comments, descriptions or information about pluralization. Whenever possible we will extract those information, too and store them along with your resources. This lets us save all the valuable information you already provide in your localization files for later.

Downloading files: Putting everything back together

At some point you might want to get your (translated) localization files back to review them or deploy them with your new feature or updated application. Once you download the files from PhraseApp we will generate a completely new file for you from scratch in the format you requested. Although this file can look different than the one you uploaded initially, we will always make sure that it is a valid localization file and includes all the relevant meta data you provided in the first place.

While the specific file structure might differ from your original one (e.g. the sorting of the translation keys within the file) we will always give you a valid file to work with and deploy with your application.

Keeping separate files

Although there is almost no format or framework that requires keeping localization information in separate files PhraseApp generally supports file-based workflows. The way to achieve this is by tagging your translations with the correct tags during the initial upload. Later you can then download translations from your project grouped by tags. Again, the tag-based workflow is extremely flexible and lets you reorganize your translation resources without having to re-upload files into your project at all.

We recommend to evaluate if keeping separate files is necessary! We encourage to keep all translations for each locale in one file instead since this makes downloading the resources from PhraseApp faster and more robust in the process. Plus, the PhraseApp Translation Center will keep your translations organized for you so that you don’t have to keep separate files around to find translations in the first place.

You should use unique key names over all files! Some frameworks allow you to use non unique keys over multiple files. For example Symfonoy supports message domains. This domains are detected by the filename. PhraseApp will not scope your keys by filename based domains. You can resolve this by using a unique domain prefix for keys.


In our example a project has several semantically named translation files for the source locale. For example: “accounts.en.yml”, “emails.en.yml” etc. These semantical names are going to be managed through tags in PhraseApp.

Configure your .phraseapp.yml to reflect the organization of the files in your project and link them to tags in the PhraseApp project by including the tag placeholder in the file path. You will need to add a new pull target entry for each tag you want to pull into a seperate file!

  access_token: "3d7e6598d955bfcab104c45c037af1b9459df5692ac4c28a17793"
  project_id: "23485c9c5dfb15d85b32d9c5f3d2hl54"
  file_format: yml
      - file: ./path/to/locales/<tag>.en.yml
          locale_id: "abcd1234cdef1234abcd1234cdef1234"
      # accounts
      - file: ./path/to/locales/accounts.<locale_name>.yml
          tag: "accounts"
      # emails
      - file: ./path/to/locales/emails.<locale_name>.yml
          tag: "emails"