Есть ли способ, которым я могу автоматизировать создание.файлы json, используемые для языковых переводов?
У меня есть файлы, такие как этот, которые имеют ключи перевода и значения:
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 ответов:
В 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. Затем он ищет все остальные файлы локали и проверяет их на наличие ключей, которые присутствуют в английском файле, но отсутствуют в нем. Затем он добавляет недостающие ключи и значения и сохраняет файлы локали в Юникоде.
Позвольте мне показать вам, как вы можете сделать то же самое со скриптами старой школы Windows, так как вы, кажется, предпочитаете 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"Я надеюсь, что это помогает.
Есть ли способ, которым я могу автоматизировать создание .файлы json, используемые для языковых переводов?
Да , выполнение автоматических задач-это именно то, что инструменты автоматизации, такие как Grunt и Gulp, предназначены для выполнения.
Как вы сказали, делать все вручную-это трудоемко и подвержено ошибкам, поэтому ворчание/глотание-это путь.
С простой конфигурацией Grunt/Gulp, все соответствующие.файлы json можно просматривать одновременно: любой ключ добавленный к любому из них будет мгновенно обнаружен, и заказывайте выполнение пользовательского скрипта по вашему выбору.
КАК GRUNT / GULP МОЖЕТ ЭТО СДЕЛАТЬ:
- Grunt/Gulp будет постоянно смотреть все соответствующие файлы JSON;
- при обнаружении изменения в наблюдаемом файле запускается пользовательский скрипт ;
- пользовательский скрипт будет читать измененный файл и извлекать новый ключ(Ы) и значение (ы);
- пользовательский сценарий будет тогда запишите во все другие соответствующие файлы JSON.
НАСТРОЙКА GRUNT
Чтобы автоматически обнаружить изменения файла и выполнить
myCustomScript, просто используйте grunt-contrib-watch Вот так:watch: { scripts: { files: ['**/*.locale.json'], tasks: ['myCustomScript'], }, }
ПОЛЬЗОВАТЕЛЬСКИЙ СКРИПТ ДЛЯ ДОБАВЛЕНИЯ НОВОГО КЛЮЧА(КЛЮЧЕЙ) К СООТВЕТСТВУЮЩЕМУ .ФАЙЛЫ 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 под названием grunt-shell , например:
grunt.initConfig({ shell: { ps: { options: { stdout: true }, command: 'powershell myScript.ps1' } } });Как подробно описано в этом посте SO .
Итак, если PowerShell-это ваша вещь, вы можете иметь лучшее из обоих миров :
- простое обнаружение с помощью часов Grunt/Gulp;
- выполнение сценария PowerShell при изменении обнаруженный.
Однако вы можете с легкостью использовать Grunt/Gulp только для этого: поскольку Grunt/Gulp уже заботится об обнаружении в фоновом режиме, все, что вам нужно сделать, это запустить пользовательский скрипт, который читает ваши новые ключи (
grunt.file.readJSON) и копирует их (grunt.file.write) в соответствующие файлы.
Автоматизировал процесс, используя решение javascript с nodejs через командную строку.
$ node localeUpdater.js
Это будет смотреть вашу локаль по умолчанию (locale-en.json) с любыми внесенными изменениями и обновите весь список файлов локали по мере необходимости.
- создайте необходимый список файлов локали, если он отсутствует, а затем инициализируйте его данными локали по умолчанию
- добавление новых ключей на основе языка по умолчанию
- удалить отсутствующие ключи по умолчанию locale
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"); }
Есть несколько гарантий, которые вы должны поставить на место.
Во-первых, ваша функция перевода должна иметь некоторые гарантии. Что-то вроде:
function gettext(text) { if (manifest[text]) { return text; } return text; }Я не знаю, как вы регистрируете новые строки, но мы регулярно меняем нашу кодовую базу для таких вещей, как
gettext('...'), а затем составляем список переводов таким образом. Пару раз в день мы передаем это в стороннюю переводческую компанию, которая замечает новые строки. Они заселяют новые вещи, а мы возвращаем контент. "Тяга" включает в себя компиляцию к различным языковым файлам. Компиляция файла перевода всегда возвращается к английскому языку. Другими словами, мы загружаем файл от третьей стороны и делаем что-то вроде:_.map(strings, function(string) { return localeManifest[locale][text] || localeManifest['en_US'][text]; }Это гарантирует, что даже если манифест для локали не содержит перевода, мы все равно заполняем его английской американской версией.
Comments