Говорят, что унция профилактического средства стоит фунта лекарства. За многие годы решения задач по глобализации Lotus Notes мы установили, где возникает большинство проблем: на этапах проектирования и разработки. В данной статье представлены передовые методики глобализации, которые вы можете использовать для разработки качественных приложений Lotus Notes. Шаблоны Lotus Notes в настоящее время переведены на 27 языков, и в данной статье представлены методики, созданные нами за годы работы в качестве разработчиков шаблонов Lotus Notes и участников групп по переводу.
Глобализация приложений Lotus Notes является непростой задачей для пользователей. Код и переводимые строки приложений Lotus Notes по своей природе связаны между собой. Разработчики обычно разрабатывают приложение Lotus Notes на одном языке и реализуют перевод на другие языки строк приложения напрямую в клиентском приложении Lotus Domino® Designer. В результате приходится при любом изменении или обновлении приложения приходится изменять сотни элементов дизайна для каждого языка отдельно. Обработка изменений, управление версиями, обновление дизайна и исправление ошибок требуют значительных затрат.
Эта статья является второй частью серии из двух статей, посвященных глобализации.
В первой части "Советы пользователям по глобализации приложений IBM Lotus Notes" рассматриваются следующие темы:
- Процесс глобализации для приложений Lotus Notes.
- Новые функциональные возможности версии 8.5 среды Lotus Domino Global Workbench, использующие файлы свойств для глобализации приложений.
- Практика глобализации приложений Lotus Notes и обновления многоязычных приложений.
Во второй части "Передовые методики разработки приложений IBM Lotus Notes, пригодных для глобализации" рассматриваются следующие темы:
- Рекомендации по разработке приложений Lotus Notes с учетом глобализации.
- Глобализация различных элементов управления в приложениях Lotus Notes.
Эта статья поможет вам в разработке высококачественных приложений Lotus Notes, удовлетворяющих требованиям глобализации. Следуя приведенным методикам, вы сможете избежать потенциальных проблем на этапах проектирования и разработки и сэкономить время и ресурсы на более поздних этапах глобализации программного обеспечения.
Как выполнить глобализацию приложения Lotus Notes
Один из общих подходов к разработке приложения на разных языках состоит в том, что приложение разрабатывается на одном языке, а затем файлы ресурсов переводятся на другие языки. Такой подход называется методологией с единым исполняемым файлом. Он имеет много преимуществ:
- С точки зрения разработчика облегчается разработка, тестирование и обслуживание.
- С точки зрения пользователя упрощается установка и настройка.
На рисунке 1 изображен единый модуль исполняемых кодов.
Рисунок 1. Модуль с единым исполняемым кодом
По своему устройству шаблон Lotus Notes представляет собой комбинацию терминологии и кода. В результате глобализация приложения Lotus Notes для многих заказчиков является непростой задачей. В приложениях Lotus Notes нет ни RC-файла (в котором переводимые фрагменты заключаются в кавычки), как в приложениях, написанных на C/C++, ни файла свойств (в котором переводимые фрагменты предваряются знаком равенства), как в Java-приложениях. Обычно приложения Lotus Notes разрабатываются на родном языке разработчика. После завершения проектирования и разработки приложения переводятся на другие языки непосредственно в Lotus Domino Designer, при этом может понадобиться изменение программного кода.
К счастью, у нас есть приложение Lotus Domino Global Workbench, позволяющее выделять строки из Lotus Notes™ и встраивать переведенные строки в соответствующие языковые версии приложения. Однако если при разработке приложения Lotus Notes не соблюдать рекомендации и оптимальные методики, обязательно возникнут проблемы. Большинство проблем глобализации можно предотвратить на начальном этапе проектирования приложения.
На рисунке 2 изображен жизненный цикл разработки глобализуемого приложения. В этом цикле глобализация присутствует на каждом этапе разработки приложения, включая сбор требований пользователей, анализ и проектирование, разработку, тестирование и обслуживание.
Рисунок 2. Жизненный цикл разработки глобализации приложения
Как показано в выделенном темным цветом фрагменте на рисунке 2, передовые методики разработки глобализуемого приложения являются одним из самых важных этапов жизненного цикла. Они помогают создавать высококачественные приложения Lotus Notes, удовлетворяющие требованиям глобализации, соответствующие рекомендациям вашей организации и проходящие тестирование корректности глобализации.
В данной статье представлены десятки типичных затруднений, с которыми мы столкнулись за годы работы по глобализации приложений Lotus Notes. Большая часть этих затруднений легко обходится в процессе разработки. Следуя приведенным рекомендациям, вы сможете спроектировать и реализовать отличное приложение с точки зрения глобализации.
Избегайте использования составных строк в коде
В процессе глобализации приложения Lotus Notes составные строки тегируются в различные термины в файлах свойств и базах данных глоссария. Из-за этого трудно гарантировать корректное комбинирование этих терминов после перевода на другие языки.
Попросту говоря, если переведенный текст формируется простой конкатенацией строк, сформированные фразы могут стать некорректными на других языках. В листинге 1 показан пример.
Листинг 1. Фрагмент кода с использованием составных строк в формуле
@If(FirstDayOut = "" | FirstDayBack = ""; ""; "I will be out of the office starting " + @Text(@Date(FirstDayOut)) + " and will not return until " + @Text(@Date(FirstDayBack)) + ".") |
Если предложение содержит составные строки, при тегировании ему не сопоставляется один термин в файле свойств. Вместо этого составляющие строки тегируются в разные термины без контекста. В листинге 2 показано, как выглядят выделенные свойства. На рисунках 3 и 4 показано, что VAR2 и VAR4 не будут выделены в файл ресурсов.
Приведенная в листинге 2 структура файлов свойств относительно проста: обычно все, что следует за знаком равенства, нужно переводить; все, чему предшествует знак номера (#), должно быть исключено из перевода.
Листинг 2. Извлеченные переводимые термины
Form.(Out_Of_Office_Profile).Str1=I will be out of the office starting Form.(Out_Of_Office_Profile).Str2=and will not return until |
Рисунок 3. Пример конкатенации - 1
Рисунок 4. Пример конкатенации - 2
Когда переводчик получает извлеченные строки и переводит их на другой язык, он не знает, будут ли они отображаться как одно предложение в пользовательском интерфейсе. Отдельные термины переводятся без контекста, и это может привести к неточностям или даже недоразумениям. Иногда составные строки имеют разную структуру в разных языках. Глагол, используемый в данной строке, может не подходить для другой строки в силу особенностей языка. Порядок слов в предложении при переводе на другой язык также может меняться.
В листинге 3 представлен предлагаемый подход для устранения конкатенации в вашем коде; показано одно из решений. В листинге 4 составляющие строки выделены как единое предложение, которое значительно легче перевести.
Листинг 3. Предлагаемый подход к устранению составных строк
@ReplaceSubstring("I will be out of the office starting var_startdate and
will not return until var_returndate.";"var_startdate":"var_returndate"
:@Text(@Date(FirstDayOut)):@Text(@Date(FirstDayBack)))
|
Листинг 4. Выделенные переводимые термины (правильный подход)
Form.(Out_Of_Office_Profile)_|_OutOfOfficeProfile.PostRecalc.Str1 = I will be out of the office starting var_startdate and will not return until var_returndate |
Не используйте переводимые строки в качестве программных условий
Избегать использования переводимых строк в качестве программных условий - это одна из самых важных рекомендаций при разработке глобализованных приложений Lotus Notes. Всегда помните об этом предупреждении, поскольку его очень легко забыть.
В листинге 5 показан пример использования переводимых строк в качестве программных условий.
Листинг 5. Фрагменты кода с использованием переводимых строк в качестве программных условий
1. REM "Begin Do Not Translate" 2. Const DSPIND = "dspIndividualAccess" 3. REM "End Do Not Translate" 4. REM "Begin Translatable Text” 5. Const CALENDER_NOTICES = "Calendar notices are automatically forwarded to this person" 6. REM "End Translatable Text” 7. Set item = note.getfirstitem(DSPIND) 8. strIndividualAccess = item.Text 9. lposition = Instr( strIndividualAccess, CALENDER_NOTICES) 10. If lposition > 0 And lposition <> 1 Then 11. ' strip off fwd msg 12. strIndividualAccess = Left( strIndividualAccess, lposition-2 ) 13. Elseif lposition=1 Then 14. strIndividualAccess="" 15. Else 16. strIndividualAccess=Left( strindividualAccess, Len(strindividualAccess)-1) 17. End If |
В листинге 5 программа решает, является ли "dspIndividualAccess" подстрокой строки "Calendar notices are automatically forwarded to this person". Lotus Domino Global Workbench создает два отдельных свойства. Трудно гарантировать, что первое предложение всегда будет переводиться как подстрока второго, если вы собираетесь переводить их на различные языки. На рисунке 5 показан пример их перевода на упрощенный китайский язык; в этом примере первое предложение не является подстрокой второго.
Рисунок 5. Перевод двух переменных
Очевидно, если строки используются в качестве программных условий, при их переводе могут возникнуть функциональные проблемы. Более того, такого рода ошибки чрезвычайно трудно отследить при глобализации приложения. Никогда не используйте переводимые строки в качестве программных условий. В дополнение к функциям Instr из LotusScript®, которая часто используется для поиска подстроки, и @UpperCase и @LowerCase из Formula, которые часто применяются для изменения регистра символов в строках, в таблице 1 перечислены некоторые другие функции в LotusScript и Formula, которые следует применять только для обработки непереводимых строк, и ни в коем случае не для переводимых строк. Применение этих функций к переводимым символьным строкам может привести к неожиданным результатам, от языковых ошибок в пользовательском интерфейсе до сбоев функций.
Таблица 1. Функции в LotusScript и Formula, которых следует избегать при работе с переводимыми строками
| Назначение | LotusScript | Formula |
|---|---|---|
| Преобразование | Cstr, Cint, Cdat, Abstract, StrConv, Lcase, Ucase | @LowerCase, @ProperCase, @LwerCase, @UpperCase, @TextToNumber, @TextToTime, @Explode, @Replace |
| Сравнение | StrToken, StrCompare, Split, like | @ReplaceSubstring, @Matches@Like, @Contains, , |
| Длина | Mid, Len, LenC | @Length |
| Позиция | Left, StrLeft, StrLeftback, Right, StrRight, StrRightback, Instr, Trim, Contains, RightBP, MidBP | @Left, @Middle, @Middleback, @Begins, @Ends, @LeftBack, @RightBack, @Right |
| Другие | Join… | @Word… |
Избегайте использования комбинаций текста и полей Lotus Notes в пользовательском интерфейсе
Поля (например, текстовые) часто используются в Lotus Notes для отображения, но их некорректное использование может привести к проблемам глобализации. Смешивание текста и полей также является проблемой конкатенации, аналогичной проблеме, рассмотренной выше.
Когда сообщение переводится на другой язык, может понадобиться изменить позицию и порядок подставляемых переменных в соответствии с синтаксическими требованиями выбранного языка. Поэтому следует избегать смешения текста и полей, которое может приводить к грамматическим ошибкам в переводимых строках. Предоставьте переводчикам возможность управлять позицией и порядком подставляемых переменных и фраз.
На рисунке 6 показан плохой пример; это комбинация текста и полей Lotus Notes. Выделяемые средой Lotus Domino Global Workbench переводимые термины приведены в листинге 8. Видно, что предложение разделено на отдельные сегменты, и его трудно переводить.
Рисунок 6. Пример плохого пользовательского интерфейса
Листинг 8. Выделенные переводимые термины
Form.Response.Str1=The response is for Form.Response.Str2=and was send by |
Как показано на рисунке 7, при попытке перевести это предложение на упрощенный китайский язык обнаруживается, что его структура отличается от английской версии, поэтому порядок полей необходимо изменить так, как показано на рисунке 8.
Рисунок 7. Перевод всего предложения на упрощенный китайский язык
Рисунок 8. Изменение порядка полей
Переводчик не может изменить порядок полей, поскольку предложение было разделено на несколько терминов в файле свойств.
Одним из решений проблемы конкатенации в пользовательском интерфейсе является помещение разделенных строк в один вычисляемый текст или поле и использование переменных, например: "The response is for VAR_Who1 and was send by VAR_Who2".
Добавляйте комментарии к переменным
Советуем добавлять комментарии к следующим переменным:
- DNT-переменные
- Скрытые переменные
- Переводимые переменные
Добавляйте комментарии для DNT-переменных и скрытых переменных
DNT-переменные (Do Not Translate - не переводить) являются важным фактором при переводе на другой язык. Скрытые переменные обычно не нужно переводить. Полезно добавлять к ним комментарии, поскольку это помогает избежать их непреднамеренного перевода. В листинге 6 приведены хорошие примеры добавления комментариев для DNT-переменных и скрытых переменных.
Листинг 6. Добавление комментариев для DNT-переменных и скрытых переменных
1. DNT-переменные в LotusScript
REM "Begin Do Not Translate"
<LotusScript Code>
REM "End Do Not Translate"
2. DNT-переменные в Formula
'Begin Do Not Translate
REM {Begin Do Not Translate};
<Formula Code>
'End Do Not Translate
REM {End Do Not Translate};
3. Постоянно скрытые переменные
'Begin Always Hidden variables
<Hidden variables>
'End Always Hidden variables
|
Добавляйте комментарии для переводимых переменных
В листинге 7 приведен пример добавления комментариев для переводимых переменных. Здесь порядок строк может определяться переводчиком. Эти комментарии помогут переводчику понять, что он переводит; помните также, что в большинстве ситуаций переводчик не видит и не понимает исходный код.
Листинг 7. Добавление комментариев для переводимых переменных
{ REM The text of the next string determines the order of display of the
following strings "FamilyName" and "GivenName" }
OrderOfStings := "FamilyNameFirst";
Field1 := "FamilyName";
Field2 := "GivenName";
{ REM Begin DNT }
FIELD Display:=@If(OrderOfStrings = "FamilyNameFirst " ;Field1+Field2; Field2+Field1)
{ REM End DNT }
DGW сгенерирует значения в файле свойств, выглядящие примерно так:
# The text of the next string determines the order of display of the
following strings " FamilyName " and " GivenName "
Form.Memo.Action_Label_Formula.FamilyNameFirst =FamilyNameFirst
Form.Memo.Action_Label_Formula.FamilyName = FamilyName
Form.Memo.Action_Label_Formula.GivenName = GivenName
|
Совет. Именование DNT-переменной с изменением регистра символов поможет переводчику понять, что их нужно игнорировать при переводе. В листинге 8 приведен пример DNT-значений upDatEupdate и inForMation upDatE.
Листинг 8. Именование DNT-переменных с изменением регистра символов
REM {Begin Do Not Translate};
update = "upDatE";
updateInformation = "inForMation upDatE";
requestInformation = "reQuesT InforMation";
requestupDate= "reQuesT upDate";
REM {End Do Not Translate};
|
Корректно присваивайте строки переменным и определяйте ваши переменные
Несколько главных рекомендаций по присваиванию строк и определению переменных:
- Никогда не встраивайте текстовые строки в исходный код.
- Определяйте и назначайте переменные только в начале сценария.
- Не используйте обычные слова языка для именования внутренних переменных.
Никогда не встраивайте строк в исходный код
В листинге 9 приведен плохой пример, где все переводимые строки закодированы в исходном коде. Такое кодирование осложняет чтение, понимание и обслуживание кода, а также затрудняет выделение терминов системой Lotus Domino Global Workbench. Лучше определять строки в виде переменных.
Листинг 9. Плохой пример: строки, закодированные в исходном коде LotusScript
Function GetString(nIndex As Integer, vData As Variant) As String
Select Case nIndex
Case RECALL_STRING_MSGTO
GetString = "Message to: "
Case RECALL_STRING_MSGSTATUS
GetString = " Message status: "
Case RECALL_STRING_FAILREASON
GetString = " Recall failure reason: "
Case RECALL_STRING_NORESPONSES
GetString = "Your recall request has been initiated.
For more information,
open the Recall Status report for this
message when you receive it."
Case RECALL_STRING_OTHERREPORT
GetString = "Other delivery reports.
(No recall information is available) "
End Function
|
В листинге 10 приведен хороший пример определения строк в сценарии в виде переменных. Эти сообщения не являются жестко закодированными.
Листинг 10. Хороший пример: применение переменных вместо жесткого кодирования строк
Function GetString(nIndex As Integer, vData As Variant) As String REM "Begin Translatable Text” Const xxMessage = "Message to: " Const xxMessageStatus = " Message status: " Const xxMessageFailReason = " Recall failure reason: " Const xxMessageInitia= "Your recall request has been initiated. For more information, open the Recall Status report for this message when you receive it." Const xxMessageOtherReport = "Other delivery reports. (No recall information is available) " REM "End Translatable Text” Select Case nIndex Case RECALL_STRING_MSGTO GetString = xxMessage Case RECALL_STRING_MSGSTATUS GetString = xxMessageStatus Case RECALL_STRING_FAILREASON GetString = xxMessageFailReason Case RECALL_STRING_NORESPONSES GetString = xxMessageInitia Case RECALL_STRING_OTHERREPORT GetString = xxMessageOtherReport End Select End Function |
Определяйте и назначайте переменные только в начале сценария
В листинге 11 все переводимые и непереводимые строки определены в начале сценария, что облегчает его чтение.
Листинг 11. Определение переменных в начале сценария
REM "Begin Translatable Text” Const xxRecipient = "Recipient" Const xxStatus = "Status" Const xxServer = "Server" Const xxDetails = "Details" Const xxNRecalled = "Not Recalled" Const xxRecalled = "Recalled" Const SERVER_NOT_SUPPORTED = "Server does not support Message Recall" Const MESSAGE_NOT_FOUND ="Cannot find message. Server could be down or recipient no longer in NAB" Const RECALL_REQUEST_NOT_FOUND = "Cannot process Recall Status report. Unable to locate Recall Request document." Const INTERNET_RECALL_NOT_ALLOWED = "Cannot Recall from Internet Address" REM "End Translatable Text” REM "Begin Do Not Translate" Const RECALL_ERROR = "Recall Error" Const MAIL_RECALL_REQUEST_FORM$= "Recall Request" Const MAIL_RECALL_RESPONSE_FORM$ = "Recall Response" Const MAIL_TRACEREPORT_FORM$= "Trace Report" Const MAIL_DELIVERYREPORT_FORM$= "Delivery Report" Const MAIL_RETURNRECEIPT_FORM$= "Return Receipt" Const SERVER_VERSION_NOT_SUPPORTED$="Pre-IBM Lotus Domino 8 Server" REM "End Do Not Translate" Class ProcessRecall Public Sub Init(uidoc As notesuidocument) On Error Goto eTrap Dim uiws As New notesuiworkspace,session As New NotesSession,reqSource As NotesUIDocument …… …… If (uidoc.InPreviewPane) Then Exit Sub End If parentDocUNID = uidoc.Document.ParentDocumentUNID If (parentDocUNID = "") Then Msgbox RECALL_REQUEST_NOT_FOUND,16,RECALL_ERROR uidoc.close Exit Sub …… …… End Sub End Class |
Не используйте обычные слова языка для именования внутренних переменных
При именовании внутренних переменных избегайте использования обычных понятных слов. Объединяйте слова без пробелов, чтобы указать переводчику, что эти строки являются непереводимыми переменными. В листинге 12 показан пример такого подхода. Используйте в качестве переменной имени документа InterestProfile, а не Interest Profile.
Листинг 12. Не используйте обычные понятные слова при именовании внутренних переменных
Вместо: @if(xxdocname = "Interest Profile";"Interest Profile";"Standard Document") Используйте: @if(xxdocname = "InterestProfile";"Interest Profile";"Standard Document") |
Создавайте псевдонимы для ключевых слов поля выбора
Для удобства программирования используйте псевдонимы для ключевых слов. Варианты выбора могут отображаться в пользовательском интерфейсе, поэтому следует ввести псевдонимы для этих вариантов в Listbox или Checkbox, а затем переводить отображаемые строки, как показано на рисунке 9.
Рисунок 9. Список опций в Listbox
На рисунке 9 вариант следует шаблону, показанному в Meeting | Meeting: первая строка является переводимой, поскольку она используется только для пользовательского интерфейса, а вторая строка (псевдоним) является непереводимой. В файлах свойств для перевода выделяются только последние переводимые строки. В листинге 13 показано, как выглядят эти выделяемые термины.
Листинг 13. Выделяемые термины
Form.meeting.Listbox.MemoType = Meeting Form.meeting.Listbox.MemoType = Appointment Form.meeting.Listbox.MemoType = All Day Event Form.meeting.Listbox.MemoType = Reminder Form.meeting.Listbox.MemoType = To Do |
Назначайте как минимум один псевдоним формам и представлениям
Название формы и название представления обычно нужно переводить, поскольку они отображаются в интерфейсе, поэтому добавление псевдонима необходимо по соображениям программирования.
Более того, мы советуем, чтобы псевдоним не содержал пробелов, особенно если он может быть использован в Web. Помните, псевдонимы в приложении Lotus Notes не переводятся. Не назначайте один и тот же псевдоним различным элементам дизайна.
Используйте таблицы вместо табуляций для отделения статического текста от поля
Избегайте использования знаков табуляции для управления размещением элементов. На рисунке 10 программист использует табуляцию для выравнивания полей. Для английского языка все выглядит замечательно, но после перевода на другой язык поля будут смещены, поскольку длина терминов при переводе меняется по-разному. На рисунке 11 после перевода терминов на корейский язык расположение элементов сбилось.
Рисунок 10. Использование табуляций для управления размещением элементов (английский язык)
Рисунок 11. Использование табуляций для управления размещением элементов (корейский язык)
Вместо этого используйте для отделения статического текста от полей таблицу. Размещение остается нормальным даже после перевода терминов на другие языки.
Кодируйте и декодируйте переменные, отображающиеся в Web
Не забывайте кодировать и декодировать переменные, которые непосредственно отображаются в Web. На рисунке 12 заголовок окна был закодирован для HTML, но не декодирован, поэтому в заголовке появляется мусор %XX%. В листинге 14 показано, как декодировать переменную.
Рисунок 12. Мусор в заголовке окна
Листинг 14. Декодирование переменной
Example: PartialName :=
@Right(@URLDecode("Domino";Query_String);"&Title=")
|
В статье представлен процесс глобализации приложений Lotus Notes и применяемая для этого инструментальная программа Lotus Domino Global Workbench. Глобализация приложений Lotus Notes выполняется путем извлечения переводимых строк при помощи системы Lotus Domino Global Workbench и встраивания переведенных строк в исходные приложения Lotus Notes.
Научиться
- Оригинал статьи "Best practices in globalization: Developing IBM Lotus Notes applications" (EN).
- Прочтите первую часть данной серии статей developerWorks® "Советы пользователям по глобализации приложений IBM Lotus Notes".
- Прочтите статью developerWorks "Введение в многоязычные приложения Lotus Notes/Domino 6" (EN).
- Прочтите статью developerWorks "Мыслите глобально. Создание многоязычной среды Lotus Notes/Domino" (EN).
-
Участвуйте в IBM Lotus Domino wiki.
(EN)
-
Страница продуктов IBM Lotus Notes и Domino на developerWorks.(EN)
Получить продукты и технологии
- Загрузите ознакомительную версию IBM Lotus Domino и Lotus Notes 8.5. (EN)
Обсудить
- Примите участие в обсуждении материала на форуме.
-
Принимайте участие в
форумах на
developerWorks Россия.
Тони Куо (Tony Kuo) - штатный инженер-программист в IBM China Software Development Lab в Тайбэе (Тайвань). Специализируется в области глобализации и тестирования программного обеспечения. Руководит группами, участвующими в глобализации IBM Lotus Notes и Lotus Domino и верификационном тестировании глобализации. Связаться с ним можно по адресу yjkuo@tw.ibm.com.