做SAP项目的朋友应该都有体会,“表单搬家”听起来是件小事,真正做起来却常常是一连串连锁反应。我最近刚处理完一个Smart Form从英文项目环境传到另一个系统、还要在目标系统落地俄语版本的需求,这里面的坑比预想多得多。这个场景在国际业务、多语言集团实施、海外子公司推广里非常典型:源系统里跑得好好的英文发货单模板,要原封不动迁到新环境,还要让俄语用户能直接打印出本地化单据。写出来给后面要用的人排个雷。
这个需求拆开看其实是两件事:一是Smart Form的跨系统传输,二是多语言翻译。单独看都不算复杂,可一旦组合起来,就牵扯到传输对象完整性、语言包、字体、打印配置等一系列环节。尤其是Smart Form这种特殊ABAP对象,存储方式和普通程序完全不一样,传错了、漏传了,到了目标系统各种奇怪问题都会冒出来。本文全程围绕“英文表单跨系统传输+目标系统落地俄语版本”这一条主线,适合SAP ABAP开发、功能顾问、Basis以及要独立跑多语言项目的实施人员参考。
1. 拆解需求:这压根不是“表单搬家”那么简单
1.1 需求本质:一套表单,两个系统,三种语言状态
大多数人对Smart Form跨系统的第一反应是“建个传输请求传过去不就完了”,但实际操作中你会发现,Smart Form的传输根本不能当普通ABAP程序处理。它不像报表程序一样所有代码都躺在SE38里,随便复制粘贴就能跑起来。一个完整可用的Smart Form,背后往往挂着打印程序、文本模块、样式、图形、页面格式甚至自定义表/结构,任何一个环节漏掉,目标系统里的表单就是“残废”状态。
再说多语言。我们这次的需求是英文表单落地俄语版本,也就是说,Smart Form在源系统里是用英文(EN)开发的,所有文本元素和文本模块都是英文内容,原始语言(Original Language)也是EN。到了新系统,用户登录语言是俄语(RU),打印出来的表单必须自动切换成俄语内容。这里有两个关键点:第一,目标系统必须提前安装俄语语言包,否则SE63里根本建不了RU的翻译条目;第二,Smart Form的文本元素、文本模块、样式里的固定文本都得逐条翻译,而且翻译完之后还要验证打印层面俄语字符能不能正常输出,尤其是西里尔字母的字体映射,稍不留神就会在打印机上变成一排问号或者方块。
1.2 路线选择:先传输再翻译,比先翻译再传输更省事
有人会问,能不能在源系统里先把俄语翻译做好,然后一次性把多语言版本传过去?理论上能做,但实操中我强烈建议不要这么干。原因有三:第一,源系统未必安装了俄语语言包,很多开发系统为了瘦身只装EN和CN,硬要做翻译还得先装语言组件,占用系统资源不说,还容易污染开发系统的语言环境;第二,翻译动作本身会产生新的传输条目,如果在源系统翻译,释放请求时会带走一大批RU翻译相关对象,到了目标系统如果目标系统语言包版本跟源系统不一致,极容易出现语言导入冲突;第三,多语言项目的惯例是“目标系统语言环境各自维护”,翻译工作放在目标系统直接做,责任边界更清晰,后续俄语文本要修改也不用回溯源系统。
所以正确的路线是:先做跨系统传输,把英文版Smart Form完整落到目标系统,在目标系统确认英文版本能正常打印之后,再在目标系统里执行俄语翻译、验证俄语输出。这个顺序能最大程度隔离变量:传输阶段出问题,就跟翻译无关;翻译阶段出问题,也不会牵扯到源代码和原始表单结构。
2. 源系统盘点:动手前把Smart Form“吃透”
2.1 确认原始语言和开发包归属
动传输请求之前,先在源系统把Smart Form自身的情况摸清楚。用事务代码SMARTFORMS打开表单,进入“属性”界面,第一件事看“原始语言”(Original Language)。这个字段决定了表单的主语言版本,也直接影响SE63翻译时的源语言判断。如果原始语言显示为EN,那翻译时源语言就选EN,目标语言选RU,逻辑很清晰。如果原始语言不是EN(比如有人用中文环境创建的英文内容),那后面翻译时就要格外小心,因为SAP里非原始语言版本的文本修改方式跟原始语言完全不一样,容易被SE63拦截。
开发包(Package)归属也很重要。Smart Form的开发包直接决定了它在传输请求里属于Workbench请求(类型K)还是Customizing请求(类型C),不同请求类型的传输路径和审批流程完全不同。一般情况下,Smart Form放在自定义开发包(如$TMP、ZCUSTOM或对应模块的开发包)里,用Workbench请求即可。如果发现表单还在$TMP里躺着,最好在传输前把它分配到一个正式开发包,否则请求到目标系统后对象会被归到本地对象,后续升级维护会非常痛苦。
2.2 把“隐形”依赖对象一个个捞出来
Smart Form最麻烦的地方在于它的“依赖对象”藏得很深。我建议在传输前按以下维度把依赖对象全部列出来,逐个确认是否要打包进同一请求:
- 打印程序:调用Smart Form的ABAP程序(通常通过SSF_FUNCTION_MODULE_NAME、SSFOPEN、SSFWRITE、SSFCLOSE这组函数调用),对象类型为PROG。如果打印程序是靠FORMS事务代码生成的“测试驱动程序”,也要一起传。
- 文本模块(Text Module):Smart Form里通过“插入文本模块”引用的独立文本,用SO10维护,对象类型为TEXT或TXMT。这个最容易漏,因为它在SMARTFORMS界面里只是一个小小引用,但实际存的是另一张表的数据。
- 样式(Style):如果表单在“样式”页签挂了自定义样式,这个样式对象(STYLE)得单独添加进传输请求,否则格式信息会丢失。
- 图形(Graphics):比如公司logo、签名图片,这些存在SE78里,对象类型为GRPH。传到目标系统后还要确认目标系统SE78里有没有对应的图形条目。
- 表和结构:表单里引用的数据字典结构(比如内表头、工作区、字段),以及打印程序里用的表,如果是新开发的自定义表,也要一起传。
- 自定义函数模块:如果Smart Form流程里调用了自定义的字段转换函数,对应的函数组(FUGR)必须跟着传。
- 页面格式(Page Format):如果用了自定义页面格式而不是标准DIN A4,要关注目标系统的打印配置里是否存在对应的格式定义。
2.3 源表单核查清单
我整理了一份自查表,分享给大家。每次做Smart Form迁移前,对着这张表过一遍,能省掉后面一半的排查时间。
| 核查维度 | 检查内容 | 源系统确认方式 |
|---|---|---|
| 表单本体 | Smart Form名称、原始语言、开发包、激活状态 | SMARTFORMS → 属性 |
| 打印程序 | 调用该表单的ABAP程序名称、程序状态 | SE38查看代码 / SE80查找引用 |
| 文本模块 | 引用的所有SO10文本名称和语言版本 | SMARTFORMS → 插入文本模块节点 |
| 样式 | 是否挂载样式、样式名称及对象类型 | SMARTFORMS → 样式页签 |
| 图形 | 所有SE78图形名称、图形ID | SMARTFORMS → 图形节点 / SE78 |
| 表/结构 | 表单定义的全局变量、ABAP结构 | SMARTFORMS → 全局定义 |
| 函数 | 流程调用的函数模块及函数组 | SMARTFORMS → 流程页签 |
这张表查完,你基本上就有了传输对象清单,接下来该去建请求了。
3. 跨系统传输实操:创建请求、添加对象、释放与导入
3.1 为什么Smart Form不能像普通ABAP对象一样直接传
很多读者可能好奇,Smart Form为什么不直接复制源程序文件到目标系统然后激活。原因是Smart Form的存储机制跟普通ABAP对象完全不同。你说它是“程序”吧,它没有源代码文件;你说它是“配置”吧,它又包含了大量的逻辑和布局。实际上Smart Form的完整定义被拆散存储在多个表里:表单头信息和ID存储在STXFADM、STXFTXT等表,字形布局、窗口信息、流逻辑、文本元素全部以特殊格式存放在这些簇表(Cluster Table)中。所以SAP才专门为Smart Form设计了独立的传输对象类型FORMS,靠的是R3TR FORMS这样的传输条目把整个表单在内存中重新组装。
明确了这一点,你就能理解为什么Smart Form传输时经常会遇到“依赖对象缺失”的报错。它不是直接编译执行的文件,而是运行时动态加载的元数据,一旦引用的文本模块、图形或结构在目标系统不存在,表单激活或运行时就会直接挂掉。这也是整篇操作里最核心、最容易被忽略的技术背景。
3.2 SE09创建请求:FORMS、TEXT、GRPH一个都不能少
传输请求在事务代码SE09(工作台请求)或SE10(请求任务)里创建。我的习惯是直接在SE09里点击“创建”按钮,请求类型选“工作台请求”,短描述写得具体一点,比如“Transmit Smart Form ZCUS_INVOICE from ECC to new system”,这样回头在传输队列里一眼就能看到这是什么。
请求创建好之后,开始添加对象。在请求的“对象”页签点“添加对象”,接下来你会看到对象类型选择界面,这就是决定成败的关键一步。按顺序添加以下对象:
- Smart Form本体:对象类型选FORMS(或者在下拉里找Smart Form/智能表单),输入表单名,回车,表单就会被加入请求。
- 文本模块:对象类型选TEXT(或Text Module/文本模块),把之前盘点出来的所有SO10文本名逐个添加进去。
- 样式:如果表单挂了样式,对象类型选STYLE,把样式名加入。
- 图形:对象类型选GRPH,把SE78里对应的图形名加入。
- 打印程序:如果打印程序也在同一传输周期内,对象类型选PROG,填入程序名。
- 表、结构、函数组:根据盘点结果,分别用TABL、STRU、FUGR等对象类型添加。
这里要特别强调一个容易踩的坑:添加对象时的事务代码可能因SAP版本不同而略有差异,如果SE09的添加对象界面里找不到对应类型,可以切换到“按开发包对象”或者“按对象目录条目(S_CTS_OBJ)”的方式,输入对象类型和名称后系统会自动校验。实在找不到,还可以在SE80的事务对象列表里右键“添加到传输请求”,效果一样。
另外,别忘了“Release”(释放)这个动作。传输请求创建后必须释放,STMS那边才能看到并导入。释放前最好用SE03(传输请求增强管理)做一次完整检查,看看有没有遗漏的对象或未激活的条目。
3.3 STMS导入目标系统与验证
请求释放之后,登录目标系统,用事务代码STMS打开传输管理界面。找到当前导入层(Import Layer)下方对应的目标系统,点进“导入队列”,你会看到从源系统传过来的请求已经在里面排队了。选中请求,点击“导入请求”按钮,模式可以选择“正式导入”或“测试导入”,建议第一次先做“测试导入”(即不实际更新系统,仅进行语法和对象检查),确认无误后再做正式导入。
导入完成后,重点验证三件事:第一,到SMARTFORMS里打开表单,看能否正常显示和编辑,如果不能激活,说明有依赖对象缺失,立刻查看激活日志定位报错对象;第二,编译并运行打印程序(事务代码SE38或直接执行程序),看英文版本能否正常预览;第三,到SE78、SO10、SE80里检查图形、文本模块、打印程序是否都已存在且状态正常。英文版本一切正常,才能证明“跨系统传输”这一步成功了,接下来才可以放心做俄语翻译。
4. 目标系统俄语翻译落地:SE63翻译实战
4.1 先检查俄语语言包:SMLT一步都不能省
之前提过,俄语翻译的前置条件是目标系统已经安装了俄语语言包。实际操作中,你可以用事务代码SMLT(语言管理)查看当前系统已安装语言列表,确认里面有没有“RU-俄语”。如果列表里没有,这一步必须先找Basis把俄语语言组件装上,否则后续SE63里建RU翻译条目时会直接报错,连保存都保存不了。
顺带说一个经验:语言组件安装完成之后,最好让Basis重启一下相关应用服务器,或者至少做一次传输配置的刷新,不然某些语言相关存储表可能没有初始化完整,翻译完运行时偶尔会出现奇怪的字符回退问题。我在项目上就碰到过一次,翻译全部保存成功,预览也没问题,但用户一打印还是英文,查了半天发现是语言包加载不完整,组件重复安装之后才好。
4.2 SE63翻译Smart Form文本元素
语言环境就绪后,进入事务代码SE63(翻译编辑器)。SE63初始屏幕可以选择不同的翻译对象类型,对Smart Form而言,我们要做两件事:翻译Smart Form自身的文本元素,以及翻译它引用的文本模块。
翻译Smart Form本体:在SE63初始屏幕选择对象类型“Smart Forms”(不同版本路径略有差异,有的版本需要从“ABAP对象”菜单下继续展开),然后输入表单名、源语言EN、目标语言RU。点进去之后,系统会列出Smart Form里所有窗口、文本元素和流逻辑中包含的硬编码文本。逐条修改成俄语,保存、激活即可。
翻译时要注意几个细节:
- 文本元素里的变量占位符(比如&WERKS&、&VBELN&)绝对不能动,无论译者怎么润色,&和&之间的内容保持原样,否则表单运行时会找不到变量。
- 带格式的文本元素(比如带有字体颜色、下划线、粗体标记的文本),翻译时尽量不要改变格式标记结构,SAP翻译编辑器一般会锁定这些无法翻译的标签,但手动修改时还是小心为妙。
- 日期、货币、数量格式在俄语环境下会自动按俄语惯例显示,如果文本中“拼接”了日期文本(比如“Date:” + &DATUM&),翻译时要把“Date:”改成俄语的“Дата:”,这个没有自动映射一说。
4.3 文本模块(SO10)的翻译
Smart Form里引用的文本模块,是通过SO10维护的独立对象,翻译方法和Smart Form自身不太一样。我习惯先到SO10里把所有相关文本查出来,看看它们有没有建过RU语言版本。大多情况下,这些文本模块在源系统里只有EN一个语言版本,到了目标系统也没有RU条目,所以需要走SE63的翻译流程。
在SE63里,对象类型选择“文本模块”(Text Module/TXMT),输入文本模块名称、源语言EN、目标语言RU,进入翻译界面后逐条处理。特别提醒:如果同一个文本模块同时被多个Smart Form引用,那么翻译一次就能覆盖所有引用位置,这个效率上是非常划算的,但也意味着你要对这个文本模块翻译质量多上心,否则所有表单一起错。
翻译完成后,回到SO10界面,用登录语言切到俄语(或者用“转到→语言”切换),确认文本模块的RU版本已经产生并且内容正确。如果SO10里RU版本不存在,多半是SE63保存时没有真正激活,需要回SE63检查保存状态。
4.4 翻译状态与语言切换验证
翻译条目创建完,一定要在Smart Form界面做一次语言切换验证。打开SMARTFORMS,进入“转到→文本元素”(或直接点击翻译图标),在语言选择里切到RU,检查表单各个窗口里的文本是否都已经显示为俄语。这里会看到SAP的语言机制:原始语言EN的文本行是“主行”,RU版本是“翻译行”,两者同时存在于表单定义中,运行时根据用户的登录语言自动选择对应语言版本的文本。
切换到RU之后,还需要实际跑一遍打印程序来验证。把登录语言改成俄语(或在用户参数里设置语言RU后重新登录),运行打印程序,用SAP打印预览(Print Preview)看效果。如果预览里俄语完全正常,再继续做真实打印或PDF导出验证,如果预览就不对,那就回到翻译/字体环节排查。
5. 俄语输出不乱码:字体与打印配置
5.1 乱码到底是表单问题还是设备问题
俄语乱码是Smart Form多语言落地时最经典的“最后一公里”故障。这种问题最大的迷惑性在于:你在SAP GUI里预览一切正常,屏幕上一行行西里尔字母清晰得很,但用户通过打印服务器真正输出到打印机时,出来的却是一堆问号、方块或者乱码。这种故障几乎可以断定不是表单翻译的问题,而是打印机设备类型的字体映射不支持西里尔字符集。反过来,如果连预览都乱码,那就要先检查表单内部的字体设置、系统语言环境以及是否存在字符集编码问题。
5.2 检查字体设置与输出设备
先看表单内部字体。在SMARTFORMS的文本元素格式、样式定义或段落/字符格式里,SAP允许指定具体的字体名(比如HELVETICA、COURIER、TIMES)和字型大小。对于俄语输出,字体名本身一般不需要特殊处理,但前提是后台输出设备(Output Device)的字体映象(Font Mapping)里为这个字体分配了支持西里尔字母的打印字体。实际操作中,我通常会先到SPAD(打印管理)里查看目标输出设备配置的设备类型和字体映象,确认有没有包含Cyrillic字体的条目。
如果是标准PDF打印,SAP会把字体作为内嵌字体嵌入PDF,西里尔字符基本不会出问题。但如果用户走的是老式ASCII打印(比如行式打印机或某些传真网关),那就必须依赖打印机硬件或软字体来渲染西里尔字符。这种情况我一般建议直接改用PDF/电子打印通道,省心省力,效果也最稳定。
5.3 PDF输出验证与最终打印
最后一步验证,我强烈建议先走一个“伪打印”流程:在打印程序里把输出设备设为PDF设备(比如LP01这种前端打印/PDF设备),生成PDF文件,用本地的Adobe Reader或浏览器预览俄语内容。PDF正常,说明Smart Form翻译和字符集都没问题,问题只可能出在真实打印设备上;PDF不正常,那问题还在表单本身,继续回去查字体格式。
如果PDF正常而真实打印机乱码,处理思路就明确多了:要么给对应输出设备增加支持Cyrillic的软字体,要么更换输出设备类型,要么干脆强制业务用户统一使用PDF打印。在投标或项目方案阶段,这个“PDF优先”的决策点一定要提前跟客户达成一致,否则最后验收时打印机型号五花八门,挨个配字体能把人磨疯。
6. 高频问题与避坑实录
6.1 请求导入报错:依赖对象不完整
这是我遇到过最多的导入失败原因。具体表现是STMS导入时报“激活对象FORMS ZXXX失败”,或者激活成功但打开表单时提示“找不到文本模块”或“找不到图形”。排查思路很简单:先回到源系统,把Smart Form所有依赖对象列个清单,逐一对照目标系统,看哪个对象缺失就把哪个补传过去。补传时要记得重新创建一个请求,把缺失对象加进去,走完释放和导入流程。特别强调一下,文本模块和图形是最容易被漏传的,这两类对象藏在表单内部,不打开看根本意识不到它们的存在。
6.2 翻译后表单还是英文
翻译保存成功,SMARTFORMS里切到RU也有内容,但运行打印程序时出来的还是英文。排查时先确认用户的登录语言是不是真的设成了RU。很多用户习惯用默认登录语言进入系统,根本没切换到俄语,Smart Form又不是按参数动态解析的,而是按运行时的登录语言加载文本版本,所以中文或英文登录环境下,自然永远显示EN内容。另一个隐蔽原因是打印程序里有用SET LOCALE或SET LANGUAGE之类语句强制语言,或者调用SSF函数时传入了固定的语言参数,这种情况下翻译再完美也白搭,只能改代码逻辑。
6.3 占位符被译者改坏导致运行时转储
这个坑最坑,因为不是每次都会立刻暴雷。如果翻译人员在润色文本时,不小心把&联系人&这种变量占位符里的内容改了,或者漏了一个&符号,Smart Form运行时就会在读取文本元素的变量替换环节出错,轻则字段显示为空,重则直接短转储(Dump)。我做过一个项目,俄语翻译后有两个字段在打印预览里是空的,查了半天才发现是译者在软件里自动纠错,把“&_WERKS&”这种带下划线变量的下划线给删了,导致变量匹配不上,SAP直接在运行时给了个“字段符号未赋值”的转储。
规避办法有两个:一是翻译交出去之前,先对表单做一次变量扫描,把所有占位符清单发给译者,明确告知“内容由系统变量控制,人工不翻译不修改”;二是翻译完成后,在SMARTFORMS里逐窗口检查一遍“变量引用一致性”,确保&...&之间的字符串跟表单全局变量定义完全一致。
6.4 一个亲历案例的复盘:从英文到俄语的全过程要点
最后复盘一下这次项目的完整流程。源系统是一个以英文为开发语言的ECC系统,目标系统是新上线的一块业务,终端用户以俄语为主。我们的任务是把发货确认单Smart Form ZINV_CONFIRM从源系统迁到目标系统,并让它在目标系统输出俄语版本。
我在源系统里花了半天做对象盘点,建了一个传输请求,把FORMS本体、6个文本模块、两个SE78图形、1个样式、2个自定义结构和1个打印程序全部打进去,释放后通过STMS在目标系统导入。英文版本在目标系统跑通后,我用了大半天做SE63翻译,文本元素30多条、文本模块6个,翻译完成后切到俄语预览,发现有两个文本模块没被翻译成功,回查是因为SE63里对象类型选错了,把文本模块选成了Smart Form的文本元素,保存到了错误的地方。修正后,俄语预览正常,但真实打印输出到用户那边还是乱码,最后定位是设备字体没有Cyrillic映射,通过切换PDF输出设备解决。
整个过程三天收工,最耗时间的不是传输也不是翻译,而是定位“打印乱码”这一个点。希望这篇能帮大家把路走顺,少花冤枉时间。