đź’ˇ Did You Know? Updating Source Strings Behavior in Transifex

When working on localization projects, source content is always evolving—strings change, new ones get added, and old ones get removed. But what happens to translations, translation history, and reports when you update content in Transifex? Let’s break it down!

:writing_hand: Example Scenarios

Imagine you’re updating a resource’s source content in your project. Depending on the options you select during upload, the impact on translations will vary:

  • New strings → Added as untranslated.

  • Removed strings → Disappear from the editor but are still stored in your Translation Memory ™.

  • Modified strings → Treated as new or updated, depending on whether the key or text was changed. Translation preservation also depends on whether you are using the Keep Translations option or not.

Note: Transifex retains translations even when the source string or the entire resource is deleted. Translations are only removed from the Translation Memory if they are explicitly deleted from the project’s resource.

:floppy_disk: Save and Keep Translations

One of the most powerful options when updating source strings is Save and Keep Translations. This feature lets you decide whether existing translations should be preserved or removed when a source string is modified.

This option is available across multiple Transifex tools:

Transifex Platform

Transifex platform via updating the source file – when uploading a new version of a source file.

Editor

Editor – for formats that allow editing source content directly in Transifex.

API

There are now two ways to manage this behavior via the API:

When uploading a new source file

Using the POST /resource_strings_async_uploads endpoint:

curl --request POST \

     --url https://rest.api.transifex.com/resource_strings_async_uploads \

     --header 'accept: application/vnd.api+json' \

     --header 'content-type: application/vnd.api+json' \

     --data '

{

  "data": {

    "attributes": {

      "callback_url": "string",

      "content": "{\"hello\": \"transifex\"}",

      "content_encoding": "text",

      "keep_translations": false,

      "replace_edited_strings": false

    },

    "relationships": {

      "resource": {

        "data": {

          "id": "o:organization_slug:p:project_slug:r:resource_slug",

          "type": "resources"

        }

      }

    },

    "type": "resource_strings_async_uploads"

  }

}

When editing an individual source string
Now supported via thePATCH /resource_strings/{resource_string_id} endpoint. You can include the new keep_translations parameter in your request to decide whether to preserve or discard translations for that specific string:

curl --request PATCH \

     --url https://rest.api.transifex.com/resource_strings/resource_string_id \

     --header 'accept: application/vnd.api+json' \

     --header 'content-type: application/vnd.api+json' \

     --data '

{

  "data": {

    "attributes": {

      "strings": {

        "one": "hello",

        "other": "world"

      },

      "keep_translations": false

    },

    "id": "o:organization_slug:p:project_slug:r:resource_slug:s:2e354ef120752c67afa1b6855aa80c52",

    "type": "resource_strings"

  }

}

Note: By default, keep_translations is set to true. Set it to false to remove translations when the source string changes.

CLI

CLI – using the Go CLI with --keep-translations.

tx push -t --keep-translations

When you use this option, Transifex will:

  • Preserve existing translations even if the source text changes.

  • Create TM entries linking the updated source text with the preserved translations.

  • Record both a source edit action and a new translation action in history.

  • Attribute the preserved translations to the user who performed the edit.

Note: A clear way to spot this in history: the timestamps of the source edit and translation action are identical.

:scroll: Impact on Translations’ History

  • Modified text on a string with a key, not using Save and Keep Translations → Original translations are removed from the editor but still visible under the History tab.

  • Modified key or strings without a key-value format → Treated as a completely new string; previous history is not carried over (though translations remain in TM).

  • Modified text on a string with a key using Save and Keep Translations → Both the change and the preserved translation are logged, so reviewers can clearly see what happened.

:bar_chart: Impact on Reports

Updating translations directly affects Activity Reports:

  • Translated Words → Counted when a string is first translated. If Save and Keep Translations is used, preserved translations are counted again as new translations for each target language.

  • Edited Words → Counted when an existing translation is changed.

  • Reviewed Words → Counted when translations are marked as reviewed.

Examples from Reports behavior:

  • If you edit the source string with Save and Keep Translations, the system re-applies translations to all languages where they existed before. This shows up in reports as new translated words credited to the user who performed the edit.

  • If a string is modified without keeping translations, it goes back to an untranslated state, and translators will have to translate it again. These new translations are also counted in reports.

  • Even if resources or languages are later removed from a project, all related translation activity remains in reports.

  • Only if the entire project is deleted will its translation activity disappear from reports.

:writing_hand: Impact on Translation Memory ™

  • Removed strings → Their translations are preserved in the TM for future reuse.

  • Modified strings (text changed, key unchanged) → Previous translations remain in TM even if the string returns to an untranslated state in the editor.

  • Modified strings (key changed) → Treated as completely new strings; old translations remain in TM but are not applied automatically unless a 100% match is found.

  • Save and Keep Translations → Creates TM entries linking the updated source with the preserved translations, so translations are immediately available for future reuse across languages.

:memo: Conclusion

Updating source strings in Transifex changes how translations, history, and reports behave.

  • Save and Keep Translations keeps existing translations, updates the TM, and logs actions in history.

  • Skipping it resets strings in the editor, but old translations remain in TM for future reuse.

  • Reports always reflect activity, even if resources or languages are removed.

