[Vue] 跟着 Vue 闯荡前端世界

笔者在套用语系时,习惯将该 key 值对应的中文语系文字当作注解一并插入,但语系文字会经常被调来调去,此时注解在画面的文字就会有不同步的情况;本文透过 C# 实践一个同步语系文字的工具,让“语系档”与“语系套用注解”永远保持一致的状态。


前言


笔者在套用语系时,习惯将该 key 值对应的中文语系文字当作注解一并插入,这样的好处是可以透过画面上的文字快速搜寻到该页面位置,并且在检视页面源代码时也会比较清楚各字段标题,不用再从 key 值去猜想了。

但语系文字经常会被调来调去,此时注解在画面的文字就会有不同步的情况,这对有点强迫症的开发人员就会很不舒服 (握拳);本文透过 C# 实践一个同步语系文字的工具,让语系档与语系注解永远保持一致的状态。

实践说明


首先将语系档以 StreamReader 开启后,透过 Regex 找出各 key-value pair 值存放在 Dictionary 中。

public Dictionary GetLangDictionary(string langPath) 
{
  var langs = new Dictionary();
  var code = string.Empty;

  using (StreamReader sr = new StreamReader(langPath))
  {
    code = sr.ReadToEnd();
    string pattern = @"(__.*): ['|`](.*)['|`]";
    MatchCollection matches = Regex.Matches(code, pattern);
    foreach (Match match in matches)
    {
      var key = match.Groups[1].Value; 
      var value = match.Groups[2].Value; 
      langs[key] = value;
    }
  }

  return langs;
}

项目中对于语系的参考都具有一致性,因此可以透过固定 pattern 将这些文字给筛选出来。

$t( '__key' /* 中文语系显示文字 */ )

使用以下 Regular Expression 来进行筛选


找出程序中有套用语系的地方后,依据取出语系的 key 值来寻找先前存入 Dictionary 的语系档文字,接着直接取代程序中的语系注解文字即可,这样就可以保持注解与语系档的一致性。

public void ReplaceLangComment(string filePath, Dictionary langs)
{
  var code = string.Empty;
  var isModified = false;
  using (StreamReader sr = new StreamReader(filePath))
  {
    code = sr.ReadToEnd();

    string pattern = @"$t(*.[`|']([sS]*?)[`|'](/*.*?*/)?.*?)";
    MatchCollection matches = Regex.Matches(code, pattern);
    foreach (Match match in matches)
    {
      string langAllText = "";
      string langKey = "";
      string langOther = "";

      langAllText = match.Value;         // ex. $t('__resetPCodeTitle'/*重设使用者名称及固定密码*/)
      langKey = match.Groups[1].Value; 	 // ex. __resetPCodeTitle
      langOther = match.Groups[2].Value; // ex. /*重设使用者名称及固定密码*/


      // 本来就没有注解就略过
      if (!langOther.Contains(@"/*"))
      { continue; }

      // 找不到语系档有对应的 key 值 (印出备查)
      if (!langs.ContainsKey(langKey.Trim()))
      {
        langKey.Dump();
        continue;
      }

      // 取出需要取代的字符串
      var startIndex = langOther.IndexOf("/*");
      var endIndex = langOther.LastIndexOf("*/");
      string replacedTarget = langOther.Substring(startIndex, endIndex - startIndex + 2);
      
      // 取出正确的语系文字
      var hasSpace = replacedTarget.Contains("/* ");
      string correctLangValue = hasSpace ? $"/* {langs[langKey.Trim()]} */" : $"/*{langs[langKey.Trim()]}*/";

      // 执行取代
      string newLangAllText = langAllText.Replace(replacedTarget, correctLangValue);
      code = code.Replace(langAllText, newLangAllText);
      isModified = true;

    }
  }

  if (isModified)
  {
    File.WriteAllText(filePath, code);
  }
}
Dump 语法为 LINQPad 使用的特殊方法,目的仅在于印出数据至画面上显示而已。

完整代码


完整代码如下,只要设定中文语系档路径位置后,再透过 Directory.GetFiles 方法过滤出需要同步语系注解的所有文件清单,逐一执行 ReplaceLangComment 进行同步即可。以下代码贴到 LINQPad 直接执行即可。


void Main()
{
  // 中文语系档位置
  var langPath = @"D:xxxsrci18ntwlang.js";
  var langs = GetLangDictionary(langPath);

  // 扫描程序目录 (取出所有 vue 档)
  string[] filePaths = Directory.GetFiles(@"D:xxxsrc", "*.vue", SearchOption.AllDirectories);
  foreach (var filePath in filePaths)
  {
    // 进行同步
    ReplaceLangComment(filePath, langs);
  }
}

public Dictionary GetLangDictionary(string langPath)
{
  var langs = new Dictionary();
  var code = string.Empty;

  using (StreamReader sr = new StreamReader(langPath))
  {
    code = sr.ReadToEnd();
    string pattern = @"(__.*): ['|`](.*)['|`]";
    MatchCollection matches = Regex.Matches(code, pattern);
    foreach (Match match in matches)
    {
      var key = match.Groups[1].Value;
      var value = match.Groups[2].Value;
      langs[key] = value;
    }
  }

  return langs;
}


public void ReplaceLangComment(string filePath, Dictionary langs)
{
  var code = string.Empty;
  var isModified = false;
  using (StreamReader sr = new StreamReader(filePath))
  {
    code = sr.ReadToEnd();

    string pattern = @"$t(*.[`|']([sS]*?)[`|'](/*.*?*/)?.*?)";
    MatchCollection matches = Regex.Matches(code, pattern);
    foreach (Match match in matches)
    {
      string langAllText = "";
      string langKey = "";
      string langOther = "";

      langAllText = match.Value;         // ex. $t('__resetPCodeTitle'/*重设使用者名称及固定密码*/)
      langKey = match.Groups[1].Value; 	 // ex. __resetPCodeTitle
      langOther = match.Groups[2].Value; // ex. /*重设使用者名称及固定密码*/


      // 本来就没有注解就略过
      if (!langOther.Contains(@"/*"))
      { continue; }

      // 找不到语系档有对应的 key 值 (印出备查)
      if (!langs.ContainsKey(langKey.Trim()))
      {
        langKey.Dump();
        continue;
      }

      // 取出需要取代的字符串
      var startIndex = langOther.IndexOf("/*");
      var endIndex = langOther.LastIndexOf("*/");
      string replacedTarget = langOther.Substring(startIndex, endIndex - startIndex + 2);
      
      // 取出正确的语系文字
      var hasSpace = replacedTarget.Contains("/* ");
      string correctLangValue = hasSpace ? $"/* {langs[langKey.Trim()]} */" : $"/*{langs[langKey.Trim()]}*/";

      // 执行取代
      string newLangAllText = langAllText.Replace(replacedTarget, correctLangValue);
      code = code.Replace(langAllText, newLangAllText);
      isModified = true;

    }
  }

  if (isModified)
  {
    File.WriteAllText(filePath, code);
  }
}


希望此篇文章可以帮助到需要的人

若内容有误或有其他建议请不吝留言给笔者喔 !