Xcstrings + GitHub Integration setup

Hi,

We have an iOS project where a while ago we use .xcstrings files to localize our app.

Due to limitations of Transifex (2023-2024) time, we were doing manual translation syncing via the tx-cli.

Now after all this time, I’m trying to see if it’s possible to have the GitHub Integration using.xcstrings files. The documentation of the GitHub Integration seems to hint that is possible

In GitHub: Installation and configuration | Transifex Help Center

by warning the line

I tried to set up again the integration with a configuration like

filters:
  - filter_type: file
    file_format: XCSTRINGS
    source_language: en
    source_file: MyApp/Resources/Localization/Localizable.xcstrings

But I get the following error.

Then, is it possible today to use the GitHub Integration with Transifex and .xcstrings?
What I’m missing?

Hello @fespinoza,

I am Antonis from the Transifex Customer Success team. I hope you’re well!

Quick answer: Yes, you can use the GitHub integration, but there’s a known limitation we’re working to resolve with .xcstrings files.

About the warning:

The translation_files_expression parameter is required since it tells the integration where to return your translation files. The warning about an “unsupported parameter” you shared in your screenshot refers to mode, which controls what appears in your translation files for incomplete translations.

Unlike most file formats (which use separate files per language), .xcstrings files contain all languages in a single file. This creates a unique situation:

When a sync is triggered (say, Spanish reaches 100% translated), your file is returned with the completed Spanish translations. But what about your other languages that aren’t complete yet?

Currently, untranslated content appears in the source language. For example, if you have:

  • Spanish (es): 100% translated
  • German (de): 0% translated
  • French (fr): 20% translated

The file will include the translations for Spanish and the 20% of the French strings, but German and the 80% incomplete French strings will appear in your source language rather than being left empty.

For file formats that use separate files per language, each language being completed doesn’t affect the rest. Due to this different approach the mode parameter also need to be handled differently on our end, but once implemented you’ll be able to specify how you want to receive your content, wether it is translated or not.

We’re actively working to add mode parameter support for .xcstrings files to give you more control over this behavior. In the meantime, you’re welcome to test the integration to see if it fits your workflow, but just be aware of this current limitation.

Let me know if you have any questions!

I understand, but in this case I don’t know what the value of translation_files_expression should be, since it complains about the <lang> parameter

For example I was trying this

filters:
  - filter_type: file
    file_format: XCSTRINGS
    source_language: en
    source_file: MyApp/Resources/Localization/Localizable.xcstrings
    translation_files_expression: MyApp/Resources/Localization/Localizable.xcstrings

I’m unsure which value should be used for a .xcstrings file

P.S. I only mentioned the mode since it was a reference to .xcstrings within the GitHub integration, meaning that it indicated me there was support for it on the integration, it wasn’t that I wanted to use that parameter

Hello @fespinoza,

The translation_files_expression value should be set to your desired path for outputting finalized translations.

The <lang> property can be used to automatically create language folders or append the language code to the file name, for example:

  • MyApp/Resources/Localization/<lang>/myfile.extension
  • MyApp/Resources/Localization/myfile_<lang>.extension

As mentioned in my previous response, .xcstrings files don’t follow the same conventions as the rest of our supported file types, so it doesn’t make sense to use <lang> since it’s meant to automate the organization of file formats that generate a different file for each target language.

The config you shared looks good (though you might need to enclose your translation_files_expression in single quotes), and it should work if you want to sync and translate a single source file. You can use the dir and dynamic filter types if you want to sync an entire directory or multiple directories.

You can also quickly test your configuration in the GitHub integration wizard by clicking “Test configuration”. It will quickly point out any issues with the configuration and will display which files are going to be synced.

Please let me know if this helps.

I understand everything you mention, but I still doesn’t help

as you said, .xcstrings files contain all the translations for all languages in a single location.

then the <lang> parameter of translation_files_expression doesn’t really apply here,

