{"id":17965356,"url":"https://github.com/t2ym/xliff-conv","last_synced_at":"2025-03-25T07:31:07.818Z","repository":{"id":57401660,"uuid":"58250755","full_name":"t2ym/xliff-conv","owner":"t2ym","description":"XLIFF to/from JSON converter for Polymer i18n-behavior","archived":false,"fork":false,"pushed_at":"2019-01-11T14:12:34.000Z","size":178,"stargazers_count":18,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-10T14:59:45.259Z","etag":null,"topics":["i18n","json","translation","xliff"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/t2ym.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-05-07T05:25:30.000Z","updated_at":"2024-04-02T22:14:44.000Z","dependencies_parsed_at":"2022-09-15T18:31:54.226Z","dependency_job_id":null,"html_url":"https://github.com/t2ym/xliff-conv","commit_stats":null,"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/t2ym%2Fxliff-conv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/t2ym%2Fxliff-conv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/t2ym%2Fxliff-conv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/t2ym%2Fxliff-conv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/t2ym","download_url":"https://codeload.github.com/t2ym/xliff-conv/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222047617,"owners_count":16922198,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["i18n","json","translation","xliff"],"created_at":"2024-10-29T12:41:53.778Z","updated_at":"2024-10-29T12:41:54.703Z","avatar_url":"https://github.com/t2ym.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/t2ym/xliff-conv.svg?branch=master)](https://travis-ci.org/t2ym/xliff-conv)\n[![Coverage Status](https://coveralls.io/repos/github/t2ym/xliff-conv/badge.svg?branch=master)](https://coveralls.io/github/t2ym/xliff-conv?branch=master)\n[![npm](https://img.shields.io/npm/v/xliff-conv.svg)](https://www.npmjs.com/package/xliff-conv)\n[![Bower](https://img.shields.io/bower/v/xliff-conv.svg)](https://customelements.io/t2ym/xliff-conv/)\n# xliff-conv\n\nXLIFF to/from JSON converter for Polymer [i18n-behavior](https://github.com/t2ym/i18n-behavior)\n\n## Features\n\n- Update bundle.*.json values with those from XLIFF\n- Generate XLIFF from bundles\n- Map todo operations in bundles onto XLIFF states\n- Update todo operations in bundles with XLIFF states\n- Concise and flexible expressions to customize conversion\n- Handy migration from [xliff2bundlejson](https://github.com/t2ym/xliff2bundlejson)\n- [UMD](https://github.com/ruyadorno/generator-umd) support\n\n## Install\n\n### For Node.js\n\n```javascript\n    npm install --save-dev xliff-conv\n```\n\n[Quick Tour](https://github.com/t2ym/polymer-starter-kit-i18n#quick-tour) with polymer-starter-kit-i18n\n\n### For Browsers\n\n```javascript\n\tbower install --save xliff-conv\n```\n\n## Import\n\n### On Node.js\n\n```javascript\n\tvar XliffConv = require('xliff-conv');\n```\n\n### On Browsers\n\n```html\n\t\u003cscript src=\"path/to/bower_components/xliff-conv/xliff-conv.js\"\u003e\u003c/script\u003e\n```\n\n## Examples\n\n### Import XLIFF task on gulp\n\n#### Note: This task has to be processed before [Leverage task with unbundle](https://github.com/t2ym/gulp-i18n-leverage#leverage-task-with-unbundle) to pick up outputs of this task.\n\n#### Input:\n  - Next XLIFF files in source\n  - Current bundle JSON files in source (as output templates)\n\n#### Output:\n  - Overwritten bundle JSON files in source\n\n```javascript\n    var gulp = require('gulp');\n    var JSONstringify = require('json-stringify-safe');\n    var stripBom = require('strip-bom');\n    var through = require('through2');\n    var XliffConv = require('xliff-conv');\n\n    // Import bundles.{lang}.xlf\n    gulp.task('import-xliff', function () {\n      var xliffPath = path.join('app', 'xliff');\n      var xliffConv = new XliffConv();\n      return gulp.src([\n          'app/**/xliff/bundle.*.xlf'\n        ])\n        .pipe(through.obj(function (file, enc, callback) {\n          var bundle, bundlePath;\n          var base = path.basename(file.path, '.xlf').match(/^(.*)[.]([^.]*)$/);\n          var xliff = String(file.contents);\n          if (base) {\n            try {\n              bundlePath = path.join(file.base, 'locales', 'bundle.' + base[2] + '.json');\n              bundle = JSON.parse(stripBom(fs.readFileSync(bundlePath, 'utf8')));\n              xliffConv.parseXliff(xliff, { bundle: bundle }, function (output) {\n                file.contents = new Buffer(JSONstringify(output, null, 2));\n                file.path = bundlePath;\n                callback(null, file);\n              });\n            }\n            catch (ex) {\n              callback(null, file);\n            }\n          }\n          else {\n            callback(null, file);\n          }\n        }))\n        .pipe(gulp.dest('app'))\n        .pipe($.size({\n          title: 'import-xliff'\n        }));\n    });\n```\n\n### Export XLIFF task on gulp\n\n#### Note: If the `todo` items in JSON files are removed, the corresponding `trans-unit`s are treated as `approved=\"yes\"` and `state=\"translated\"`.\n\n#### Input:\n  - Next bundles object in gulpfile.js\n\n#### Output:\n  - bundle.{lang}.xlf XLIFF in DEST_DIR/xliff\n\n```javascript\n    var gulp = require('gulp');\n    var through = require('through2');\n    var XliffConv = require('xliff-conv');\n\n    var bundles; // bundles object generated by preprocess and leverage tasks\n\n    // Generate bundles.{lang}.xlf\n    gulp.task('export-xliff', function (callback) {\n      var DEST_DIR = 'dist';\n      var srcLanguage = 'en';\n      var xliffPath = path.join(DEST_DIR, 'xliff');\n      var xliffConv = new XliffConv();\n      var promises = [];\n      try {\n        fs.mkdirSync(xliffPath);\n      }\n      catch (e) {\n      }\n      for (var lang in bundles) {\n        if (lang) {\n          (function (destLanguage) {\n            promises.push(new Promise(function (resolve, reject) {\n              xliffConv.parseJSON(bundles, {\n                srcLanguage: srcLanguage,\n                destLanguage: destLanguage\n              }, function (output) {\n                fs.writeFile(path.join(xliffPath, 'bundle.' + destLanguage + '.xlf'), output, resolve);\n              });\n            }));\n          })(lang);\n        }\n      }\n      Promise.all(promises).then(function (outputs) {\n        callback();\n      });\n    });\n```\n\n## API\n\n### Constructor\n\n`var xliffConv = new XliffConv(options)`\n\n#### `options` object\n\n- date: Date, default: new Date() - date attribute value for XLIFF\n- xliffStates: Object, default: XliffConv.xliffStates.default - todo.op to XLIFF state mapping table\n- patterns: Object, default: XliffConv.patterns - A set of named regular expressions for pattern matching\n- logger: Function, default: console.log - information logger\n- warnLogger: Function, default: console.warn - warning logger\n- errorLogger: Function, default: console.error - error logger\n\n#### `XliffConv.xliffStates` object - predefined mapping tables for `options.xliffStates`\n\n```javascript\n  XliffConv.xliffStates = {\n    // All state-less unapproved strings are regarded as needs-translation\n    'default': {\n      'add'    : [ 'new' ],\n      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '' ],\n      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],\n      'default': [ 'translated', 'signed-off', 'final', '[approved]' ]\n    },\n    // Aannotations {{name}} and tags \u003ctag-name\u003e are regarded as translated\n    'annotationsAsTranslated': {\n      'add'    : [ 'new' ],\n      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '' ],\n      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],\n      'default': [ 'translated', 'signed-off', 'final', '[approved]', '[source~=annotationsAndTags]' ]\n    },\n    // Newly added annotations {{name}} and tags \u003ctag-name\u003e are regarded as translated\n    'newAnnotationsAsTranslated': {\n      'add'    : [ 'new' ],\n      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '' ],\n      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],\n      'default': [ 'translated', 'signed-off', 'final', '[approved]', '[state==new\u0026\u0026source~=annotationsAndTags]' ]\n    },\n    // Newly added annotations {{name}} and tags \u003ctag-name\u003e are regarded as translated only at export\n    'newAnnotationsAsTranslatedAtExport': {\n      'add'    : [ 'new' ],\n      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '' ],\n      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],\n      'default': [ 'translated', 'signed-off', 'final', '[approved]', '[export\u0026\u0026state==new\u0026\u0026source~=annotationsAndTags]' ]\n    },\n    // Annotations {{name}} and tags \u003ctag-name\u003e are skipped in translation by translate=no\n    'annotationsAsNoTranslate': {\n      'add'    : [ 'new' ],\n      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '' ],\n      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],\n      'default': [ 'translated', 'signed-off', 'final', '[source~=annotationsAndTags\u0026\u0026translate:=no\u0026\u0026state:=final]', '[approved]' ],\n    },\n    /* === State Mapping Tables for migration from xliff2bundlejson === */\n    // All state-less strings are regarded as approved=yes\n    'approveAll': {\n      'add'    : [ 'new' ],\n      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n' ],\n      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],\n      'default': [ 'translated', 'signed-off', 'final', '' ]\n    },\n    // State-less translated strings need review\n    'reviewTranslated': {\n      'add'    : [ 'new' ],\n      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '[!state\u0026\u0026!approved\u0026\u0026source==target]', '' ],\n      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n', '[!state\u0026\u0026!approved\u0026\u0026source!=target]' ],\n      'default': [ 'translated', 'signed-off', 'final', '[approved]' ]\n    },\n    // State-less translated strings are regarded as approved=yes\n    'approveTranslated': {\n      'add'    : [ 'new' ],\n      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '[!state\u0026\u0026!approved\u0026\u0026source==target]', '' ],\n      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],\n      'default': [ 'translated', 'signed-off', 'final', '[!state\u0026\u0026!approved\u0026\u0026source!=target]', '[approved]' ]\n    }\n    /*\n      Expression format:\n        [condition1\u0026\u0026condition2\u0026\u0026...\u0026\u0026effect1\u0026\u0026effect2\u0026\u0026...]\n          - expression is true when all the conditions are true\n          - optional effects are processed if the expression is true\n\n      Operators for conditions:\n        parameter\n          - true if parameter is non-null\n        !parameter\n          - true if parameter is undefined, null, or ''\n        parameter1==parameter2\n          - true if parameter1 is equal to parameter2\n        parameter1!=parameter2\n          - true if parameter1 is not equal to parameter2\n        parameter~=pattern\n          - true if parameter matches the regular expression options.patterns.pattern\n          - if options.patterns.pattern is undefined, pattern is treated as the matching string\n        tag.attribute~=pattern\n          - true if attribute value of tag matched the regular expression options.patterns.pattern\n          - if options.patterns.pattern is undefined, pattern is treated as the matching string\n\n      Operators for effects:\n        tag.attribute:=value\n          - assign attribute of tag with the string value\n        attribute:=value\n          - assign predefined alias attribute with the string value\n        tag:=value\n          - assign textContent of tag with the string value\n\n      Predefined parameters: Undefined parameters are treated as strings for matching\n        state\n          - state attribute of target\n        id\n          - id attribute of trans-unit\n        component\n          - component name in id\n        restype\n          - restype attribute of trans-unit. 'x-json-string' for strings\n        source\n          - text content of source tag\n        target\n          - text content of target tag\n        approved\n          - true if approved attribute of trans-unit is 'yes'\n        import\n          - true on XLIFF import (parseXliff); false on XLIFF export (parseJSON)\n        export\n          - true on XLIFF export (parseJSON); false on XLIFF import (parseXliff)\n\n      Predefined tags:\n        file\n          - file tag\n        trans-unit\n          - trans-unit tag\n        source\n          - source tag\n        target\n          - target tag\n\n      Predefined alias attributes:\n        translate\n          - alias for trans-unit.translate\n        approved\n          - alias for trans-unit.approved\n        state\n          - alias for target.state\n     */\n  };\n```\n\n#### `XliffConv.patterns` object - predefined named regular expressions for `options.patterns`\n\n```javascript\n  XliffConv.patterns = {\n    'annotationsAndTags': /^({{[^{} ]*}}|\\[\\[[^\\[\\] ]*\\]\\]|\u003c[-a-zA-Z]{1,}\u003e)$/,\n    'annotations': /^({{[^{} ]*}}|\\[\\[[^\\[\\] ]*\\]\\])$/,\n    'numbers': /^[0-9.]{1,}$/,\n    'tags': /^\u003c[-a-zA-Z]{1,}\u003e$/\n  };\n```\n\n### `xliffConv.parseXliff(xliff, options, callback)` method\n\n- xliff: String, XLIFF as a string\n- options: Object, options.bundle as target bundle JSON object\n- callback: Function, callback(output) with output JSON object\n\n### `xliffConv.parseJSON(bundles, options, callback)` method\n\n- bundles: Object, bundles object\n- options.srcLanguage: String, default: 'en' - `\u003cfile source-language\u003e` attribute\n- options.destLanguage: String, default: 'fr' - `\u003cfile target-language\u003e` attribute\n- options.xmlSpace: String, default: 'default' - `\u003cfile xml:space\u003e` attribute\n- options.dataType: String, default: 'plaintext' - `\u003cfile datatype\u003e` attribute\n- options.original: String, default: 'messages' - `\u003cfile original\u003e` attribute\n- options.productName: String, default: 'messages' - `\u003cfile product-name\u003e` attribute\n- options.xmlHeader: String, default: \n```\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003c!DOCTYPE xliff PUBLIC \"-//XLIFF//DTD XLIFF//EN\" \"http://www.oasis-open.org/committees/xliff/documents/xliff.dtd\"\u003e\n```\n- options.xliffTemplate: String, default:\n```xml\n\u003cxliff version=\"1.0\"\u003e\n  \u003cfile xml:space=\"[options.xmlSpace]\"\n      source-language=\"[options.srcLanguage]\"\n      target-language=\"[options.destLanguage]\"\n      datatype=\"[options.dataType]\"\n      original=\"[options.original]\"\n      date=\"[this.date.toISOString().replace(/[.][0-9]*Z$/, 'Z')]\"\n      product-name=\"[options.productName]\"\u003e\n    \u003cheader\u003e\n      \u003ctool tool-id=\"xliff-conv\" tool-name=\"xliff-conv\" tool-version=\"[toolVersion]\"/\u003e\n    \u003c/header\u003e\n    \u003cbody\u003e\n    \u003c/body\u003e\n  \u003c/file\u003e\n\u003c/xliff\u003e\n```\n- options.transUnitTemplate: String, default:\n```xml\n      \u003ctrans-unit\u003e\n        \u003csource\u003e\u003c/source\u003e\n        \u003ctarget\u003e\u003c/target\u003e\n      \u003c/trans-unit\u003e\n```\n- options.addNewAttr: Object, default: `undefined`\n  - Customize id and add a new attribute to `\u003ctrans-unit\u003e` with the original id value\n  - labelArrayWithUniqueId is an Object mapping a new attribute value for each id\n```javascript\n      xliffConv.parseJSON(bundles, {\n        srcLanguage: srcLanguage,\n        destLanguage: destLanguage,\n        addNewAttr: {\n          newAttrName: labelMapWithUniqueId\n        }\n      }, function (output) {\n        fs.writeFile(path.join(xliffPath, 'bundle.' + destLanguage + '.xlf'), output, resolve);\n      });\n```\n```javascript\n      // example labelMapWithUniqueId Object\n      labelMapWithUniqueId =\n        {\n          // id: attribute value\n          \"Factory_audit_address\": \"ckv7ymf07ahqog4lur12bwobg1z3dsxzkqkdwxan\",\n          \"alert_info_when_update_config_preferences\": \"ybsqyempsolypcf4poq1wdxxl8c04oam03ei27bc\",\n          \"application_title\": \"rj7rtcdbefchcbrq9itw6sewjifd2v3c5dn99969\",\n          \"back\": \"48gtruuew3ndd7pnj26lttt0kbgnlv2iyhtti99v\",\n          \"barcode_section\": \"i2d0t2y11b5zlrlhbn5it8qkbxbp7ub0bdgxy7tr\",\n          \"cancel_title\": \"bbzgu18z7wl6thj0eh9p83nlcrz4znyfox4khjuq\",\n          \"client_initial_2_letter\": \"ilttwryn5jccb4wnhfu3nq9z72ds21m2ho7fnsgs\"\n        }\n```\n```xml\n      \u003c!-- example trans-unit --\u003e\n      \u003c!-- without options.addNewAttr --\u003e\n      \u003ctrans-unit id=\"Factory_audit_address\" approved=\"yes\"\u003e\n        \u003csource\u003eAddress\u003c/source\u003e\n        \u003ctarget state=\"translated\"\u003eAdresse\u003c/target\u003e\n      \u003c/trans-unit\u003e\n      \u003c!-- with options.addNewAttr = { resname: labelMapWithUniqueId } above --\u003e\n      \u003ctrans-unit id=\"ckv7ymf07ahqog4lur12bwobg1z3dsxzkqkdwxan\" resname=\"Factory_audit_address\" approved=\"yes\"\u003e\n        \u003csource\u003eAddress\u003c/source\u003e\n        \u003ctarget state=\"translated\"\u003eAdresse\u003c/target\u003e\n      \u003c/trans-unit\u003e\n```\n\n- callback: Function, callback(output) with output XLIFF as a string\n\n#### Notes:\n- With `options.xliffTemplate`, all the attribute values within the template are NOT replaced.  It is the caller's responsibility to set appropriate values to the attributes.\n- With `options.transUnitTemplate`, XliffConv does NOT recognize `\u003cnote\u003e` tags in the template in importing XLIFF and discards the contents.\n\n### Custom XLIFF restype attributes\n\n| restype          | JSON type | Note                       |\n|:-----------------|:----------|:---------------------------|\n| x-json-string    | string    | Omitted                    |\n| x-json-boolean   | boolean   | \"true\" or \"false\" in value |\n| x-json-number    | number    |                            |\n| x-json-object    | object    | Unused for now             |\n| x-json-undefined | undefined | Empty string in value      |\n\n### Default Mapping of todo.op and XLIFF states\n\n#### JSON -\u003e XLIFF\n\n| todo.op | XLIFF state              |\n|:--------|:-------------------------|\n| add     | new                      |\n| replace | needs-translation        |\n| review  | needs-review-translation |\n| N/A     | translated               |\n\n#### XLIFF -\u003e JSON\n\n| XLIFF state              | approved  | todo.op | Note        |\n|:-------------------------|:----------|:--------|:------------|\n| new                      | no or N/A | add     |             |\n| needs-translation        | no or N/A | replace |             |\n| needs-adaptation         | no or N/A | replace |             |\n| needs-l10n               | no or N/A | replace |             |\n| N/A                      | no or N/A | replace |             |\n| needs-review-translation | no or N/A | review  |             |\n| needs-review-adaptation  | no or N/A | review  |             |\n| needs-review-l10n        | no or N/A | review  |             |\n| translated               | yes       | N/A     | Remove todo |\n| signed-off               | yes       | N/A     | Remove todo |\n| final                    | yes       | N/A     | Remove todo |\n| N/A                      | yes       | N/A     | Remove todo |\n\n## License\n\n[BSD-2-Clause](https://github.com/t2ym/xliff-conv/blob/master/LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ft2ym%2Fxliff-conv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ft2ym%2Fxliff-conv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ft2ym%2Fxliff-conv/lists"}