如何实现多语言数据库设计?

多语言访问数据库

概括

我被问过很多次要产生可用于不同语言的数据库,例如英语,法语,葡萄牙语,德语,挪威语等。

我已经为此开发了一个系统,现在与您分享。

该系统将允许您以用户选择的语言显示所有表格,报告,代码内消息等。

我提供了一个精简的Access 2003数据库,其中包含所有代码和表以及一个可以用英语或葡萄牙语显示的虚拟主菜单。

它最初是在Access 2中开发的,直到Access 2003才可以使用。没有理由为什么它不能在Access 2007中工作。

必须感谢Paul Litwin,他在多年前的Access Developers Conference上给了我最初的构想。

假设

我假设一个拆分的数据库,每台PC上的代码,服务器上的共享数据,每台PC可以运行不同的语言。

我假设开发是用英语完成的。 将英语更改为法语,或者用其他语言开发。

局限性

该系统不允许翻译输入的数据。

该系统实际上不进行翻译; 这必须由语言学家在表格中输入。

该系统不会翻译Windows或访问生成的消息(例如错误消息或消息框中的是/否/确定),您必须运行Windows的法语或西班牙语等版本,并为此运行Access。

如果使用此系统翻译成非罗马语言,例如阿拉伯语,俄语(或我的情况是泰卢固语),则必须安装Windows XP的相应语言支持。

每个短语或文本部分的字符数上限为255个字符(除非您需要大量的备忘录记录)。

概念

需要一个表格来保存所有要显示在系统中任何地方的文本,该表格可以用所有选定的语言来保存此文本。

该表是tblTranslate,包含翻译键,文本来源的上下文,英文文本以及每种其他语言的字段。

然后需要一种方法来检索此文本并以所选语言显示它。 一种方法不能完成所有工作,实际上此系统中使用了3种方法。

可以通过以下方式在Access数据库中显示文本。

  • 表格和报告的标题。
  • 消息的代码。
  • 选项列表针对表中的字段,例如,“您有医院吗?”没有;不知道”。
  • 终端用户输入的数据。

此处不考虑最终用户输入的数据。 如果要使用多语言,则为每个用户创建字段,然后让用户输入每种语言。

选项列表。 我编写的数据库倾向于提供大量设置选项供用户选择。 通常,这些字段将作为字段名称的值列表内置到表中,但是现在它们本身必须是查找表。 每个查找表具有相同的字段名称。 我将在后面详细解释。

代码中的消息。 而不是使用msgbox“这是我的消息”,我使用msgbox strTranslate(“ TR0000003”),其中TR000003是tblTranslate中英文文本“ This is my message”的键,而strTranslate是一个例程,我将在后面解释。

表格和报告的标题

这是一个聪明的地方。 每个控件,表单,子表单,报表,页眉,页脚等都具有TAG属性。 Access完全没有使用它,并且在此标记属性中,我将“ TRxxxxxx”键放入了转换表。

这一切听起来非常繁琐和复杂,这就是为什么我编写了例程以使其尽可能自动执行的原因。

因此,让我们开始吧。

表的创建

在后端数据库中,您需要创建以下内容:

tblLanguage是保存语言列表的表。 它包括以下字段:

语言,文本字段,主键。 这是英语的语言名称。 这也将是下一个表中的字段名,因此请保持名称合理。 English-USA可以,而English(“ USA”)则不能,因为它不能成为字段名称。

trKey,文本字段。 它具有翻译键,用于将语言名称本身翻译成其他语言,即IE。 英语,角度,英格尔斯。

tblTranslate是包含所有语言的系统所有语言数据的表​​。 它具有以下字段。

trKey,文本字段,主键。 在我的设计中,“ TR”后跟九位数字。

上下文,文本字段。 未在系统中使用,但是由开发人员(和语言翻译)用来确定文本的来源。

英语,文本字段。 文本的英文版。 必填字段。

