是否可以在Delphi中组合资源字符串?

Alo*_*mer 1 delphi delphi-xe4

我想替换看起来像的代码

resourcestring
    RESSTR_ERR1_TRYAGAIN = 'Error 1. Please try again.';
    RESSTR_ERR2_TRYAGAIN = 'Error 2. Please try again.';
    RESSTR_ERR3_TRYAGAIN = 'Error 3. Please try again.';        
Run Code Online (Sandbox Code Playgroud)

用这样的东西:

resourcestring
    RESSTR_ERR1 = 'Error 1.';
    RESSTR_ERR2 = 'Error 2.';
    RESSTR_ERR3 = 'Error 3.';        
    RESSTR_TRYAGAIN = 'Please try again.'; 

    RESSTR_ERR1_TRYAGAIN = RESSTR_ERR1 + ' ' + RESSTR_TRYAGAIN; //error
    RESSTR_ERR2_TRYAGAIN = RESSTR_ERR2 + ' ' + RESSTR_TRYAGAIN;
    RESSTR_ERR3_TRYAGAIN = RESSTR_ERR3 + ' ' + RESSTR_TRYAGAIN;
Run Code Online (Sandbox Code Playgroud)

但这会导致错误E2026 Constant expression expected.,我明白了.

不过,我想知道是否有解决方案,允许我以RESSTR_ERRx_TRYAGAIN上述方式定义.(目标是在不触及使用RESSTR_ERRx_TRYAGAIN的所有位置的情况下消除其他翻译).

直到现在我唯一的想法是以下,但我不想使用它,因为这是相当丑陋的:

var
    RESSTR_ERR1_TRYAGAIN: string;
    //...

initialization
    RESSTR_ERR1_TRYAGAIN := RESSTR_ERR1 + ' ' + RESSTR_TRYAGAIN;
    //...
Run Code Online (Sandbox Code Playgroud)

Del*_*ics 5

resourcestring字符串在运行时解析.每次引用resourcestring时,实际发生的是您正在调用LoadResString() API以从应用程序资源加载(可能)翻译的字符串.

const 声明是常量,必须在编译时完全定义.

即使是类型化常量(技术上是变量,受编译器设置限制)也必须在编译时初始完全定义,即使它可能稍后在运行时被修改.没有基于在运行时应用的转换自动更新常量的机制.

即使您可以按照尝试的方式组合资源字符串,也不会保存任何转换,因为任何声明的资源字符串组合本身都必须是资源字符串,需要为该组合单独转换:

resourcestring
   foo = 'foo.';  // Requires translation of 'foo.'
   bar = 'bar';   // Requires translation of 'bar'
   foobar = foo + bar   // Would require translation of 'foo.bar'
Run Code Online (Sandbox Code Playgroud)

当然,正如您所发现的那样,第三个声明是不可能的,但即使它存在,它也不会为您节省额外的翻译.

你不能使用常量来保持组合的翻译值的原因是这些不是常数:

resourcestring
   foo = 'foo.';  // Requires translation of 'foo.'
   bar = 'bar';   // Requires translation of 'bar'

const
   foobar = foo + bar   // When referenced, foo and bar are actually calls to a function and so are not constant
Run Code Online (Sandbox Code Playgroud)

如果您主要关注减少声明常量的工作,那么您可以使用:

const
  foo = 'foo.';
  bar = 'bar';

resourcestring
  foobar = foo + bar;
Run Code Online (Sandbox Code Playgroud)

但是,您仍然需要为所有生成的资源字符串提供完整的常量部分,因此无法实现避免其他转换的目标.

恒定解决方案的问题

任何旨在实现组合声明的解决方案resourcestring都需要为特定组合单独翻译,从而实现很少/没有好处(实际创造更多工作:额外翻译).

任何试图使用资源字符串的编译时值声明常量的解决方案都不会在运行时进行转换.

你的工作与周围的初始化从一个相当更加微妙复杂这是您的初始化伪常数将包含初始化时的资源字符串的翻译值受到影响.如果您正在使用Sisulizer之类的东西,它允许运行时更改i18n资源,那么任何此类更改都不会反映在您的伪常量中.

您仍然可以使用此技术,但将初始化代码放在您在初始化 时调用的函数中,以及在运行时是否/何时更改转换语言.

运行时问题的运行时解决方案

如上所述,潜在的问题是您正在尝试声明由仅在运行时解析的值组成的编译时常量.

您需要的是一种方便,可靠的机制,可在运行时组合两个运行时值.

如果'try again'示例是一个独立的案例,那么将特定资源字符串附加到某个其他指定字符串(可能是资源字符串,或者可能不是)的简单函数可能就足够了:

function MessageWithTranslatedTryAgain(const aMessage: String): String;
begin
  if aMessage[Length(aMessage)] <> '.' then
    result := aMessage + '. ' + RESSTR_TRYAGAIN
  else
    result := aMessage + ' ' + RESSTR_TRYAGAIN;
end;
Run Code Online (Sandbox Code Playgroud)

如果您有许多这样的可能组合,那么您可能会选择使用许多静态实用程序方法来实现一个类:

type
  Translate = class
  public
    class function MessageWithTryAgain(const aMessage: String): String;
    class function MessageWithContinue(const aMessage: String): String;
    // etc
  end;
Run Code Online (Sandbox Code Playgroud)