there is no such thing as:
```

 translation_files_expression: MyApp/Resources/Localization/<lang>_Localizable.xcstrings

it’s a single Localizable.xcstrings file.

What I need help is to concretely set up a xcstrings file with the integration (a concrete example), which it’s supposed to be possible, yet not clear to me due to the <lang> requirement on translation_files_expression

You’re absolutely right, since .xcstrings files contain all language translations in a single file, the <lang> placeholder in the translation_files_expression doesn’t really apply in this case.

At the moment, repository integrations in Transifex don’t yet fully support .xcstrings files in the way you describe, that is, pointing both the source and target languages to the same file in the repo. The lang flag was originally designed for file formats that create separate files per language, which is why it doesn’t currently align with how .xcstrings files are structured.

We’re truly sorry for the inconvenience this causes. There’s already an open improvement request for extending repository integration support for .xcstrings, and I’ve linked your case to it so we can notify you as soon as there’s progress or a workaround available.

Thank you again for your patience and for sharing such clear feedback, it’s very helpful for our team as we improve this functionality.

Best,

Hi,

what do you mean with

At the moment, repository integrations in Transifex don’t yet fully support .xcstrings files in the way you describe

From what I understand, the GitHub integration simply doesn’t support xcstrings (you can give me an example of a working setup if I am wrong)

As I said, we had to use this manual approach since Sept 2024 (after a lot of back and forth with transifex support), even though apple released XCSTRINGS with Xcode 15 on June 2023.

I saw the previous question about this very topic more than a year ago :backhand_index_pointing_down:

Basically the speed of development has been incredibly slow and the documentation GitHub: Installation and configuration | Transifex Help Center in this case gave me false hopes that you actually supported the GitHub integration right now.

Hello @fespinoza,

I understand the confusion, and let me clarify exactly where things stand.

The GitHub integration works with .xcstrings files for upload and parsing, but it doesn’t support the exact workflow you’re looking for. The <lang> parameter requirement in translation_files_expression is by design for file formats that generate separate files per language. If used with .xcstrings, it would generate one file per language, but all of them would contain content from all target languages, which isn’t what you’re looking for or what the format was designed for.

Here’s the core issue: Transifex’s platform architecture, including repository integrations, the translation_files_expression logic, and how we handle file syncing, was built around the industry-standard pattern of separate files per language. .xcstrings uses a fundamentally different approach: one file containing all languages. This architectural difference is why you’re running into these limitations, and it’s not something a quick configuration change can resolve.

By “doesn’t fully support,” I mean: we can parse and work with the file format itself, but our platform’s sync architecture isn’t designed for single-file-contains-all-languages formats. That’s the gap you’re experiencing.

I completely understand your frustration. You’ve been managing a workaround since September 2024, and .xcstrings has been around since June 2023. Reworking platform architecture to accommodate a format that works fundamentally differently takes significant engineering time and resources. It’s not just about adding support for a new file format in this case, since it requires rethinking how multiple parts of the system handle source files, translations, syncing, and updates. The single-file-contains-all-languages model represents a different paradigm from the separate-files-per-language pattern (like .strings, .json, .xml, .xliff) that most localization platforms and workflows have been built around for years.

This is on our radar as a priority, and your detailed input here directly contributes to how we approach the solution. We genuinely appreciate your patience as we work through the technical challenges involved.

Your manual workflow remains the most reliable path forward, though I know it’s not ideal. You’ll be notified when there are any updates on our progress.

If you’re open to a different approach, our iOS Native SDK is a more integrated solution and can push source content via CLI without dealing with files. However, it’s designed for over-the-air (OTA) translations where your app fetches translations at runtime, rather than bundling them at build time. This requires integrating our SDK into your app and adopting a different localization strategy. It’s not a replacement for the file-based GitHub sync workflow you’re looking for, but it could be worth exploring if dynamic translation updates would fit your use case, and the file-based approach simply has too many limitations for your needs.

Your feedback is noted, and your case is linked to the improvement request we’ve shared with our Product team. If there’s a specific piece of feedback you haven’t shared yet, or if you have questions about any of the options I mentioned, let me know, and I’d be happy to discuss it with our team.