然后是:

葡萄牙语

法文

等等

其名称必须与上面的tblLanguage中的条目完全匹配的所有文本字段。

这些字段是必填文本,默认条目为“等待翻译”。

上面的表保存了翻译信息,您还将需要一组查找表来保存所需的数据。 例如,您可能有一个询问是/否问题的字段,或者一个期望答案的字段是母亲,父亲,姐妹,兄弟。

存储在数据库中的实际数据将是一个数字,链接到文本字段。 例如,报告中的问题可能看起来像这样。


Q21   Who was present at the incident    0=No-one
                                         1=Mother
                                         2=Father
                                         3=Sister

在数据输入表单上,将出现一个列出上述选项的组合框。 这些选项存储在查找表中。

对于每个查找列表,您都需要创建一个以tlk为前缀的表。 例如。 tlkYesNO,tlkRelation。

这些tlk表必须都具有完全相同的字段名称和结构(以方便以后添加选项),如下所示:


Field        Type      Comment
option_id    Byte      Primary key, number will be stored in main tableB
option_name  Text      The English text to be displayed (actual text will come from tblTranslate)
trKey        Text(11)  The key to tblTranslate for this data

然后用数据填充表,然后在行中向tblTranslate添加行。

对于系统的前端,在多用户系统中的每台PC上,只需要一个表。

TlkText具有以下字段


Field    Type
trKey    Text(11)  Primary key, will be copied from tblTranslate
trText   Text      Local language text, copied from tblTranslate

因此,我们创建了表。 我们如何使用它们?

如上所述,有三种类型的数据要显示。

查找列表存储在tlkxxxxx中,文本消息以代码,标签和文本形式写在表单和报表上。

对于查找列表,查找表包含trKey,它指向tlkTranslate中的一条记录。

对于文本消息,使用以下函数strTranslate。

使用例


        MsgBox strTranslate("TR000000131", "Record Not Saved")
功能

Function strTranslate(ByVal strKey As String, Optional RealText As String = "") As String
On Error GoTo strTranslate_Err
'takes the tran key and returns local text. RealText is ignored
'check key in right format
If Len(strKey) = 11 And Left(strKey, 2) = "TR" Then
    strTranslate = DLookup("trText", "tlkText", "trKey='" & strKey & "'")
Else
    strTranslate = "Invalid Translation Key"
End If
strTranslate_Exit:
    Exit Function
strTranslate_Err:
    MsgBox Err.Description
    Resume strTranslate_Exit 
End Function

请记住,tlkText是tlkTranslate的本地版本,以用户选择的语言保存数据。

对于查找表和文本消息,都必须手动输入trKey的下一个值。

最后是表单和报表上的标签和文本。

如果您不希望翻译特定的标签,请在该标签的Tag属性中输入“请勿翻译”,否则,请不要理会它。

完成几天的编码后,或每当要添加最新翻译时,请从立即窗口运行以下代码。

AccessAllForms“设置”

这将调用其他两个例程,即setformtags和setrpttags。

AccessAllForms“ Clear”删除所有标签,并且非常最终!


Sub AccessAllForms(strSetOrClear As String)
On Error GoTo AccessAllForms_Err
'this opens, for edit, all forms in the system, and then sets tags
If strSetOrClear <> "Set" And strSetOrClear <> "Clear" Then Exit Sub
Dim i As Integer, j As Integer
Dim db As Database
Dim frm As Form, rpt As Report
Set db = CurrentDb
For i = 0 To db.Containers.Count - 1
    If db.Containers(i).Name = "Forms" Then
        For j = 0 To db.Containers(i).Documents.Count - 1
            DoCmd.OpenForm db.Containers(i).Documents(j).Name, acDesign
               Set frm = Forms(db.Containers(i).Documents(j).Name)
               If strSetOrClear = "Set" Then
                   setformtags frm
                Else
                    clearformtags frm
                End If
            DoCmd.Close acForm, db.Containers(i).Documents(j).Name, acSaveYes
        Next
    End If
    If db.Containers(i).Name = "Reports" Then
        For j = 0 To db.Containers(i).Documents.Count - 1
            DoCmd.OpenReport db.Containers(i).Documents(j).Name, acDesign
               Set rpt = Reports(db.Containers(i).Documents(j).Name)
               If strSetOrClear = "Set" Then
                   setrpttags rpt
                Else
                   clearrpttags rpt
                End If
            DoCmd.Close acReport, db.Containers(i).Documents(j).Name, acSaveYes
        Next
    End If