Use Save and Keep Translations to make updates smooth and keep your workflow clear.

:sparkles: Curious to see it in action? Give Transifex a try and make managing translations easier for your whole team!

1 Like

Many thanks, @Sandy_DLR, for this really helpful advisory. Still, found some glitches in it:
1st:

This must read instead:
tx push -s --keep-translations
since translations must be kept when source is updated, not when translations themselves are updated; it is without function in -t mode.
(confirmed by consultation with the transifex help desk.)

2nd:
Your source file upload screenshot shows a checkbox “keep existing translations”, which doesn’t exist, even in resources which have a key-value paring, like .strings files. So this method won’t work.

3rd:
The Using the Client advisory states under the header “Pushing files to Transifex”, subheader “Other Flags”, that you can set this on resource level in a config file:

--keep-translations: If present, translations of source strings with the same key whose content changes will not be discarded. This can also be set on a per-resource level in the configuration file.

While it doesn’t mention, how to do that. So my question is: How to do that?

Hi @Robin

Thanks for sharing

  • Regarding the --keep-translations yes it should be related to the push of the source files
  • For your second bullet, the keep existing translations is only available for certain file formats, if you don’t see the option the file format that you are using might not support this feature. The keep translations feature is for key/value based strings but for now strings and xcstrings are not supported.
  • For your third question, you need to combine the flag with the --resources flag and share the organization, project and resource slug where you want to push the new source strings
tx push -s --keep-translations --resources "o:org-slug:p:project-slug:r:resource-slug"

Hope this helps to clarify your doubts.

Best,
Carlos Olvera

Many thanks Carlos Olvera, second bullet taken: It was not clear to me that some file types don’t have this button, even when they are based on a key-value structure. Thanks for clarifying.

Now the third one:

Your example is again tailored for command line, while the document clearly states, that this can as well be set in a config file. But: What config file is meant here? Is it the ~/.transifexrc file in user’s home, or is it the ./.tx/config file in the resource folder? And what syntax is expected to put it into the file instead of using it at command line? Is it sufficient already to omit the double dash in front of --keep-translations? Or must a keep-translations=true be added?

Hi @Robin

Here is an example of a .tx/config with keep_translations enabled:

[main]
host = https://www.transifex.com

[o:my-org:p:my-project:r:my-resource]
file_filter            = translations/<lang>.json
source_file            = translations/en.json
source_lang            = en
type                   = KEYVALUEJSON
keep_translations      = true
replace_edited_strings = false

Then push with:

tx push -s

No need to pass --keep-translations in the command since it’s already set in the config.

As you can see you just need to add the keep_translations = true to the configuration at resource level.

Best,
Carlos Olvera

Hi Carlos @colvera ,

Many thanks for this. It confirms my suspicion that the =true must be added, and the double slash is to be removed when using in the config file. Thanks for pointing me to the proper tx cli config file wherein this can be set.

Now, rethinking your words:

Does that imply, you can’t use that --keep-translations option on the .strings file type even when using the tx cli (via command line or by config file), or does this restriction only apply to the web GUI, where the button is missing? The latter won’t be a big deal, while the first would be a real showstopper. I know, as a workaround I can pull all translations of all project languages first via tx cli, then update the source, and finally push all saved translations back in place. Which would assign all translations falsely to me then. And would cause much unnecessary network traffic at your end, since our resource has ~270MiB including all translated .strings files, twice, for up and download, means moving around half a GiB of data in total, just for processing a source file update of 2.2 MiB, which would be not really economically. So I really hope that the --keep-translations option works in the tx cli for .strings files, and the restriction you mentioned applies only to your web GUI. Can you confirm, please?

Hi @Robin,

Good news, I can confirm that --keep-translations works fully for .strings files via the TX CLI, both as a command-line flag and in the config file. There is no restriction on this file type.

Via command line:

tx push -s --keep-translations

Via config file (permanent, per-resource):

[o:your-org:p:your-project:r:your-resource]
file_filter       = translations/<lang>.strings
source_file       = en.strings
source_lang       = en
type              = STRINGS
keep_translations = true

With this in place, a simple tx push -s will preserve all existing translations for strings whose source text changed — no need for the pull-all/push-all workaround. Only the 2.2 MiB source file is uploaded.

Regarding the web GUI: The “Keep Translations” checkbox limitation you noticed applies specifically to the .xcstrings (Apple String Catalog) format — not to .strings (Apple Strings). For .strings files, the checkbox should still appear in the web UI when updating a resource via Resources → Update → Upload file. If you don’t see it there, please let me know and I’ll investigate further.

So to summarize: the CLI option works perfectly for your use case, and the UI limitation you read about applies to a different file format (.xcstrings), not yours.

Kind regards,
Carlos

Many thanks again Carlos @colvera .

This is really great news, saving lots of heavy network traffic. I’ll switch to using the tx cli exclusively, until you have implemented the missing functionality for .strings in your web GUI.

