一直以来多语言问题都是个让人头疼的问题,不是这个问题有多难,而是很繁琐,而我们目前的这个项目有点特殊,我希望最大限度的化繁为简,以下是我解决这个问题的方案。
我们的项目有这样两个前提:
1、要支持多语言但最多三种语言,一般情况下就两种语言,所以并没有随时切换语言的要求。
2、我们希望有一种可以初期不用管语言问题,之后统一翻译的方案
基于这么两点,我们提出了这样的方案:
1、初期写程序时不用关心多语言的翻译工作,只要将所有使用到中文的地方都用{}扩上
2、在数据库中Chinese会设置为唯一约束
3、所有的翻译工作会在BasePage中的Render方法中作
4、所有的页面会继承BasePage
5、翻译时会根据当前的语言设置构建以language表中Chinese做key,相应的语言为value的字典,然后查找需要翻译的字符串是不是在字典中,如果不在就生成这一行。
数据库设计四个字段
ID,Chinese,English,Other
BasePage源码
1. using System;
2. using System.Data;
3. using System.Configuration;
4. using System.Linq;
5. using System.Web;
6. using System.Web.Security;
7. using System.Web.UI;
8. using System.Web.UI.HtmlControls;
9. using System.Web.UI.WebControls;
10. using System.Web.UI.WebControls.WebParts;
11. using System.Xml.Linq;
12. using System.Text.RegularExpressions;
13. using System.Text;
14. using System.Collections;
15. using System.Collections.Generic;
16. using System.IO;
17. using System.Diagnostics;
18.
19. /// <summary>
20. ///BasePage 的摘要说明
21. /// </summary>
22. public class BasePage : System.Web.UI.Page
23. {
24. //利用Dictionary来筛选所有的多语言标签,然后做替换,可以缓存
25. Dictionary<string, string> dic;
26. public BasePage()
27. {
28.
29. }
30. //需要替换的标签,标签头为数字字母下划线汉字
31.
32. static readonly Regex re = new Regex
33. (@"((\{)|(\%7B))[\w\-\+\|u4e00-\u9fa5]+?((\})|(\%7D))",
34. RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
35.
36. //不需要替换的标签
37. static readonly Regex re_nr = new
38. Regex(@"<NOREPLACE>[\w\W]*?</NOREPLACE>", RegexOptions.Multiline | RegexOptions.IgnoreCase);
39.
40. private string RenderTag(ref string content)
41. {
42. if (re_nr.IsMatch(content))//不需要替换标签
43. {
44. StringBuilder sb = new StringBuilder();
45.
46. MatchCollection grouplist = re_nr.Matches(content);
47. string[] reList = re_nr.Split(content);
48.
49. for (int i = 0; i < grouplist.Count; i++)
50. {
51. sb.Append(ReplaceTag(ref reList[i]));
52. sb.Append(grouplist[i].Value);
53. sb.Append(ReplaceTag(ref reList[i + 1]));
54. }
55.
56. content = sb.ToString();
57. }
58. else
59. {
60. content = ReplaceTag(ref content);
61. }
62. return content;
63. }
64.
65. private string ReplaceTag(ref string content)
66. {
67. //模板标签{yes},{no},{search}
68. MatchCollection mc = re.Matches(content);
69.
70. if (dic == null)
71. {
72. dic = LanguageManager.GetResource();
73. }
74.
75. for (int i = 0; i < mc.Count; i++)
76. {
77. //如果数据库中还没有此字符串
78. if (!dic.ContainsKey(mc[i].Value.TrimStart('{').TrimEnd('}')))
79. {
80. content = content.Replace(mc[i].Value, mc[i].Value.TrimStart('{').TrimEnd('}'));
81.
82. if (!dic.ContainsKey(mc[i].Value.TrimStart('{').TrimEnd('}')))
83. {
84. LanguageManager.AddLanguageString(mc[i].Value.TrimStart('{').TrimEnd('}'));
85. }
86. }
87. else if (dic[mc[i].Value.TrimStart('{').TrimEnd('}')] == null)
88. {
89. content = content.Replace(mc[i].Value, "$$$$");
90. }
91. else
92. {
93.
94. content = content.Replace(mc[i].Value, dic[mc[i].Value.TrimStart('{').TrimEnd('}')].ToString());
95.
96.
97. }
98. }
99. dic.Clear();
100. return content;
101. }
102. protected override void Render(HtmlTextWriter writer)
103. {
104.
105. Stopwatch stopwatch = new Stopwatch();
106. stopwatch.Reset();
107. stopwatch.Start();
108. try
109. {
110. //会把页面的输出结果存储在这个StringBuilder中
111. StringBuilder sb = new StringBuilder();
112. StringWriter sw = new StringWriter(sb);
113. HtmlTextWriter htw = new HtmlTextWriter(sw);
114. base.Render(htw);
115. string content = sb.ToString();
116.
117. content = RenderTag(ref content);
118.
119. //重新写入页面
120. writer.Write(content);
121.
122. }
123. catch (Exception ex)
124. {
125. Response.Write(ex.ToString());
126. Response.End();
127. }
128. finally
129. {
130. stopwatch.Stop();
131. Response.Write("runtime:" + stopwatch.ElapsedMilliseconds.ToString() + "ms");
132. }
133.
134. }
135. }
2. using System.Data;
3. using System.Configuration;
4. using System.Linq;
5. using System.Web;
6. using System.Web.Security;
7. using System.Web.UI;
8. using System.Web.UI.HtmlControls;
9. using System.Web.UI.WebControls;
10. using System.Web.UI.WebControls.WebParts;
11. using System.Xml.Linq;
12. using System.Text.RegularExpressions;
13. using System.Text;
14. using System.Collections;
15. using System.Collections.Generic;
16. using System.IO;
17. using System.Diagnostics;
18.
19. /// <summary>
20. ///BasePage 的摘要说明
21. /// </summary>
22. public class BasePage : System.Web.UI.Page
23. {
24. //利用Dictionary来筛选所有的多语言标签,然后做替换,可以缓存
25. Dictionary<string, string> dic;
26. public BasePage()
27. {
28.
29. }
30. //需要替换的标签,标签头为数字字母下划线汉字
31.
32. static readonly Regex re = new Regex
33. (@"((\{)|(\%7B))[\w\-\+\|u4e00-\u9fa5]+?((\})|(\%7D))",
34. RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
35.
36. //不需要替换的标签
37. static readonly Regex re_nr = new
38. Regex(@"<NOREPLACE>[\w\W]*?</NOREPLACE>", RegexOptions.Multiline | RegexOptions.IgnoreCase);
39.
40. private string RenderTag(ref string content)
41. {
42. if (re_nr.IsMatch(content))//不需要替换标签
43. {
44. StringBuilder sb = new StringBuilder();
45.
46. MatchCollection grouplist = re_nr.Matches(content);
47. string[] reList = re_nr.Split(content);
48.
49. for (int i = 0; i < grouplist.Count; i++)
50. {
51. sb.Append(ReplaceTag(ref reList[i]));
52. sb.Append(grouplist[i].Value);
53. sb.Append(ReplaceTag(ref reList[i + 1]));
54. }
55.
56. content = sb.ToString();
57. }
58. else
59. {
60. content = ReplaceTag(ref content);
61. }
62. return content;
63. }
64.
65. private string ReplaceTag(ref string content)
66. {
67. //模板标签{yes},{no},{search}
68. MatchCollection mc = re.Matches(content);
69.
70. if (dic == null)
71. {
72. dic = LanguageManager.GetResource();
73. }
74.
75. for (int i = 0; i < mc.Count; i++)
76. {
77. //如果数据库中还没有此字符串
78. if (!dic.ContainsKey(mc[i].Value.TrimStart('{').TrimEnd('}')))
79. {
80. content = content.Replace(mc[i].Value, mc[i].Value.TrimStart('{').TrimEnd('}'));
81.
82. if (!dic.ContainsKey(mc[i].Value.TrimStart('{').TrimEnd('}')))
83. {
84. LanguageManager.AddLanguageString(mc[i].Value.TrimStart('{').TrimEnd('}'));
85. }
86. }
87. else if (dic[mc[i].Value.TrimStart('{').TrimEnd('}')] == null)
88. {
89. content = content.Replace(mc[i].Value, "$$$$");
90. }
91. else
92. {
93.
94. content = content.Replace(mc[i].Value, dic[mc[i].Value.TrimStart('{').TrimEnd('}')].ToString());
95.
96.
97. }
98. }
99. dic.Clear();
100. return content;
101. }
102. protected override void Render(HtmlTextWriter writer)
103. {
104.
105. Stopwatch stopwatch = new Stopwatch();
106. stopwatch.Reset();
107. stopwatch.Start();
108. try
109. {
110. //会把页面的输出结果存储在这个StringBuilder中
111. StringBuilder sb = new StringBuilder();
112. StringWriter sw = new StringWriter(sb);
113. HtmlTextWriter htw = new HtmlTextWriter(sw);
114. base.Render(htw);
115. string content = sb.ToString();
116.
117. content = RenderTag(ref content);
118.
119. //重新写入页面
120. writer.Write(content);
121.
122. }
123. catch (Exception ex)
124. {
125. Response.Write(ex.ToString());
126. Response.End();
127. }
128. finally
129. {
130. stopwatch.Stop();
131. Response.Write("runtime:" + stopwatch.ElapsedMilliseconds.ToString() + "ms");
132. }
133.
134. }
135. }