I don’t think there’s a tool. It’s not trivial, but it can be done. It will generally be easier to go from a longer to a shorter text, so banana to apple is easier than apple to banana. With txd you can figure out the address of the string, and then you can modify the bits in a hex editor. It’s not one byte per character (see the Z-machine standard). You will also have to fix the file checksum in the header.
If you don’t feel like doing the bit encoding manually, you could of course put the desired string in another Inform project, compile that, and then use txd to find the offset to the string. Then just copy those bytes over the old string (without overwriting what comes after) and fix the checksum.
You can also run it through a decompiler (which produces horribly messy but hopefully technically correct code), change the string, and compile it again. I think Disinform is the best option out there, though I haven’t tried to decompile anything in a long time.
No, that’s why Linus said the problem was nontrivial!
In general, if you decompile and recompile a Z-code/Glulx game while changing code or strings, all the strings and functions will wind up with new addresses. This will break all the game references (like object properties or literals in code) which store string and function addresses.
You can do some analysis to try to figure out which values are string and function addresses, and match them up with their original values. Getting this 90% right is fairly easy. Getting it 100% right is very difficult.
The only safe course is what Linus originally suggested: replace a string with another string of equal length, either by recompiling or by byte-editing the game file. (You can also replace a string with a shorter string, by putting a terminator character in the middle. The details are different between Z-code and Glulx but it’s possible in both.)
If the string is a high string (i.e. it’s one of the strings listed last in a txd listing), you can probably create a longer version of the string which you place last in the story file, and change the reference(s) to the string in the program.
Good point; that’s easier than locating the references to every string. You’d still have to be sure to find and change all the references to your string, though. (There could be more than one; they might occur in global variables, array data, property tables, or function code.)