后台采用CSV文件的形式存储多语言的数据,然后前端通过API请求调用后端多语言接口,业务处理层对数据进行组合,最后根据匹配函数对CSV中的数据进行匹配,取出相对应的语言数据返回给前端。
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(); } }
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; }
/// <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) }; }
public class MultilingualVM { public string PageName { get; set; } public string Category { get; set; } }
/// <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官网通道)。我们在这里采用共享服务方式来解决这个问题。在最外层的组件作为父组件,提供服务。在里层的其他组件则作为子组件,注册服务。所以只需要让父组件去后端获取一个多语言数据,然后再分配给注册过服务的子组件们。
@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); } }
@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(); } } }
至此,只需要把这个多语言下拉框共享组件引用到具体的组件中,就可以获取到相对应的多语言数据了。
这里贴一张下拉框的效果图:
具体的细节有什么不理解的,可以随时提问!