diff -r 75abdd7f2568 roundup/cgi/templating.py --- a/roundup/cgi/templating.py Thu Jul 30 17:16:32 2026 -0400 +++ b/roundup/cgi/templating.py Mon Aug 03 00:21:26 2026 +0000 @@ -3753,6 +3753,22 @@ def keywords_expressions(self, request): return render_keywords_expression_editor(request) + @staticmethod + def localReplace(message): + """Default no-op for localReplace. + + Override with real definition in extensions. + + This allows templates to ship with localReplace(....) + and have an: + + instance.registerUtil('localReplace', local_replace) + + define local_replace with the same call signature (i.e. no self) + in the extension definition. + """ + return message + def html_calendar(self, request): """Generate a HTML calendar. diff -r 75abdd7f2568 roundup/instance.py --- a/roundup/instance.py Thu Jul 30 17:16:32 2026 -0400 +++ b/roundup/instance.py Mon Aug 03 00:21:26 2026 +0000 @@ -262,7 +262,12 @@ instead. """ - self.templating_utils[name] = function + # allow templating util defined in extensions + # to replace the one defined in core. + if hasattr(self.TemplatingUtils, name): + setattr(self.TemplatingUtils, name, staticmethod(function)) + else: + self.templating_utils[name] = function def registerUtilMethod(self, name, function): """Register a method that can be called using: