经典 ASP - 网站本地化
Classic ASP - Website localization
我需要为现有的经典 asp 网站添加语言支持
我找到的"best"解决方案是将每一个文本封装在一个函数中,
创建一个数据库 table 存储每个页面的翻译并使用字典对象检索正确的值。
示例:
<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
该函数尚未就绪,因为目前每次调用它时都会访问数据库并加载页面的所有翻译并创建词典:
在这种情况下,最好避免字典并直接查询数据库以获取所需的句子。
我需要"ONLY"找到一个明智的方法来存储字典"somewhere"以避免重建它
但是选择哪个呢? Application, Session, objVariable 进入页面,???
谷歌搜索了一下,我意识到应用程序不是一个明智的解决方案,原因有很多,
Session:我尽量保持 session 非常小:如果可以避免的话,我永远不会保存一个有 30-50 个 Keys 的对象....除非我在页面本身的末尾删除它(如果它值得)?
有人建议将翻译加载到应用程序中 "plain array" 然后在每次需要时构建词典,但是在将句子加载到词典中时我可以测试当前句子是否是目标句子并在没有的情况下提取翻译使用词典..
因此这也不是一个明智的解决方案
我还阅读了
Lookup Component from Microsoft
但找不到任何文档
也许可以使用一些 .NET 组件,例如 HashTable?
既然我认为翻译是一个普遍的问题,我希望必须有更好的解决方案,而且我的做法是错误的:
能否提出更好的方法或一些提示?
我使用 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
%>
注意。文件名中的日期戳在那里,因此在构建缓存时没有问题。
然后,在您的 ASP 页面中,您可以使用 Server.Execute
...
包含最新的缓存文件
Server.Execute("\cache\language_" & Application("languagecache"))
这只是一个例子。您还应该添加代码以确保如果在第一次构建缓存文件之前访问页面,它会从始终存在的包含文件中获取内容。您还可以添加一些代码来检查上次生成缓存文件的时间,并在设定的时间后生成一个新的缓存文件。你可以这样做是一个计划任务,这样一些可怜的用户就不必等待缓存文件的构建(或者只是异步启动它)。
前段时间我从另一个开发人员那里继承了一个项目,到目前为止在 Classic ASP 我还没有找到更有效的本地化处理方式。
基本前提是
在数据库中存储键值对,我们使用的结构是一个包含键的keys
table和一个"section" (表示一组特定的键)。然后我们有我们的 values
table,其中包含通过 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
table中定义),这是如何我们决定缓存文件的逻辑分离。在每次迭代中,我们通过 WinHttpRequest
对象将工作传递到另一个页面。页面 returns 一个 XML 结构,它是通过查看数据库并提取与正在迭代的特定部分相关的所有键值对而构建的。
如前所述,专门构建了一个由 WinHttpRequest
对象调用的页面,在查询数据库中的特定部分键值对后 returns 它们在定制 XML 结构。
存储类似
的文件结构
\packs\ ┐
├ \de\
├ \es\
├ \fr\
... etc
其中包含数据库支持的每种语言的子目录。 Web Application Identity (无论是 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 应用程序中工作时,它只是成为构建过程的一部分).
我们称之为 locale.asp
的 #include
做的事情与您在问题中描述的类似。它由各种功能组成,其中主要功能包括;
init_langpack(langcode, admin, section)
- 处理 XML 缓存文件的任何初始化。 langcode
只是您要加载的语言的字符串表示形式 (整理到目录名称、de
、es
等)。 admin
确定我们是否在 "Admin Mode" 中,如果在,设置页眉等行为会略有不同,而 section
是 XML 文件 (我们将其分成几个部分) 我们要加载到 XMLDOM 对象中。在加载 XML.
时,应始终在尝试访问 ml_string()
之前调用它
ml_string(id, showcontrol)
- 使用 ASP 页面,我们要在其中输出本地化 id
是 XML / Keys table (为什么都是?,稍后会解释),而 showcontrol
布尔值用于决定页面何时显示在 "Admin Mode" 所以我们可以在 editable 字段中显示或不显示本地化。由于本地化在页面中的放置方式,您可能并不总是想这样做 (允许您以不同方式处理它们,在下方显示面板等).
我需要为现有的经典 asp 网站添加语言支持
我找到的"best"解决方案是将每一个文本封装在一个函数中, 创建一个数据库 table 存储每个页面的翻译并使用字典对象检索正确的值。
示例:
<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
该函数尚未就绪,因为目前每次调用它时都会访问数据库并加载页面的所有翻译并创建词典: 在这种情况下,最好避免字典并直接查询数据库以获取所需的句子。
我需要"ONLY"找到一个明智的方法来存储字典"somewhere"以避免重建它
但是选择哪个呢? Application, Session, objVariable 进入页面,???
谷歌搜索了一下,我意识到应用程序不是一个明智的解决方案,原因有很多,
Session:我尽量保持 session 非常小:如果可以避免的话,我永远不会保存一个有 30-50 个 Keys 的对象....除非我在页面本身的末尾删除它(如果它值得)?
有人建议将翻译加载到应用程序中 "plain array" 然后在每次需要时构建词典,但是在将句子加载到词典中时我可以测试当前句子是否是目标句子并在没有的情况下提取翻译使用词典.. 因此这也不是一个明智的解决方案
我还阅读了
Lookup Component from Microsoft
但找不到任何文档
也许可以使用一些 .NET 组件,例如 HashTable?
既然我认为翻译是一个普遍的问题,我希望必须有更好的解决方案,而且我的做法是错误的:
能否提出更好的方法或一些提示?
我使用 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
%>
注意。文件名中的日期戳在那里,因此在构建缓存时没有问题。
然后,在您的 ASP 页面中,您可以使用 Server.Execute
...
Server.Execute("\cache\language_" & Application("languagecache"))
这只是一个例子。您还应该添加代码以确保如果在第一次构建缓存文件之前访问页面,它会从始终存在的包含文件中获取内容。您还可以添加一些代码来检查上次生成缓存文件的时间,并在设定的时间后生成一个新的缓存文件。你可以这样做是一个计划任务,这样一些可怜的用户就不必等待缓存文件的构建(或者只是异步启动它)。
前段时间我从另一个开发人员那里继承了一个项目,到目前为止在 Classic ASP 我还没有找到更有效的本地化处理方式。
基本前提是
在数据库中存储键值对,我们使用的结构是一个包含键的
keys
table和一个"section" (表示一组特定的键)。然后我们有我们的values
table,其中包含通过 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
table中定义),这是如何我们决定缓存文件的逻辑分离。在每次迭代中,我们通过WinHttpRequest
对象将工作传递到另一个页面。页面 returns 一个 XML 结构,它是通过查看数据库并提取与正在迭代的特定部分相关的所有键值对而构建的。如前所述,专门构建了一个由
WinHttpRequest
对象调用的页面,在查询数据库中的特定部分键值对后 returns 它们在定制 XML 结构。
存储类似
的文件结构\packs\ ┐ ├ \de\ ├ \es\ ├ \fr\ ... etc
其中包含数据库支持的每种语言的子目录。 Web Application Identity (无论是
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 应用程序中工作时,它只是成为构建过程的一部分).
我们称之为 locale.asp
的 #include
做的事情与您在问题中描述的类似。它由各种功能组成,其中主要功能包括;
init_langpack(langcode, admin, section)
- 处理 XML 缓存文件的任何初始化。langcode
只是您要加载的语言的字符串表示形式 (整理到目录名称、de
、es
等)。admin
确定我们是否在 "Admin Mode" 中,如果在,设置页眉等行为会略有不同,而section
是 XML 文件 (我们将其分成几个部分) 我们要加载到 XMLDOM 对象中。在加载 XML. 时,应始终在尝试访问 ml_string(id, showcontrol)
- 使用 ASP 页面,我们要在其中输出本地化id
是 XML / Keys table (为什么都是?,稍后会解释),而showcontrol
布尔值用于决定页面何时显示在 "Admin Mode" 所以我们可以在 editable 字段中显示或不显示本地化。由于本地化在页面中的放置方式,您可能并不总是想这样做 (允许您以不同方式处理它们,在下方显示面板等).
ml_string()
之前调用它