我想替换看起来像
的代码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.';
有这样的事情:
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;
但这会导致错误E2026 Constant expression expected.
,我明白了。
尽管如此,我想知道是否有解决方案,允许我以上述方式定义RESSTR_ERRx_TRYAGAIN
。 (目标是在不触及使用RESSTR_ERRx_TRYAGAIN的所有位置的情况下消除其他翻译)。
直到现在我唯一的想法是以下,但我不想使用它,因为这是相当丑陋的:
var
RESSTR_ERR1_TRYAGAIN: string;
//...
initialization
RESSTR_ERR1_TRYAGAIN := RESSTR_ERR1 + ' ' + RESSTR_TRYAGAIN;
//...
答案 0 :(得分: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'
当然,正如您所发现的那样,第三个声明是不可能的,但即使它已经存在,它也不会为您节省额外的翻译。
您不能使用常量来保存组合的翻译值的原因是这些不是常数:
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
如果您主要关注减少声明常量的工作,那么您可以使用它:
const
foo = 'foo.';
bar = 'bar';
resourcestring
foobar = foo + bar;
但是,您仍然需要为所有生成的资源字符串提供完整的常量部分,因此无法实现避免其他翻译的目标。
任何旨在宣布合并resourcestring
的解决方案都需要针对特定组合单独翻译,从而实现很少/没有任何好处(实际创造更多工作:额外翻译)。
任何试图使用资源字符串的编译时值声明常量的解决方案都不会在运行时进行转换。
使用初始化的处理方法会遇到一个相当复杂的复杂问题,即初始化的伪常量将包含初始化时资源字符串的转换值。如果您正在使用Sisulizer之类的东西,它允许运行时更改i18n资源,那么任何此类更改都不会反映在您的伪常量中。
您仍然可以使用此技术,但是将初始化代码放在您在初始化 和时调用的函数中,如果/何时在运行时更改了翻译语言
如上所述,根本问题在于您尝试声明编译时常量,该常量仅由运行时解析的值组成。
您需要的是在运行时组合两个运行时值的方便可靠的机制。
如果再次尝试'示例是一个单独的案例,然后一个简单的函数将特定的资源字符串附加到某个其他指定的字符串(可能是一个资源字符串,或可能不是)可能就足够了:
function MessageWithTranslatedTryAgain(const aMessage: String): String;
begin
if aMessage[Length(aMessage)] <> '.' then
result := aMessage + '. ' + RESSTR_TRYAGAIN
else
result := aMessage + ' ' + RESSTR_TRYAGAIN;
end;
如果您有许多这样的可能组合,那么您可能会选择使用许多静态实用程序方法来实现一个类:
type
Translate = class
public
class function MessageWithTryAgain(const aMessage: String): String;
class function MessageWithContinue(const aMessage: String): String;
// etc
end;
答案 1 :(得分:2)
可以使用记录和运算符重载:
interface
type
TSpaceSeparatedResourceStrings = record
Part1: PResStringRec;
Part2: PResStringRec;
class operator Implicit(From: TSpaceSeparatedResourceStrings): string;
end;
resourcestring
RESSTR_ERR1 = 'Error 1.';
RESSTR_ERR2 = 'Error 2.';
RESSTR_ERR3 = 'Error 3.';
RESSTR_TRYAGAIN = 'Please try again.';
const
RESSTR_ERR1_TRYAGAIN: TSpaceSeparatedResourceStrings
= (Part1: @RESSTR_ERR1; Part2: @RESSTR_TRYAGAIN);
RESSTR_ERR2_TRYAGAIN: TSpaceSeparatedResourceStrings
= (Part1: @RESSTR_ERR2; Part2: @RESSTR_TRYAGAIN);
RESSTR_ERR3_TRYAGAIN: TSpaceSeparatedResourceStrings
= (Part1: @RESSTR_ERR3; Part2: @RESSTR_TRYAGAIN);
implementation
class operator TSpaceSeparatedResourceStrings.Implicit(From: TSpaceSeparatedResourceStrings): string;
begin
Result := LoadResString(From.Part1) + ' ' + LoadResString(From.Part2);
end;
用法:
ShowMessage(RESSTR_ERR1_TRYAGAIN);
我用dxgettext测试了这个并且它被正确翻译了。
(将Part1
和Part2
定义为string
的最初想法并不总是有效(正如Deltics所指出的):它确实编译但如果语言在运行时切换。)