Next
Set db = Nothing 
AccessAllForms_Exit:
   Exit Sub
AccessAllForms_Err:
   MsgBox Err.Description & " in AccessAllForms"
   Resume AccessAllForms_Exit
End Sub

上面的代码遍历表单和报表容器,并为每个表单和报表调用适当的例程。

对于表格:


Sub setformtags(frm As Form)
On Error GoTo setformtags_Err
'Mark Fisher
'This finds each control on the form that carries a caption and
'puts the caption in the trans table and fills in the tag property
'
'it ignores tags already set
'
Dim ctl As Control, prt As Property, strKey As String
Dim db As Database, strSQL As String
Set db = CurrentDb 
For Each ctl In frm.Controls
'go through every control
    For Each prt In ctl.Properties
    'find correct property
        If prt.Name = "Caption" Then
        'only look at controls that have a caption
            If Len(prt.Value & "") > 1 Then
            'only look at controls that have data in the caption
                If Len(ctl.Tag & "") = 0 Or ctl.Tag = "DetachedLabel" Then
                'only look at controls that we have not touched yet
                    strKey = nextseq()
                    strSQL = "INSERT INTO tlkTranslate ( trKey, context, English ) SELECT '" & strKey & "' AS Expr1, '" & frm.Name & ":" & ctl.Name & "' AS Expr2, " & Chr(34) & prt.Value & Chr(34) & " AS Expr3;"
                    db.Execute (strSQL)
                    ctl.Tag = strKey
                End If
            End If
        End If
    Next
Next
If Len(frm.Tag & "") = 0 Then
'set the form tag
    strKey = nextseq()
    strSQL = "INSERT INTO tlkTranslate ( trKey, context, English ) SELECT '" & strKey & "' AS Expr1, '" & frm.Name & ":Header' AS Expr2, " & Chr(34) & frm.Caption & Chr(34) & " AS Expr3;"
    db.Execute (strSQL)
    frm.Tag = strKey
End If 
Set db = Nothing
setformtags_Exit:
   Exit Sub
setformtags_Err:
   MsgBox Err.Description & " in setformtags"
   Resume setformtags_Exit
End Sub
Nextseq()用于按顺序获取下一个键:

Function nextseq() As String
On Error GoTo nextseq_Err
'this generates the next trans key
nextseq = "TR" & Format(Val(Right(DMax("trkey", "tlkTranslate"), 9)) + 1, "000000000")
nextseq_Exit:
   Exit Function
nextseq_Err:
   MsgBox Err.Description & " in nextseq"
   Resume nextseq_Exit
End Function
对于报告,代码几乎相同

Sub setrpttags(rpt As Report)
On Error GoTo setrpttags_Err
'Mark Fisher
'This finds each control on the report that carries a caption and
'puts the caption in the trans table and fills in the tag property
'
'it ignores tags already set
Dim ctl As Control, prt As Property, strKey As String
Dim db As Database, strSQL As String
Set db = CurrentDb 
For Each ctl In rpt.Controls
'go through every control
    For Each prt In ctl.Properties
    'find correct property
        If prt.Name = "Caption" Then
        'only look at controls that have a caption
            If Len(prt.Value & "") > 0 Then
            'only look at controls that have data in the caption
                If Len(ctl.Tag & "") = 0 Or ctl.Tag = "DetachedLabel" Then
                'only look at controls that we have not touched yet
                    strKey = nextseq()
                    strSQL = "INSERT INTO tlkTranslate ( trKey, context, English ) SELECT '" & strKey & "' AS Expr1, '" & rpt.Name & ":" & ctl.Name & "' AS Expr2, " & Chr(34) & prt.Value & Chr(34) & " AS Expr3;"
                    db.Execute (strSQL)
                    ctl.Tag = strKey
                End If
            End If
        End If
    Next
