It would help if you outlined you intended use of this behavior, as without that it is not clear what is and is not helpful.

### Single function case

You can use the two-argument form of `OptionValue`:

    rule = {"t" :> OptionValue[gg, "t1"]};  (* note RuleDelayed *)
    
    Options[gg] = {"t1" -> "T1", "t2" -> "1"};
    gg[___, OptionsPattern[]] := StringReplace["content", rule]
    
    gg[1]

>     "conT1enT1"

This works just fine with a single function (`gg`), but it is not directly applicable if you intend to use this rule in multiple functions.

### Arbitrary function case

As you apparently understand based on your workaround, the `OptionValue` expression must appear literally on the right-hand-side of a rule or definition with `OptionsPattern`.  Your use of `Evaluate` causes the `OptionValue` expression to appear explicitly for `SetDelayed`.  Any other method that does the same can be used, e.g.:

    With[{rule = rule},
      gg[___, OptionsPattern[]] := StringReplace["content", rule]
    ]

Or:

    (gg[___, OptionsPattern[]] := StringReplace["content", #]) & @ rule

For the arbitrary-function case I see no simpler method than these.