经典ASP - 网站本地化

时间:2016-05-25 00:59:45

标签: dictionary vbscript asp-classic

我需要为现有的经典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?

由于我认为翻译是一个常见问题,我希望必须有一个更好的解决方案,而且我的方法是错误的:

可以提出更好的方法或一些提示吗?

2 个答案:

答案 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)

前段时间我从另一位开发人员那里继承了一个项目,到目前为止,我还没有找到一种处理本地化的更有效方法。

基本前提是

  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)  ║
    ╚══════════════╩═════════════════╩═════════════════╩══════════════════╝
    
  2. 构建ASP应用程序以从数据库中的键值对创建XML。该应用程序基本上是两页

    1. 在嵌套循环中迭代支持的语言和(在keys表中定义)部分,这就是我们决定缓存文件逻辑分离的方法。在每次迭代中,我们通过WinHttpRequest对象将工作传递给另一个页面。该页面返回一个XML结构,该结构是通过查看数据库并提取与正在迭代的特定部分相关的所有键值对来构建的。

    2. 正如已经提到的那样,专门为WinHttpRequest对象调用而构建的页面在查询数据库以获取特定部分后,键值对以定制的XML结构返回它们。

  3. 存储类似

    的文件结构
    \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文件被截断以保持简单,实际文件包含更多值

  4. 主要本地化由一个#include文件提供支持,该文件被添加到需要支持本地化的每个页面(它只是在本地化Web应用程序中工作时成为构建过程的一部分)

    #include我们称locale.asp与您在问题中描述的内容类似。它由各种功能组成,主要包括;

    • init_langpack(langcode, admin, section) - 处理XML缓存文件的任何初始化。 langcode只是您要加载的语言的字符串表示(整理到目录名称,dees等)admin确定我们是否处于“管理模式”,如果我们是,设置页眉等,行为略有不同,section是XML文件(我们将其分为几个部分)< / em>我们想要加载到XMLDOM对象中。在加载XML时尝试访问ml_string()之前应始终调用它。

    • ml_string(id, showcontrol) - 使用我们想要输出本地化的ASP页面id是XML / Keys表中的一个键(为什么两个?)将在位),而showcontrol布尔值用于决定页面何时以“管理模式”显示,因此我们可以在可编辑字段中显示本地化。您可能并不总是希望这样做,因为本地化如何放置在页面中(允许您以不同方式处理它们,在下面显示一个面板等)