Next
If Len(rpt.Tag & "") = 0 Then
'set the report tag
    strKey = nextseq()
    strSQL = "INSERT INTO tlkTranslate ( trKey, context, English ) SELECT '" & strKey & "' AS Expr1, '" & rpt.Name & ":Header' AS Expr2, " & Chr(34) & rpt.Caption & Chr(34) & " AS Expr3;"
    db.Execute (strSQL)
    rpt.Tag = strKey
End If 
Set db = Nothing
setrpttags_Exit:
   Exit Sub
setrpttags_Err:
   MsgBox Err.Description & " in setrpttags"
   Resume setrpttags_Exit
End Sub
一旦您拥有数十或数百个表单和报表,AccessAllForms可能需要一些时间来运行,所以去喝杯咖啡,稍后再回来:)

好的,所以现在我们有了一个系统,其中所有可显示的文本都以英语存储在tlkTranslate中,而所有其他字段都与“ Waiting Translation”一起存储。

现在,我们将数据库发送给我们的语言学家,该语言学家使用简单的表格frmTranslateLive来显示所有尚未翻译的文本,以及上下文字段和英文文本,然后由他或她将其一一翻译。

在这一点上,我应该指出该系统的局限性。 每个词组或一段文字都不能超过255个字符,包括空格等。

好的,现在所有内容都已翻译,我们如何使用它。

使用系统

在主菜单上是一个按钮,选择语言。 这将打开一个简单的表单,显示一个组合框,该组合框列出了表tblLanguage中的语言名称。 选择后,将运行以下代码。


Private Sub cboLanguage_AfterUpdate()
On Error GoTo cboLanguage_AfterUpdate_Err
'this will delete the existing text data and load in the new one
Dim db As Database, strSQL As String
Set db = CurrentDb
db.Execute ("DELETE tlkText.* FROM tlkText;") 
strSQL = "INSERT INTO tlkText ( trKey, trText )SELECT trKey, " & cboLanguage & " FROM tlkTranslate;"
db.Execute (strSQL)
db.Execute ("UPDATE tblGlobalCode SET tblGlobalCode.[Language] = '" & cboLanguage & "';")
Set db = Nothing
formtran Forms!fmnuMainMenu
DoCmd.Close
cboLanguage_AfterUpdate_Exit:
   Exit Sub
cboLanguage_AfterUpdate_Err:
   MsgBox Err.Description & " in cboLanguage_AfterUpdate"
   Resume cboLanguage_AfterUpdate_Exit
End Sub

这会将适当的语言从共享的后端数据库复制到本地PC。

tblGlobalCode是保存用户特定数据的本地表。 它需要知道本地语言对于某些更复杂的操作是什么,例如运行telegu或阿拉伯语脚本,这超出了本文的范围。

因此,如何显示新语言。

好吧,对于文本消息,上面列出的strTranslate可以完成这项工作。

对于报表和组合框,tlkxxxx表链接到tlkText。

例如,

询问多胎的问题将使用此方法:


SELECT tlkMultipleBirth.option_id, tlkText.trText FROM tlkMultipleBirth INNER JOIN tlkText ON tlkMultipleBirth.trkey=tlkText.trKey;
用英语给出:

option_id  trText
1          SINGLE
2          TWIN
3          TRIPLET
4          Quads
8          Don't know
9          No Data Entered
或者这个葡萄牙语

