有没有办法可以自动创建用于语言翻译的.json文件?

时间:2015-05-08 14:12:55

标签: javascript json angularjs powershell angular-translate

我有这样的文件,它们有翻译键和值:

locale-en.json
{
    "CHANGE_PASSWORD": "Change Password",
    "CONFIRM_PASSWORD":  "Confirm Password",
    "NEW_PASSWORD": "New Password"
}

locale-jp.json
{
    "CHANGE_PASSWORD": "パスワードを変更します",
    "CONFIRM_PASSWORD":  "パスワードを認証します",
    "NEW_PASSWORD": "新しいパスワード"
}

例如,当我向包含英语翻译的JSON文件添加新的翻译密钥时,我必须记住将该密钥和相关翻译添加到所有其他JSON文件中。所有JSON文件也都单独编辑。这个过程既费力又容易出错。

有没有人找到减少错误和自动化过程的方法。

理想情况下,我希望能够从Windows PowerShell运行一个脚本,如果在locale-en.json中添加了一个额外的密钥,该脚本会将文件更改为:

locale-en.json
{
    "CHANGE_PASSWORD": "Change Password",
    "CONFIRM_PASSWORD":  "Confirm Password",
    "NEW_PASSWORD": "New Password",
    "NEW_KEY": "New Key"
}

locale-jp.json
{
    "CHANGE_PASSWORD": "パスワードを変更します",
    "CONFIRM_PASSWORD":  "パスワードを認証します",
    "NEW_PASSWORD": "新しいパスワード",
    >>>"NEW_KEY": "New Key"
}

4 个答案:

答案 0 :(得分:10)

你可以在powershell中写下这样的东西:

$masterFile = "locale-en.json"

function Get-LocaleMap($file){

    $map = @{}

    $localeJson = ConvertFrom-Json (gc $file -Raw)
    $localeJson | gm -MemberType NoteProperty | % {
        $map.Add($_.Name, ($localeJson | select -ExpandProperty $_.Name))
    }

    return $map
}

$masterLocale = Get-LocaleMap $masterFile

ls | ? { $_.Name -like "locale-*.json" -and $_.Name -ne $masterFile } | % {
    $locale = Get-LocaleMap $_.FullName
    $masterLocale.GetEnumerator() | % {
        if(!$locale.ContainsKey($_.Key)){
            $locale.Add($_.Key, $_.Value)
        }
    }

    ConvertTo-Json $locale | Out-File -FilePath $_.FullName -Force -Encoding utf8
}

它从您的英文json文件创建了一个字典。然后,它会查找所有其他语言环境文件,并检查它们是否存在于英语文件中但却从中丢失的键。然后,它添加缺少的键和值,并以Unicode格式保存语言环境文件。

让我向您展示如何使用旧式Windows Scripting执行相同操作,因为您似乎更喜欢JavaScript:

var masterFile = "locale-en.json"
var fso = new ActiveXObject("Scripting.FileSystemObject");
var scriptPath = fso.GetParentFolderName(WScript.ScriptFullName);
var charSet = 'utf-8';
var f = fso.GetFolder(scriptPath);
var fc = new Enumerator(f.files);

function getLocaleMap(fileName){
    var path = scriptPath + '\\' + fileName;
    var stream = new ActiveXObject("ADODB.Stream"); // you cannot use fso for utf-8

    try{
        stream.CharSet = charSet;
        stream.Open();
        stream.LoadFromFile(path);
        var text = stream.ReadText();
        var json = {};
        eval('json = ' + text); // JSON.parse is not available in all versions
        return json;
    }
    finally{
        stream.Close();
    }
}

function saveAsUtf8(fileName, text){
    var path = scriptPath + '\\' + fileName;
    var stream = new ActiveXObject("ADODB.Stream"); 

    try{
        stream.CharSet = charSet;
        stream.Open();
        stream.Position = 0;
        stream.WriteText(text);
        stream.SaveToFile(path, 2); // overwrite
    }
    finally{
        stream.Close();
    }
}

var locales = [];
var masterMap = getLocaleMap(masterFile);

for (; !fc.atEnd(); fc.moveNext())
{
    var file = fc.item();
    var extension = file.Name.split('.').pop();
    if(extension != "json" || file.Name == masterFile){
       continue;
    }

    var map = getLocaleMap(file.Name);
    var newLocaleText = '{\r\n';
    var i = 0;

    for(var name in masterMap){
        var value = '';

        if(map[name]){
            value = map[name];
        }
        else{
            value = masterMap[name];
        }

        if(i > 0){
            newLocaleText += ",\r\n";
        }

        newLocaleText += "\t'" + name + "': '" + value + "'";
        i++;
    }

    newLocaleText += '\r\n}'

    saveAsUtf8(file.Name, newLocaleText);
}

您可以从命令行运行javascript,如下所示:

Cscript.exe "C:\yourscript.js"

我希望它有所帮助。

答案 1 :(得分:6)

  

有没有办法可以自动创建用于语言翻译的.json文件?

,执行自动任务就像GruntGulp这样的自动化工具。

正如你所说,手动操作既费力又容易出错,所以Grunt / Gulp是你的选择。

使用简单的Grunt / Gulp配置,可以同时监视所有相关的.json文件:将立即检测到添加到其中任何一个的任何键,并命令执行自定义脚本你的选择。

