Summary
Previously, recalculating the translation string templates caused a misalignment: after any changed string, subsequent entries were re-numbered and old values received new “stable” IDs.
You can reproduce by checking out #33224 and running:
0cmake --preset dev-mode -DWITH_USDT=OFF -DENABLE_IPC=OFF && cmake --build build_dev_mode --target translate
This will change many translation IDs:
0git diff | egrep '^[+-].+trans-unit id='
1- <trans-unit id="_msg1040">
2- <trans-unit id="_msg1041">
3+ <trans-unit id="_msg1040">
4...
5- <trans-unit id="_msg1160">
6+ <trans-unit id="_msg1159">
7+ <trans-unit id="_msg1160">
Details
As mentioned in #33224 (comment), changing a translatable string’s content moves it within the sorted messages and gives it a new sequential ID. Messages between its old and new positions were then misidentified, making translation work on Transifex and similar platforms harder.
Fix
The translate CMake target now runs a small Python script that restores IDs from the previous translation file. It maps each message by (group resname + source text) to old and new IDs, and performs a single-pass search-and-replace on the newly generated XLF to restore the original IDs. Unchanged strings keep their IDs; genuinely new strings get the next sequential _msg following the very last id.
Reproducer
This PR has two commits; the first resets the baseline to make testing simpler.
Deleting a translation
0diff --git a/src/init.cpp b/src/init.cpp
1--- a/src/init.cpp (revision e94ee7674c5b023268fe33df8839b6879a81afab)
2+++ b/src/init.cpp (date 1756457795674)
3@@ -904,7 +904,6 @@
4 }
5
6 if (args.IsArgSet("-datacarriersize") || args.IsArgSet("-datacarrier")) {
7- InitWarning(_("Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated. They will be removed in a future version."));
8 }
9
10 // We no longer limit the orphanage based on number of transactions but keep the option to warn users who still have it in their config.
correctly deletes only that one
0 git diff | egrep '^[+-].+trans-unit id='
1- <trans-unit id="_msg1039">
Adding a new one:
0diff --git a/src/init.cpp b/src/init.cpp
1--- a/src/init.cpp (revision e94ee7674c5b023268fe33df8839b6879a81afab)
2+++ b/src/init.cpp (date 1756457688152)
3@@ -905,6 +905,7 @@
4
5 if (args.IsArgSet("-datacarriersize") || args.IsArgSet("-datacarrier")) {
6 InitWarning(_("Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated. They will be removed in a future version."));
7+ InitWarning(_("Options2 '-datacarrier' or '-datacarriersize' are set but are marked as deprecated. They will be removed in a future version."));
8 }
9
10 // We no longer limit the orphanage based on number of transactions but keep the option to warn users who still have it in their config.
keep all other ones intact
0git diff | egrep '^[+-].+trans-unit id='
1+ <trans-unit id="_msg1239">
Modifying a single one
0diff --git a/src/init.cpp b/src/init.cpp
1--- a/src/init.cpp (revision e94ee7674c5b023268fe33df8839b6879a81afab)
2+++ b/src/init.cpp (date 1756457951822)
3@@ -904,7 +904,7 @@
4 }
5
6 if (args.IsArgSet("-datacarriersize") || args.IsArgSet("-datacarrier")) {
7- InitWarning(_("Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated. They will be removed in a future version."));
8+ InitWarning(_("Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated and are expected to be removed in a future version."));
9 }
10
11 // We no longer limit the orphanage based on number of transactions but keep the option to warn users who still have it in their config.
is marked as a clean delete/add
0 git diff | egrep '^[+-].+trans-unit id='
1- <trans-unit id="_msg1039">
2+ <trans-unit id="_msg1239">
And as a bonus, only changing the case of a translation
0diff --git a/src/init.cpp b/src/init.cpp
1--- a/src/init.cpp (revision e94ee7674c5b023268fe33df8839b6879a81afab)
2+++ b/src/init.cpp (date 1756457080223)
3@@ -904,7 +904,7 @@
4 }
5
6 if (args.IsArgSet("-datacarriersize") || args.IsArgSet("-datacarrier")) {
7- InitWarning(_("Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated. They will be removed in a future version."));
8+ InitWarning(_("OPTIONS '-DATACARRIER' OR '-DATACARRIERSIZE' ARE SET BUT ARE MARKED AS DEPRECATED. THEY WILL BE REMOVED IN A FUTURE VERSION."));
9 }
10
11 // We no longer limit the orphanage based on number of transactions but keep the option to warn users who still have it in their config.
results in keeping the message id
0git diff | egrep '^[+-].+trans-unit id='
1- <trans-unit id="_msg1039">
2+ <trans-unit id="_msg1039">