一、实现思想
后台采用CSV文件的形式存储多语言的数据,然后前端通过API请求调用后端多语言接口,业务处理层对数据进行组合,最后根据匹配函数对CSV中的数据进行匹配,取出相对应的语言数据返回给前端。
二、后端 .NET CORE具体实现
- 先写一个返回给前端的ResultVM方法。
public class ResultVM
{
Int32 _Affected = 0;
object _Data;
public Boolean IsSuccess
{
get
{
if (_Data != null)
{
return true;
}
return _Affected > 0;
}
}
public Int32 Affected
{
get { return _Affected; }
set { _Affected = value; }
}
public object Data
{
get { return _Data; }
set { _Data = value; }
}
public String Message { get; set; }
public void SetMessageJson(String key, String value)
{
this.Message = "{" + String.Format("'{0}':'{1}'", key, value) + "}";
}
public void SetMessageJson(IList<String> keys, IList<Object> values)
{
if (keys.Count < 1 || values.Count < 1 || keys.Count != values.Count)
{
this.Message = "";
}
StringBuilder error = new StringBuilder();
error.Append("{");
for (int i = 0; i < keys.Count; i++)
{
error.Append("'" + keys[i] + "':'" + values[i] + "',");
}
error.Remove(error.Length - 1, 1).Append("}");
this.Message = error.ToString();
}
}
- 接着写一个读取CSV的方法,读取出来的数据转化成JSON格式。
public string OpenCSVToJson(string filePath, string AreaCode)
{
System.Text.Encoding encoding = GetType(filePath);
System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
System.IO.StreamReader sr = new System.IO.StreamReader(fs, encoding);
string strLine = "";
string[] aryLine = null;
bool IsFirst = true;
string sJson = "{";
while ((strLine = sr.ReadLine()) != null)
{
if (IsFirst == true)
{
IsFirst = false;
continue;
}
else
{
aryLine = strLine.Split(',');
if (aryLine[0].ToString() == AreaCode)
{
sJson += "\"" + aryLine[1] + "\":" + "\"" + aryLine[2] + "\",";
}
}
}
sJson = sJson.Substring(0, sJson.Length - 1) + "}";
sr.Close();
fs.Close();
return sJson;
}
public static System.Text.Encoding GetType(string FILE_NAME)
{
System.IO.FileStream fs = new System.IO.FileStream(FILE_NAME, System.IO.FileMode.Open, System.IO.FileAccess.Read);
System.Text.Encoding r = GetType(fs);
fs.Close();
return r;
}
public static System.Text.Encoding GetType(System.IO.FileStream fs)
{
byte[] Unicode = new byte[] { 0xFF, 0xFE, 0x41 };
byte[] UnicodeBIG = new byte[] { 0xFE, 0xFF, 0x00 };
byte[] UTF8 = new byte[] { 0xEF, 0xBB, 0xBF }; // With BOM
System.Text.Encoding reVal = System.Text.Encoding.Default;
System.IO.BinaryReader r = new System.IO.BinaryReader(fs, System.Text.Encoding.Default);
int i;
int.TryParse(fs.Length.ToString(), out i);
byte[] ss = r.ReadBytes(i);
if (IsUTF8Bytes(ss) || (ss[0] == 0xFF && ss[1] == 0xBB && ss[2] == 0xBF))
{
reVal = System.Text.Encoding.UTF8;
}
else if (ss[0] == 0xFE && ss[1] == 0xFF && ss[2] == 0x00)
{
reVal = System.Text.Encoding.BigEndianUnicode;
}
else if (ss[0] == 0xFF && ss[1] == 0xFE && ss[2] == 0x41)
{
reVal = System.Text.Encoding.Unicode;
}
r.Close();
return reVal;
}
public static bool IsUTF8Bytes(byte[] data)
{
int charByteCounter = 1;
byte curByte;
for (int i = 0; i < data.Length; i++)
{
curByte = data[i];
if (charByteCounter == 1)
{
if (curByte >= 0x80)
{
while (((curByte <<= 1) & 0x80) != 0)
{
charByteCounter++;
}
if (charByteCounter == 1 || charByteCounter > 6)
{
return false;
}
}
}
else
{
if ((curByte & 0xC0) != 0x80)
{
return false;
}
charByteCounter--;
}
}
if (charByteCounter > 1)
{
throw new Exception("Unexpected byte format");
}
return true;
}
- 创建一个新的API Controller,写一个接口。
/// <summary>
/// Get Multilingual To Json
/// </summary>
/// <param name="VM"></param>
/// <returns></returns>
[HttpGet]
public ResultVM GetMultilingualToJson(MultilingualVM VM)
{
return new ResultVM { Data = BL.GetMultilingualToJson(VM) };
}
- 接口接收的Model MultilingualVM,一个属性是接收前端页面的名字,一个属性是接收语言的类型(比如中文简体2052,英文1033等)
public class MultilingualVM
{
public string PageName { get; set; }
public string Category { get; set; }
}
- 创建业务逻辑层,处理接口接收到的数据。利用刚刚上面写好的读取CSV数据的方法读取对应的多语言数据。
/// <summary>
/// Get page multilingual
/// </summary>
/// <param name="VM"></param>
/// <returns></returns>
public ResultVM GetMultilingualToJson(MultilingualVM VM)
{
var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
string sResult = "{";
string[] pageNames = VM.PageName.Split(';');
foreach (string pageName in pageNames)
{
sResult += "\"" + pageName + "\":" + (ReadCSV.OpenCSVToJson(System.IO.Directory.GetCurrentDirectory() + config["MultilingualFilePath:" + "Load_" + pageName + "_Multilingual"], VM.Category)) + ",";
}
sResult = sResult.Substring(0, sResult.Length - 1) + "}";
return new ResultVM { Data = sResult };
}
至此后端的框架就已经搭建完成。
二、前端框架具体实现
前端实现思想:采用Angular前端框架做的页面往往一个页面会包含多个组件,组件之间经常会用路由来进行切换与交互。那这里就涉及到组件与组件之间交互的问题了。Angular7官网上也提供了几种可供组件与组件之间交互的方法(Angular官网通道)。我们在这里采用共享服务方式来解决这个问题。在最外层的组件作为父组件,提供服务。在里层的其他组件则作为子组件,注册服务。所以只需要让父组件去后端获取一个多语言数据,然后再分配给注册过服务的子组件们。
- 首先写一个共享服务MissionService。
@Injectable({
providedIn: 'root'
})
export class MissionService {
constructor(
private multilingualService: MultilingualService
) {
}
public languageID: any;
public arrayCSV = [];
private languageData = new Subject<any>();
languageData$ = this.languageData.asObservable();
setLanguageID(languageID: any) {
this.arrayCSV.filter(filtrate => {
filtrate.category = languageID;
this.multilingualService.getMultilingualToJson(filtrate).subscribe(
res => {
filtrate.data = JSON.parse(res.data.data);
}
);
});
this.languageData.next(this.arrayCSV);
}
getLanguageData(csvName: any): any {
let vm = { pageName: csvName, category: this.languageID, data: [] };
//check arrayCSV
if (this.arrayCSV.filter(filtrate => filtrate.pageName == csvName).length == 0) {
this.multilingualService.getMultilingualToJson(vm).subscribe(
res => {
vm.data = JSON.parse(res.data.data);
}
)
this.arrayCSV.push(vm);
}
this.languageData.next(this.arrayCSV);
}
}
- 接着写一个请求后端多语言接口的服务MultilingualService。
@Injectable({
providedIn: 'root'
})
export class MultilingualService {
constructor(
private http: HttpClient,
private generateApiUrlService: GenerateApiUrlService
) { }
getMultilingualToJson(multilingualVM: any):Observable<any>{
return this.http.get<any>(this.generateApiUrlService.getCommonApiUrl('Multilingual/GetMultilingualToJson'),{params:multilingualVM}).pipe();
}
}
}
3.写一个共享下拉框多语言组件(这里引用到了NG-ZORRO组件库中的下拉框组件,具体的引用方法可以查询官网的文档https://ng.ant.design/docs/introduce/zh)。这里会将当前多语言的类型存储在cookie中。在这个组件中提供了上面我们所建的服务MissionService,同时也引入了多语言服务MultilingualService进行多语言API请求。当组件通过MultilingualService请求后端接口接收到返回的数据时,会将数据放到共享服务上,最后共享服务会将数据分配给注册了服务的子组件中。
multilingual.component.html
<div class="psms-multilingual form-group pull-right">
<nz-select style="width: 120px;" [(ngModel)]="languageValue" (ngModelChange)="getChange($event)">
<nz-option *ngFor="let language of languages" [nzValue]="language.languageCode" [nzLabel]="language.dictDescription"></nz-option>
</nz-select>
</div>
multilingual.component.ts
export class MultilingualComponent implements OnInit {
languages = [];
languageValue: string = '1033';
constructor(
private cookieService: CookieServiceService
, private missionService: MissionService
, private multilingualService: MultilingualService
) {
this.getMultilingualSelectValue();
this.missionService.languageID = this.languageValue;
}
ngOnInit() {
}
getChange(languageCode: string): void {
this.missionService.languageID = languageCode;
this.missionService.setLanguageID(languageCode);
this.cookieService.setCookieValue('multilingual', languageCode);
}
getMultilingualSelectValue() {
this.multilingualService.getMultilingualSelectValueApi().subscribe(Response => {
this.languages = Response.data.data.table;
})
if (this.cookieService.checkCookieName('multilingual')) {
this.languageValue = this.cookieService.getMultilingualCookie().toString();
}
}
}
至此,只需要把这个多语言下拉框共享组件引用到具体的组件中,就可以获取到相对应的多语言数据了。
这里贴一张下拉框的效果图:
具体的细节有什么不理解的,可以随时提问!