GRUNT / GULP如何做到:

  1. Grunt / Gulp将不断观看所有相关的JSON文件;
  2. 如果在观看的文件中检测到更改,则会运行自定义脚本;
  3. 自定义脚本将读取更改的文件并检索新的密钥和值;
  4. 然后,自定义脚本到所有其他相关的JSON文件。
  5. 配置GRUNT

    要自动检测文件更改并执行myCustomScript,只需使用grunt-contrib-watch,如下所示:

    watch: {
      scripts: {
        files: ['**/*.locale.json'],
        tasks: ['myCustomScript'],
      },
    }
    

    自定义脚本添加新密钥(S)到相关的.JSON文件:

      grunt.event.on('watch', function(action, filepath) {
        // filepath is the path to the file where change is detected
        grunt.config.set('filepath', grunt.config.escape(filepath));
       });
    
      var myCustomScript=function(changedFile,keyFile){
    
         var project = grunt.file.readJSON(changedFile);
         //will store the file where changes were detected as a json object
    
         var keys=grunt.file.readJSON(keyFile);
         //will store keyFile as a json object
    
         //walk changedFile keys, and check is keys are in keyFile
         for (var key in project) {
           if (project.hasOwnProperty(key)) {
             if(!keys.hasOwnProperty(key)){
               //a new key was detected
               newKeyArray.push(key);
             }
           }
         }
    
      //should update all the other relevant JSON files with `grunt.file.write`, and add all the keys in newKeyArray:
    
      var filesToChangeArray=grunt.file.match('**/*.locale.json');
      //returns an array that contains all filepaths where change is desired
      filesToChangeArray.forEach(function(path){
        //walk newKeyArray to set addedContent string
        newKeyArray.forEach(function(key){
        addedContent+='"'+key+'":"to be set",';
        //this will write all the new keys, with a value of "to be set", to the addedContent string
        }
        grunt.file.write(path,addedContent);
        });
      }
    
      

    理想情况下,我希望能够从Windows PowerShell运行脚本

    即使Grunt / Gulp经常用于执行用javaScript / nodejs编写的自定义文件,它们也能够命令执行用其他语言编写的脚本。

    要执行PowerShell脚本,您可以使用名为grunt-shell的Grunt插件,如下所示:

    grunt.initConfig({
    shell: {
        ps: {
            options: {
                stdout: true
            },
            command: 'powershell myScript.ps1'
        }
    }
    });
    

    detailed in this SO post

    因此,如果PowerShell是你的事,你可以拥有两全其美

    • 使用Grunt / Gulp手表轻松检测;
    • 检测到更改时执行PowerShell脚本。
      

    但是,您可以轻松地使用 Grunt / Gulp :因为 Grunt / Gulp 已经在后台处理检测,所有你需要的do是让它运行一个自定义脚本来读取新密钥(grunt.file.readJSON)并将它们(grunt.file.write)复制到相关文件中。

答案 2 :(得分:3)

使用带有nodejs的javascript解决方案通过命令行自动执行该过程。

  

$ node localeUpdater.js

这将使用所做的任何修订来监视您的默认语言环境(locale-en.json),并根据需要更新整个语言环境文件列表。

  1. 创建必要的区域设置文件列表(如果不存在),然后使用默认区域设置数据
  2. 进行初始化
  3. 根据默认语言环境添加新密钥
  4. 根据默认区域设置删除缺失的密钥
  5.   

    localeUpdater.js

    var fs = require("fs");
    
    var localeFileDefault = "locale-en.json";
    var localeFileList = ["locale-jp.json", "locale-ph.json"];
    
    fs.watchFile(localeFileDefault, function() {
    
      var localeDefault = readFile(localeFileDefault);
      var localeCurrent = null;
      var fileNameCurrent = null;
    
      for (var i in localeFileList) {
        fileNameCurrent = localeFileList[i];
    
        console.log("Adding new keys from default locale to file " + fileNameCurrent);
        localeCurrent = readFile(fileNameCurrent);
        for (var key in localeDefault) {
          if (!localeCurrent[key]) {
            console.log(key + " key added.");
            localeCurrent[key] = localeDefault[key];
          }
        }
    
        console.log("Removing keys not on default locale to file " + fileNameCurrent);
        for (var key in localeCurrent) {
          if (!localeDefault[key]) {
            console.log(key + " key removed.");
            delete localeCurrent[key];
          }
        }
    
        writeFile(fileNameCurrent, JSON.stringify(localeCurrent));
        console.log("File " + fileNameCurrent + " updated.");
      }
    
    });
    
    function readFile(fileName) {
      var result = null;
      if (fs.existsSync(fileName)) {
        result = fs.readFileSync(fileName, "utf8");
        result = result ? JSON.parse(result) : {};
      } else {
        writeFile(fileName, "{}");
        result = {};
      }
      return result;
    }
    
    function writeFile(fileName, content) {
      fs.writeFileSync(fileName, content, "utf8");
    }

答案 3 :(得分:0)

您应该采取多种保护措施。

首先,您的翻译功能应该有一些保护措施。类似的东西:

function gettext(text) {
    if (manifest[text]) {
        return text;
    }

    return text;
}

我不确定你是如何注册新字符串的,但是我们正在为gettext('...')这样的代码编写代码库,然后我们编译一个翻译列表。我们每天都会把它推到第三方翻译公司,该公司会注意到新的字符串。他们填充新的东西,我们把内容拉回来。 “拉”涉及对不同语言文件的编译。翻译文件编译总是回归英语。换句话说,我们从第三方下载文件并执行以下操作:

_.map(strings, function(string) {
    return localeManifest[locale][text] || localeManifest['en_US'][text];
}

这确保即使语言环境的清单不包含翻译,我们仍然使用英语美国版本填充它。