option_id  trText
1          ÚNICO
2          GÊMEOS 
3          TRIGÊMEO
4          Quadruplo
8          Não sabe
9          Sem dado preenchido

对于表单和报表,我有两个函数在表单或报表打开事件中调用。

Formtran我或reporttran我。


Private Sub Form_Open(Cancel As Integer)
On Error GoTo Form_Open_Err
formtran Me
'called by more than one form. If not cluster, then
    'table name/clusterid/formname/tabanca id/household blah blah

Sub formtran(frm As Form)
On Error GoTo formtran_Err
'This returns the language text for each tagged control
Dim ctl As Control 
For Each ctl In frm.Controls
    If Len(ctl.Tag & "") > 0 Then
    'only look at controls that are tagged
        If Left(ctl.Tag, 2) = "TR" Then
        'make sure we have the correct tag
            ctl.Caption = nulltostring(DLookup("trText", "tlkText", "trKey='" & ctl.Tag & "'"))
        End If
    End If
Next 
If Len(frm.Tag & "") > 0 Then
    frm.Caption = nulltostring(DLookup("trText", "tlkText", "trKey='" & frm.Tag & "'"))
End If 
formtran_Exit:
   Exit Sub
formtran_Err:
   MsgBox Err.Description & " in formtran"
   Resume formtran_Exit
End Sub

Function nulltostring(varTXT As Variant) As String
On Error GoTo nulltostring_Err
'converts null value to empty string
If IsNull(varTXT) Then
    nulltostring = ""
Else
    nulltostring = varTXT
End If
nulltostring_Exit:
   Exit Function
nulltostring_Err:
   MsgBox Err.Description & " in nulltostring"
   Resume nulltostring_Exit
End Function
对于报告:

Sub reportTran(rpt As Report)
On Error GoTo reportTran_Err
'This returns the language text for each tagged control
Dim ctl As Control 
For Each ctl In rpt.Controls
    If Len(ctl.Tag & "") > 0 Then
    'only look at controls that are tagged
        If Left(ctl.Tag, 2) = "TR" Then
        'make sure we have the correct tag
            ctl.Caption = nulltostring(DLookup("trText", "tlkText", "trKey='" & ctl.Tag & "'"))
        End If
    End If
Next 
If Len(rpt.Tag & "") > 0 Then
    rpt.Caption = nulltostring(DLookup("trText", "tlkText", "trKey='" & rpt.Tag & "'"))
End If
reportTran_Exit:
   Exit Sub
reportTran_Err:
   MsgBox Err.Description & " in reportTran"
   Resume reportTran_Exit
End Sub

朋友们,就是这样!

结论

该系统可以将数据库的最终用户快速(即时)转换为任何罗马风格的语言。

它可以用于其他脚本,例如阿拉伯文,俄文,希腊文,泰卢固文等,但是对于这种情况,需要更多的工作,超出本文的范围。

设置有点繁琐,如果要更改一段文本(例如标签),则必须记住也要更改tlkTranslate的翻译,但是,如果您使用英语,则数据输入人员会说葡萄牙语,您的现场工作人员只会说Kriol,您别无选择,只能建立一个多语言的系统。

每个短语或消息的上限为255个字符!

我再次感谢Paul Litwin,他在很多年前向我展示了原始概念。

您可以随意使用和修改此系统,但如果您确实使用它,我将感谢我的名字和公司作为来源。

Attched是我的数据库之一,去除了大部分功能和数据,但保留了所有翻译代码和一份数据输入表格和一份报告,以便您可以实际使用它。 显然,在正常使用中,除tlkText和tblGlobalCode之外的所有表都位于后端数据库中。

附加的文件
文件类型:zip MultiLingualSample.zip (1.79 MB,3778视图)

From: https://bytes.com/topic/access/insights/908560-how-implement-multi-lingual-database

你可能感兴趣的:(如何实现多语言数据库设计?)