The checkbox is actually missing. Please see the screenshot I had appended above, which clearly shows the checkbox is not there for apple strings files, even when these have the key/value structure (which is, btw, why we use them for antiX Linux .desktop files translations instead of adding each of the 500+ .desktop files individually one by one as separate resources, which would be unmaintainable for our small team.)

Hello @Robin,

I am Antonis from the Transifex team.

The screenshot you shared doesn’t appear to be fully/correctly loaded. Here’s a screenshot I just took from the update window of an Apple .strings file:

Can you try interacting with the “Update source file” flow and let me know whether you still see the same issue or if your pop-up looks like mine and Carlos’ now?

Hi Antonis @Mylon , Thanks for looking into this! Meanwhile I have rechecked, and since I noticed, that you used an apple strings file in UTF-8 encoding, while my resource is still UTF-16 encoded, since that is what Transifex had provided initially before adding support for UTF-8 apple .strings, I set up in our test bed a .strings resource with utf-8 encoding for testing, to exclude the possibility that the different encoding causes the trouble. Same result: The pupup looks (besides the properly recognized encoding, reading UTF-8 now) exactly like the one I had posted above, in which the complete “Option” section is not present when comparing to your screenshots of this. Apart from that, the upload process works reliable and fluent with this box, no other issues observed. This is reproducible; the box seems to be fully loaded and functional (besides of the missing options field in it), and there is no sign of pending loading activity. As said, now that I know this pitfall, that’s not a big deal, I’ll simply use the tx client instead for updating, where I can set this flag if required. Note to self: Never update a key/value paired resource via Web-GUI, if translations must be kept instead of cleared.

Hi @Robin

This is Carlos, please allow me to chime in. Could you please share the URL of the project where you are trying to upload the strings file and a sample of you file if possible?

Best

Sure. Here you are the link to the community test bed copy of the original resource from our antix-development space: Log in · Transifex (apple strings files UTF-16 encoded). I have deleted the additional UTF-8 test meanwhile again, since there was no difference in the popup box behaviour. The respective original of the .strings file you’ve asked for you’ll find here: antix23-desktop-files.strings · Test · Robin Antix / antiX23 desktop-files · GitLab

Thanks for sharing Robin, after testing the file that you shared on our end and in both cases the options is displayed.


Taking a deeper look the “Keep existing translations when the source string changes” option in the web UI is currently available for paid plans only, and unfortunately is not included in the Open Source plan. We totally understand this can be a limitation, especially for active projects with frequent source updates.

The good news is that you can achieve the same result using the TX CLI with the --keep-translations flag, which is available regardless of plan

Best

Thanks for solving the riddle, Carlos @colvera ! Not a real problem here: Our update paths are fully automated, I’ve added the respective --keep-translation setting to the build scripts or config files, and I’ll instruct our maintainers not to update key-value paired resources manually (as a shortcut for quick manual minor interim string fixes) via the Transifex Web-GUI if translations for changed source strings must be kept, but always use the tx client instead.
I’ll have to admit, the default upload behaviour at Transifex for .strings files was completely unexpected, since the key-value pairing was introduced precisely to allow translations being kept while source strings can be fixed independently. And If I remember correctly, the default behaviour was changed silently at Transifex at some point of time in the past, on earlier updates of .strings files resources the translations for these were kept without any additional setting, and also when uploading via Transifex Web GUI. As you can take from my screenshot, there is no indication of that inverted default behaviour in the file-upload GUI box for the Open-source plan, while in your screenshots from paid plan the existence of the extra tickbox renders it perfectly clear that the default at Transifex is deleting the translations also for key-value based file types, not only for the source-text based translation templates like gettext .pot, for which this behaviour is expected. I consider it to be important to communicate these details in a GUI, at least when no tickbox is present from which you can implicitly derive the default behaviour. Alternatively (or preferably additionally) the default behaviour should be explicitly be stated in your documentation of the file types (or did I overlook that important piece of information therein?)

Hi @Robin

Thank you for taking the time to share this feedback, you raise several valid points.

You’re correct that the default behavior when updating a source file for key-value formats like .strings is to delete translations for any source string that has changed. We understand this can feel counterintuitive, since the whole purpose of a key-value structure is to decouple the key from the source text, allowing translations to persist independently.

Regarding whether this was changed at some point, the current behavior has been consistent in the platform for some time, though it’s possible that earlier versions of the client or platform handled this differently. We don’t have a record of a deliberate silent change, but we acknowledge that the experience may have differed in earlier workflows.

You’re also absolutely right that the upload dialog on the Open Source plan gives no indication of this default behavior. On paid plans, the presence of the “Keep existing translations” checkbox makes the default implicitly clear, but without that checkbox visible, there’s no way to know what will happen to your translations. This is a fair UX criticism, and I’ll pass it along to our product team.

Regarding the documentation, you didn’t overlook it. Our documentation does in some cases specify when a feature is plan-specific, but in this instance that detail was missing. We’ll work on adding explicit mention of this default behavior and its plan availability to our Preventing Translation Edits article, which is where we document this functionality.

Thank you again for the detailed feedback, it genuinely helps us identify where we can improve both the product and the documentation.

Kind regards,
Carlos