实现多国语言有许多种实现方案,无外乎是一种字符串替换技术,将界面控件的文本标签替换成相应语言的文字。.NET Windows Forms实现多国语言的方法有以下几种:

1 .NET的方案,使用资源文件

分别做三个语言的资源文件,比如String.resx,String.zh-cn.resx,String.zh-tw.resx,编译程序集,运行时用下面的代码设置程序的语言区域。

string languageName="zh-cn";
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(languageName)
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(languageName)

2 使用Xml格式的资源文件

创建Xml格式的资源文件,保存一种或多种语言的字符串,运行时根据用户所选的语言进行界面标签字符串替换。

例子Xml字符串文件如下:

<?xml version="1.0"?>
<configuration>
<add key="Login" Default="Login" zhcn="登录" zhtw="登錄" />
<add key="UserId" Default="User Id" zhcn="用户编码" zhtw="使用者編碼" />
</configuration>

3 数据库方案

将语言资源字符串存放在数据库中,运行时读取并替换,这是我推荐的方案。

设计语言翻译数据库表,用于存放语言翻译内容,表结构如下:

CREATE TABLE [dbo].[LanguageTranslation]
(
[LanguageCode] [nvarchar] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[KeyText] [nvarchar] (200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL CONSTRAINT,
[DisplayText] [nvarchar] (200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[CreatedDate] [datetime] NULL,
[CreatedBy] [nvarchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[RevisedDate] [datetime] NULL,
[RevisedBy] [nvarchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[LanguageTranslation] ADD CONSTRAINT [PK_LanguageTranslation] PRIMARY KEY CLUSTERED ([LanguageCode], [KeyText]) ON [PRIMARY]
GO
EXEC sp_addextendedproperty N'MS_Description', N'翻译', 'SCHEMA', N'dbo', 'TABLE', N'LanguageTranslation', NULL, NULL
GO
EXEC sp_addextendedproperty N'MS_Description', N'语言编码
0 英语
1 繁体中文
2 简体中文
', 'SCHEMA', N'dbo', 'TABLE', N'LanguageTranslation', 'COLUMN', N'LanguageCode'
GO
EXEC sp_addextendedproperty N'MS_Description', N'索引词', 'SCHEMA', N'dbo', 'TABLE', N'LanguageTranslation', 'COLUMN', N'KeyText'
GO
EXEC sp_addextendedproperty N'MS_Description', N'显示词', 'SCHEMA', N'dbo', 'TABLE', N'LanguageTranslation', 'COLUMN', N'DisplayText'
GO
EXEC sp_addextendedproperty N'MS_Description', N'创建日期', 'SCHEMA', N'dbo', 'TABLE', N'LanguageTranslation', 'COLUMN', N'CreatedDate'
GO
EXEC sp_addextendedproperty N'MS_Description', N'建立人', 'SCHEMA', N'dbo', 'TABLE', N'LanguageTranslation', 'COLUMN', N'CreatedBy'
GO
EXEC sp_addextendedproperty N'MS_Description', N'修改日期', 'SCHEMA', N'dbo', 'TABLE', N'LanguageTranslation', 'COLUMN', N'RevisedDate'
GO
EXEC sp_addextendedproperty N'MS_Description', N'修改人', 'SCHEMA', N'dbo', 'TABLE', N'LanguageTranslation', 'COLUMN', N'RevisedBy'
GO

我以Language Code和相应的字符串为主键,Language Code的值是0,1,2,分别代表英语,繁体,简体。

字符串为界面控件标签上的文字,比如User Id, Department等。

为方便编辑字符串资源,增加一个存储过程,用于增加和修改语言资源:

SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
GO
CREATE PROCEDURE [dbo].[spAddTranslationText]
@KeyText nvarchar(200),
@EnglishText nvarchar(200),
@ChtText nvarchar(200),
@ChsText nvarchar(200)
AS
BEGIN SET NOCOUNT ON;
SET @KeyText = UPPER(@KeyText)
DELETE LanguageTranslation WHERE KEYTEXT = @KeyText INSERT LanguageTranslation (LANGUAGECODE, KEYTEXT, DISPLAYTEXT, CREATEDDATE, CREATEDBY, REVISEDDATE, REVISEDBY)
VALUES ('0', @KeyText, @EnglishText, GETDATE(), 'MIS', GETDATE(), 'MIS') INSERT LanguageTranslation (LANGUAGECODE, KEYTEXT, DISPLAYTEXT, CREATEDDATE, CREATEDBY, REVISEDDATE, REVISEDBY)
VALUES ('1', @KeyText, @ChtText, GETDATE(), 'MIS', GETDATE(), 'MIS') INSERT LanguageTranslation (LANGUAGECODE, KEYTEXT, DISPLAYTEXT, CREATEDDATE, CREATEDBY, REVISEDDATE, REVISEDBY)
VALUES ('2', @KeyText, @ChsText, GETDATE(), 'MIS', GETDATE(), 'MIS') END GO

为了简化简体到繁体的转化,调用.NET  VB类库中的方法,实现简体转化为繁体的功能,简体转化为繁体:

public string ConvertToTraditionalChinese(string label)
{
return Strings.StrConv(label, VbStrConv.TraditionalChinese, 0);
}

基本上满足需求,转换的准确率不如Word或一些在线翻译工具。

将存储过程和语言转换的方法封装起来,做成一工具,输入要翻译的资源字符串和简体翻译,生成存储过程调用。

程序启动时,设计一个翻译资源缓存字典表,分别存放对应语言的键值对。

private static Dictionary<int, DataTable> _cachedLanguageTranslation;

以下的代码从数据库中读取翻译数据到内存中,参考

DataTable languageTable = null;
DbFunctionCall isNullDisplayText = new DbFunctionCall("ISNULL", new object[] { LanguageTranslationFields.DisplayText, string.Empty });
EntityField2 displayTextField = new EntityField2("DisplayText", isNullDisplayText);
ResultsetFields fields = new ResultsetFields(2);
fields.DefineField(LanguageTranslationFields.KeyText, 0, "KeyText");
fields.DefineField(displayTextField, 1, "DisplayText"); ISortExpression sortExpression = new SortExpression(LanguageTranslationFields.KeyText | SortOperator.Ascending); using (DataAccessAdapterBase adapter = GetSystemDataAccessAdapter())
{
languageTable = new FastSerializableDataTable();
languageTable.RemotingFormat = SerializationFormat.Binary; IRelationPredicateBucket bucket = new RelationPredicateBucket();
bucket.PredicateExpression.Add(LanguageTranslationFields.LanguageCode == languageCode);
bucket.PredicateExpression.Add(displayTextField != string.Empty);
bucket.PredicateExpression.Add(LanguageTranslationFields.KeyText != displayTextField); adapter.FetchTypedList(fields, languageTable, bucket, 0, sortExpression, false);

最后,设计一个公共接口方便调用:

//Shared.cs
public static string TranslateText(string textToTranslate)
{
return LanguageTranslator.TranslateText(textToTranslate);
}

用数据库作为ERP多国语言实现方案有以下几个原因:

1  资源字符串可以被修改。这是最主要的原因,软件公司以程序员为主,没有实际的行业经验,不足以恰当(信,达,雅)的设计出各行业的翻译。产品发布到客户后,还可以修改资源字符串,不合理的地方以用户的经验为主。

2  资源字符串部署。以数据库表作为字符串资源的存储方式,部署时只需要发布SQL语句文件即可。

INSERT INTO [LanguageTranslation] ([LanguageCode],[KeyText],[DisplayText])
VALUES(N'0', N'-- PRODUCTION REQ --', N'') INSERT INTO [LanguageTranslation] ([LanguageCode],[KeyText],[DisplayText])
VALUES(N'0', N'-- LOC.TOTAL_QTY. --', N'') INSERT INTO [LanguageTranslation] ([LanguageCode],[KeyText],[DisplayText])
VALUES(N'0', N'-- LOC TOTAL_QTY. --', N'') INSERT INTO [LanguageTranslation] ([LanguageCode],[KeyText],[DisplayText])
VALUES(N'0', N'--- JOB ---', N'') INSERT INTO [LanguageTranslation] ([LanguageCode],[KeyText],[DisplayText])
VALUES(N'0', N' DR ', N'') INSERT INTO [LanguageTranslation] ([LanguageCode],[KeyText],[DisplayText])
VALUES(N'0', N' DISC. ALLOWED ', N'') INSERT INTO [LanguageTranslation] ([LanguageCode],[KeyText],[DisplayText])
VALUES(N'0', N'-------------- DEMAND --------------', N'')

写完了多国语言实现方案,意犹未尽,去Google上搜索一下stackoverflow提供的解决方案,地址是

http://stackoverflow.com/questions/373388/best-way-to-implement-multi-language-globalization-in-large-net-project

http://stackoverflow.com/questions/119568/best-practice-to-make-a-multi-language-application-in-c-winforms

这篇问答中提到几个工具,这几个工具的网站都可以打开,读者若是在寻找多国语言方案,可实际操作体会一下。

Sisulizer   http://www.sisulizer.com/

WPF LocalizationExtension  http://wpflocalizeextension.codeplex.com/

GetText http://gnuwin32.sourceforge.net/packages/gettext.htm

DBResource Provider  http://www.west-wind.com/presentations/wwDbResourceProvider/


解析大型.NET ERP系统 多国语言实现的更多相关文章

  1. 解析大型.NET ERP系统 十三种界面设计模式

    成熟的ERP系统的界面应该都是从模板中拷贝出来的,各类功能的界面有规律可遵循.软件界面设计模式化或是艺术性的创作,我认可前者,模式化的界面客户容易举一反三,降低学习门槛.除了一些小部分的功能界面设计特 ...

  2. 解析大型.NET ERP系统架构设计 Framework+ Application 设计模式

    我对大型系统的理解,从数量上面来讲,源代码超过百万行以上,系统有超过300个以上的功能,从质量上来讲系统应该具备良好的可扩展性和可维护性,系统中的功能紧密关联.除去业务上的复杂性,如何设计这样的一个协 ...

  3. 解析大型.NET ERP系统 设计异常处理模块

    异常处理模块是大型系统必备的一个组件,精心设计的异常处理模块可提高系统的健壮性.下面从我理解的角度,谈谈异常处理的方方面面.我的设计仅仅限定于Windows Forms,供参考. 1 定义异常类型 . ...

  4. 解析大型.NET ERP系统 电子邮件系统帐户集成

    为保证ERP系统的信息流准确快速的传递,需要给系统设计一个消息盒子机制.当系统中发生业务操作后,需要提醒下一个环节的操作人员,以保证ERP信息流快速准确传递.比如生产任务单(工作单,加工单,制单)过帐 ...

  5. 解析大型.NET ERP系统 权限模块设计与实现

    权限模块是ERP系统的核心模块之一,完善的权限控制机制给系统增色不少.总结我接触过的权限模块,以享读者. 1 权限的简明定义 ERP权限管理用一句简单的话来说就是:谁 能否 做 那些 事. 文句 含义 ...

  6. 解析大型.NET ERP系统 通用附件管理功能

    大型系统具备一个通用的附件管理功能,对于单据中无法清晰表达的字段,用一个附件图片或附件文档表示是最好的方法了.比如物料清单附加一张CAD图纸,销售订单评审功能中附加客户的各种表格,通用附件功能对系统起 ...

  7. 解析大型.NET ERP系统核心组件 查询设计器 报表设计器 窗体设计器 工作流设计器 任务计划设计器

    企业管理软件包含一些公共的组件,这些基础的组件在每个新项目立项阶段就必须考虑.核心的稳定不变功能,方便系统开发与维护,也为系统二次开发提供了诸多便利.比如通用权限管理系统,通用附件管理,通用查询等组件 ...

  8. 解析大型.NET ERP系统 20条数据库设计规范

    数据库设计规范是个技术含量相对低的话题,只需要对标准和规范的坚持即可做到.当系统越来越庞大,严格控制数据库的设计人员,并且有一份规范书供执行参考.在程序框架中,也有一份强制性的约定,当不遵守规范时报错 ...

  9. 解析大型.NET ERP系统 单据编码功能实现

    单据编码是ERP系统中必备的功能,用于生成各种单据的流水号,常常借助于日期时间等字符来生成一个唯一的单据号码.从软件的角度来说,就是为生成数据表的主键值(参考编号),从用户的角度来说,就是给业务单据制 ...

随机推荐

  1. CORS详解[译]

    介绍 由于同源策略的缘故,以往我们跨域请求,会使用诸如JSON-P(不安全)或者代理(设置代理和维护繁琐)的方式.而跨源资源共享(Cross-Origin Resource Sharing)是一个W3 ...

  2. 使用 Roslyn 编译器服务

    .NET Core和 .NET 4.6中 的C# 6/7 中的编译器Roslyn 一个重要的特性就是"Compiler as a Service",简单的讲,就是就是将编译器开放为 ...

  3. 0-1背包问题蛮力法求解(c++版本)

    // 0.1背包求解.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream>   #define ...

  4. CorelDRAW X8 如何破解激活(附国际版安装包+激活工具) 2016-12-15

    之前有位搞平面的好友“小瘦”说CDR X8无法破解,只能用X7.呃……呃……呃……好像是的 其实CDR8难激活主要在于一个点“没有离线激活了,只可以在线激活”,逆天不是专供逆向的,当然没能力去破解,这 ...

  5. KV存储系统

    现在的KV存储系统都是分布式的,首先介绍Zookeeper——针对大型分布式系统的高可靠的协调系统. 开发分布式系统是件很困难的事情,其中的困难主要体现在分布式系统的“部分失败”.“部分失败”是指信息 ...

  6. 【微框架】Maven +SpringBoot 集成 阿里大鱼 短信接口详解与Demo

    Maven+springboot+阿里大于短信验证服务 纠结点:Maven库没有sdk,需要解决 Maven打包找不到相关类,需要解决 ps:最近好久没有写点东西了,项目太紧,今天来一篇 一.本文简介 ...

  7. runtime梳理。

    一.runtime简介 RunTime简称运行时.OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制. 对于C语言,函数的调用在编译的时候会决定调用哪个函数. 对于OC的函数,属于 ...

  8. 《Django By Example》第一章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:本人目前在杭州某家互联网公司工作, ...

  9. 谈谈一些有趣的CSS题目(六)-- 全兼容的多列均匀布局问题

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

  10. AJAX 大全

    本章内容: 简介 伪 AJAX 原生 AJAX XmlHttpRequest 的属性.方法.跨浏览器支持 jQuery AJAX 常用方法 跨域 AJAX JsonP CORS 简单请求.复制请求.请 ...