The "traditional" way is to use PROGMEM and use const char * strings.
I don't use the "traditional" way. Instead I use some "helper" classes and macros that WString.h provides.
This does mean, though, due to limitations in C++, that you have to create your string constants in two stages.
First is to define your variables:
const __FlashStringHelper *stringOne;
const __FlashStringHelper *stringTwo;
Then you need to assign the actual strings to those variables within a function. This could be in setup(), but I prefer to define an initializeStrings() function that setup() calls:
void initializeStrings() {
stringOne = F("This is the first string")
stringTwo = F("This is the second string");
}
void setup() {
initializeStrings();
}
You can then pass these objects (they're not really objects, it's all just some magic casting done by the compiler) as parameters to other functions using const __FlashStringHelper * as the type. They can also be passed directly to any of the .print() and .println() functions provided by the Print class (which all Stream objects ultimately inherit).
If you want to use the standard C string library functions _P variants for manipulating the strings (concatenating them to other strings, for instance), you can simply cast them to PGM_P:
char temp[50];
strcpy_P(temp, (PGM_P)stringOne);
strcat_P(temp, (PGM_P)stringTwo);
Another alternative to all that is to use precompiler macros.
#define STRING_ONE F("This is the first string");
#define STRING_TWO F("This is the second string");
Again, you can cast those to PGM_P to use the _P variants of the standard C string library functions, and pass them directly to print functions, since they are replaced verbatim as F("This is the first string"), and F() does a reinterpret-cast to const __FlashStringHelper *.