I have a program already internationalized with gettext module, however it bugs me for days whether should I centralize the strings (make them variables, so they can be referred by the main program or the tests suite) inside one module or not. If they are not centralized, then every time I change the strings, I must manually copy/paste the strings into the integration tests, violating DRY. But if they are centralized, it sacrifices readability in the main program. Or there is a better way to do this?
IMHO the key to solve your problem is how you design your integration tests, and it has probably nothing to do with localization or internationalization at all. In a non-localized program the same problem can occur.
I guess your tests - at least at some level - take some input data, run the program which produces some textual output which contains some of the localized strings. Then, the output is compared to some expected output.
We have a bunch of such programs and tests here, and the way we deal with them is by not hardcoding the output texts directly into the integration tests. Instead, we pipe the output of each test into a file (for example, into a directory "currentOutput" and a file name which identifies the test in a unique manner), compare the file against a pendant in a directory "expectedOutput". When some of the tests fail, we use our favorite diff/merge tool and compare the different files and manually check what causes the difference. When we are sure the difference is only caused by an intended string change, we simply copy the content from "currentOutput" to "expectedOutput" , so updating the expected data is very smooth and painless.
TLDR; duplicate the strings in the tests, but make the updating of strings within the test suite a semi-automatic process.