Конвертировать LTR в RTL?
Как вы знаете, многие компоненты пользовательского интерфейса и инструменты разработки не поддерживают RTL, мы можем назвать это перелистыванием текста, потому что результатом является тот же пример:
LTR
سلام salam متن راهنما word
РТЛ
word متن راهنما salam سلام
в любом случае, чтобы конвертировать этот LTR в RTL, я понятия не имею, и язык не имеет значения
На самом деле я ищу решение, чтобы сделать это в приложении RAD Studio Firemonkey, так как вы, возможно, знаете, что приложения Firemonkey не поддерживают RTL, оно находится в дорожной карте Rad Studio, но еще не реализовано
2 ответа
Под Windows вы можете сделать это через API UniScribe.
Я использовал это, чтобы преобразовать текст Unicode в набор глифов для нашего Open Source PDF Writer.
У вас есть пример исходного кода в модуле SynPdf.pas. Увидеть TPdfWrite.AddUnicodeHexTextUniScribe
метод:
function TPdfWrite.AddUnicodeHexTextUniScribe(PW: PWideChar;
WinAnsiTTF: TPdfFontTrueType; NextLine: boolean; Canvas: TPdfCanvas): boolean;
var L, i,j: integer;
res: HRESULT;
max, count, numSp: integer;
Sp: PScriptPropertiesArray;
W: PWideChar;
items: array of TScriptItem;
level: array of byte;
VisualToLogical: array of integer;
psc: pointer; // opaque Uniscribe font metric cache
complex,R2L: boolean;
complexs: array of byte;
glyphs: array of TScriptVisAttr;
glyphsCount: integer;
OutGlyphs, LogClust: array of word;
procedure Append(i: Integer);
// local procedure used to add glyphs from items[i] to the PDF content stream
var L: integer;
W: PWideChar;
procedure DefaultAppend;
var tmpU: array of WideChar;
begin
SetLength(tmpU,L+1); // we need the text to be ending with #0
move(W^,tmpU[0],L*2);
AddUnicodeHexTextNoUniScribe(pointer(tmpU),WinAnsiTTF,false,Canvas);
end;
begin
L := items[i+1].iCharPos-items[i].iCharPos; // length of this shapeable item
if L=0 then
exit; // nothing to append
W := PW+items[i].iCharPos;
if not GetBit(complexs[0],i) then begin
// not complex items are rendered as fast as possible
DefaultAppend;
exit;
end;
res := ScriptShape(0,psc,W,L,max,@items[i].a,
pointer(OutGlyphs),pointer(LogClust),pointer(glyphs),glyphsCount);
case res of
E_OUTOFMEMORY: begin // max was not big enough (should never happen)
DefaultAppend;
exit;
end;
E_PENDING, USP_E_SCRIPT_NOT_IN_FONT: begin // need HDC and a selected font object
res := ScriptShape(Canvas.FDoc.GetDCWithFont(WinAnsiTTF),
psc,W,L,max,@items[i].a,
pointer(OutGlyphs),pointer(LogClust),pointer(glyphs),glyphsCount);
if res<>0 then begin // we won't change font if necessary, sorry
// we shall implement the complex technic as stated by
// http://msdn.microsoft.com/en-us/library/dd374105(v=VS.85).aspx
DefaultAppend;
exit;
end;
end;
0: ; // success -> will add glyphs just below
else exit;
end;
// add glyphs to the PDF content
// (NextLine has already been handled: not needed here)
AddGlyphs(pointer(OutGlyphs),glyphsCount,Canvas);
end;
begin
result := false; // on UniScribe error, handle as Unicode
// 1. Breaks a Unicode string into individually shapeable items
L := StrLenW(PW)+1; // include last #0
max := L+2; // should be big enough
SetLength(items,max);
count := 0;
if ScriptItemize(PW,L,max,nil,nil,pointer(items),count)<>0 then
exit; // error trying processing Glyph Shaping -> fast return
// 2. guess if requiring glyph shaping or layout
SetLength(complexs,(count shr 3)+1);
ScriptGetProperties(sP,numSp);
complex := false;
R2L := false;
for i := 0 to Count-2 do // don't need Count-1 = Terminator
if fComplex in sP^[items[i].a.eScript and (1 shl 10-1)]^.fFlags then begin
complex := true;
SetBit(complexs[0],i);
end else
if fRTL in items[i].a.fFlags then
R2L := true;
if not complex then begin
// no glyph shaping -> fast append as normal Unicode Text
if R2L then begin
// handle Right To Left but not Complex text
W := pointer(items); // there is enough temp space in items[]
W[L] := #0;
dec(L);
for i := 0 to L do
W[i] := PW[L-i];
AddUnicodeHexTextNoUniScribe(W,WinAnsiTTF,NextLine,Canvas);
result := true; // mark handled here
end;
exit;
end;
// 3. get Visual Order, i.e. how to render the content from left to right
SetLength(level,count);
for i := 0 to Count-1 do
level[i] := items[i].a.s.uBidiLevel;
SetLength(VisualToLogical,count);
if ScriptLayout(Count,pointer(level),pointer(VisualToLogical),nil)<>0 then
exit;
// 4. now we have enough information to start drawing
result := true;
if NextLine then
Canvas.MoveToNextLine; // manual NextLine handling
// 5. add glyphs for all shapeable items
max := (L*3)shr 1+32; // should be big enough - allocate only once
SetLength(glyphs,max);
SetLength(OutGlyphs,max);
SetLength(LogClust,max);
psc := nil; // cached for the same character style used
if Canvas.RightToLeftText then
// append from right to left visual order
for j := Count-2 downto 0 do // Count-2: ignore last ending item
Append(VisualToLogical[j]) else
// append from left to right visual order
for j := 0 to Count-2 do // Count-2: ignore last ending item
Append(VisualToLogical[j]);
end;
Конечно, это только под Windows. Так что он не будет работать на Mac OS X. Вам придется использовать другую библиотеку под Mac OS X...
Это сложно. Если вы хотите сделать это правильно, вы должны использовать Библиотеку Bidi из International Components for Unicode.
Если вы используете MFC, вот как установить как правое направление, так и выравнивание. Предполагая, что ваш элемент управления CEdit называется m_TextEdit:
void MyDialog::SetLangDirection(bool RTL)
{
DWORD w_dwStyle;
w_dwStyle = GetWindowLong(m_TextEdit.GetSafeHwnd(), GWL_EXSTYLE);
if (RTL)
{
w_dwStyle -= WS_EX_LEFT | WS_EX_LTRREADING;
w_dwStyle |= WS_EX_RIGHT | WS_EX_RTLREADING;
}
else
{
w_dwStyle -= WS_EX_RIGHT | WS_EX_RTLREADING;
w_dwStyle |= WS_EX_LEFT | WS_EX_LTRREADING;
}
SetWindowLong(m_TextEdit.GetSafeHwnd(), GWL_EXSTYLE, w_dwStyle);
}
Смотрите мой совет.