我需要为现有的经典asp网站添加语言支持
我找到的“最佳”解决方案是封装函数中的每个文本, 创建一个数据库表,其中存储每个页面的翻译并使用字典对象来检索正确的值。
示例:
<div>Welcome to xy website</div>
<button class="btn green">Login</button>
变为
<div><%=TL("Welcome to xy website")%></div>
<button class="btn" ><%=TL("Login")%></button>
然后TL功能应该是这样的
Function TL(strInput)
Dim strTargetLanguage, strPageURL,objDict,strTmp1,strTmp2
if strInput<>"" then
' First check if customer has set language.. else uses browser language
if request.cookies("culture")="" then
strTargetLanguage=lcase(left(request.servervariables("HTTP_ACCEPT_LANGUAGE"),2))
else
strTargetLanguage=lcase(left(request.cookies("culture"),2))
end if
' if User's Language is not supported....
if instr(strAcceptedLanguages,strTargetLanguage)= 0 then
strTargetlanguage="en"
end if
strPageURL=Request.ServerVariables("URL")
Set objDict=Server.CreateObject("Scripting.Dictionary")
objDict.Add "strPageUrl",strPageUrl
'Stored Procedure to load translation in the required language and for the target Page
cmd.CommandText="spDictionaryRead"
cmd.CommandType=4
cmd.Parameters("@LanguageID")=strTargetLanguage
cmd.Parameters("@PageUrl")=strPageURL
set rst=cmd.Execute()
if not rst.eof then
while not rst.eof
objDict.Add rst("txt"),rst(strTargetLanguage)
rst.movenext()
wend
end if
rst.close
if objDict.Exists(strInput)=true then
TL=objDict.Item(strInput)
else
' Custom Function to translate using google
TL=Translate(strInput,"en",strTargetLanguage)
TL=Replace(TL,"'","''")
strInput=replace(strInput,"'","''")
'Add new Sentence to Dictionary
cmd.CommandText="spDictionaryWrite"
cmd.CommandType=4
cmd.Parameters("@PageUrl")=strPageURL
cmd.Parameters("@TXT")=strInput
cmd.Parameters("@TargetLanguage")= strTargetLanguage
cmd.Parameters("@TargetText")=TL
cmd.Execute()
set objDict=nothing
end if
else
TL=""
end if
End Function
该函数尚未就绪,因为目前每次调用它都会访问数据库并加载页面的所有翻译并创建字典: 在这种情况下最好避免使用Dictionary并直接在DB中查询所需的句子。
我需要“仅”才能找到一种明智的方式将字典存储在“某处”,以避免重建它 但是要选择哪个?应用程序,Session,objVariable进入页面,???
谷歌搜索了一下我意识到应用程序不是一个明智的解决方案,原因很多,会话:我尝试保持会话非常苗条:如果我可以避免,我永远不会保存一个带有30-50个密钥的对象....除非我在页面末尾删除它(如果值得)?
有人建议将翻译加载到Application中作为“普通数组”,然后在每次需要时构建Dictionary,但在将句子加载到Dictionary中时,我可以测试当前句子是否为目标句子并在不使用Dictionary的情况下提取翻译。 。 因此,这不是一个明智的解决方案
我也读到了
Microsoft的查找组件
但找不到任何文档
也许可以使用一些.NET组件,比如HashTable?
由于我认为翻译是一个常见问题,我希望必须有一个更好的解决方案,而且我的方法是错误的:
可以提出更好的方法或一些提示吗?
答案 0 :(得分:2)
我使用Application
来缓存Classic ASP中的某些对象,通常是一个数组,其中包含从GetRows()
数据库中检索到的值。
Session
不适用,因为它仅适用于一个用户,而不是Application
等所有用户。
对于您可能想要缓存大量数据的情况,我有一个建议。
从数据库中检索值时,您可以使用文件系统对象创建一个ASP脚本,该脚本包含用于创建字典和填充值的VBScript代码。然后,您可以在所有文件中包含此生成的ASP页面。
例如,要构建缓存文件......
<%
datestamp = Year(Now()) & Month(Now()) & Day(Now()) & Hour(Now()) & Minute(Now()) & Second(Now())
set fs=Server.CreateObject("Scripting.FileSystemObject")
set tfile=fs.CreateTextFile(Server.MapPath("\cache\language_" & datestamp))
tfile.WriteLine("<%")
tfile.WriteLine("Set objDict=Server.CreateObject(""Scripting.Dictionary"")")
'...your database code here....
while not rst.eof
tfile.WriteLine("objDict.Add " & rst("txt") & ",rst(strTargetLanguage)")
rst.movenext()
wend
'...etc etc...
tfile.WriteLine("%>")
tfile.close
set tfile=nothing
set fs=nothing
Application("languagecache") = datestamp
%>
NB。文件名中的日期戳是存在的,因此在构建缓存时没有问题。
然后,在ASP页面中,您可以使用Server.Execute
...
Server.Execute("\cache\language_" & Application("languagecache"))
这只是一个例子。您还应该添加代码以确保在第一次构建缓存文件之前访问页面时,它会从始终存在的包含文件中获取内容。您还可以添加一些代码来检查上次生成缓存文件的时间,并在设定的时间后生成新的缓存文件。您可能这样做是一项计划任务,因此一些不良用户不必在构建缓存文件时等待(或者只是异步启动它)。
答案 1 :(得分:1)
前段时间我从另一位开发人员那里继承了一个项目,到目前为止,我还没有找到一种处理本地化的更有效方法。
基本前提是
将键值对存储在数据库中,我们使用的结构是包含键的keys
表和“section”(表示特定的键组)。然后我们有values
表,其中包含与FK (1:M)关系相关的特定语言的本地化。
╔══════════════════════════════════════════════════════════════════╗
║ Keys Table ║
╠══════════════╦══════════════╦═════════════════╦══════════════════╣
║ id (int, PK) ║ key (string) ║ section (string)║ editpanel (bit) ║
╚══════════════╩══════════════╩═════════════════╩══════════════════╝
╔═════════════════════════════════════════════════════════════════════╗
║ Values Table ║
╠══════════════╦═════════════════╦═════════════════╦══════════════════╣
║ id (int, PK) ║ key_id (int, FK)║ lang (string) ║ value (string) ║
╚══════════════╩═════════════════╩═════════════════╩══════════════════╝
构建ASP应用程序以从数据库中的键值对创建XML。该应用程序基本上是两页
在嵌套循环中迭代支持的语言和(在keys
表中定义)部分,这就是我们决定缓存文件逻辑分离的方法。在每次迭代中,我们通过WinHttpRequest
对象将工作传递给另一个页面。该页面返回一个XML结构,该结构是通过查看数据库并提取与正在迭代的特定部分相关的所有键值对来构建的。
正如已经提到的那样,专门为WinHttpRequest
对象调用而构建的页面在查询数据库以获取特定部分后,键值对以定制的XML结构返回它们。
存储类似
的文件结构\packs\ ┐
├ \de\
├ \es\
├ \fr\
... etc
包括数据库中支持的每种语言的子目录。这些目录需要Web应用程序标识(无论是IUSR
还是预先配置的帐户),至少具有Modify
权限,以允许创建和修改缓存的XML文件。
定制的XML文件看起来像这样
<?xml version="1.0" encoding="utf-8" ?>
<language_pack>
<strings>
<string id="391" key="connect" editpanel="0" section="email">
<![CDATA[Connect]]>
</string>
<string id="9" key="uploadimage" editpanel="0" section="common">
<![CDATA[Upload Photo]]>
</string>
<string id="12" key="notes" editpanel="0" section="common">
<![CDATA[Notes]]>
</string>
</strings>
<error_messages>
<error id="1" key="pleasebepatient">
<![CDATA[\nThis action may take a little time!\nPlease be patient.\n]]>
</error>
</error_messages>
<info>
<langcode>gb</langcode>
<langname>English</langname>
<strings>194</strings>
<time>0</time>
</info>
</language_pack>
XML文件被截断以保持简单,实际文件包含更多值
主要本地化由一个#include
文件提供支持,该文件被添加到需要支持本地化的每个页面(它只是在本地化Web应用程序中工作时成为构建过程的一部分)
#include
我们称locale.asp
与您在问题中描述的内容类似。它由各种功能组成,主要包括;
init_langpack(langcode, admin, section)
- 处理XML缓存文件的任何初始化。 langcode
只是您要加载的语言的字符串表示(整理到目录名称,de
,es
等)。 admin
确定我们是否处于“管理模式”,如果我们是,设置页眉等,行为略有不同,section
是XML文件(我们将其分为几个部分)< / em>我们想要加载到XMLDOM对象中。在加载XML时尝试访问ml_string()
之前应始终调用它。
ml_string(id, showcontrol)
- 使用我们想要输出本地化的ASP页面id
是XML / Keys表中的一个键(为什么两个?)将在位),而showcontrol
布尔值用于决定页面何时以“管理模式”显示,因此我们可以在可编辑字段中显示本地化。您可能并不总是希望这样做,因为本地化如何放置在页面中(允许您以不同方式处理它们,在下面显示一个面板等)。