npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

xliff-conv

v1.0.12

Published

XLIFF to/from JSON converter for Polymer i18n-behavior

Downloads

69

Readme

Build Status Coverage Status npm Bower

xliff-conv

XLIFF to/from JSON converter for Polymer i18n-behavior

Features

  • Update bundle.*.json values with those from XLIFF
  • Generate XLIFF from bundles
  • Map todo operations in bundles onto XLIFF states
  • Update todo operations in bundles with XLIFF states
  • Concise and flexible expressions to customize conversion
  • Handy migration from xliff2bundlejson
  • UMD support

Install

For Node.js

    npm install --save-dev xliff-conv

Quick Tour with polymer-starter-kit-i18n

For Browsers

	bower install --save xliff-conv

Import

On Node.js

	var XliffConv = require('xliff-conv');

On Browsers

	<script src="path/to/bower_components/xliff-conv/xliff-conv.js"></script>

Examples

Import XLIFF task on gulp

Note: This task has to be processed before Leverage task with unbundle to pick up outputs of this task.

Input:

  • Next XLIFF files in source
  • Current bundle JSON files in source (as output templates)

Output:

  • Overwritten bundle JSON files in source
    var gulp = require('gulp');
    var JSONstringify = require('json-stringify-safe');
    var stripBom = require('strip-bom');
    var through = require('through2');
    var XliffConv = require('xliff-conv');

    // Import bundles.{lang}.xlf
    gulp.task('import-xliff', function () {
      var xliffPath = path.join('app', 'xliff');
      var xliffConv = new XliffConv();
      return gulp.src([
          'app/**/xliff/bundle.*.xlf'
        ])
        .pipe(through.obj(function (file, enc, callback) {
          var bundle, bundlePath;
          var base = path.basename(file.path, '.xlf').match(/^(.*)[.]([^.]*)$/);
          var xliff = String(file.contents);
          if (base) {
            try {
              bundlePath = path.join(file.base, 'locales', 'bundle.' + base[2] + '.json');
              bundle = JSON.parse(stripBom(fs.readFileSync(bundlePath, 'utf8')));
              xliffConv.parseXliff(xliff, { bundle: bundle }, function (output) {
                file.contents = new Buffer(JSONstringify(output, null, 2));
                file.path = bundlePath;
                callback(null, file);
              });
            }
            catch (ex) {
              callback(null, file);
            }
          }
          else {
            callback(null, file);
          }
        }))
        .pipe(gulp.dest('app'))
        .pipe($.size({
          title: 'import-xliff'
        }));
    });

Export XLIFF task on gulp

Note: If the todo items in JSON files are removed, the corresponding trans-units are treated as approved="yes" and state="translated".

Input:

  • Next bundles object in gulpfile.js

Output:

  • bundle.{lang}.xlf XLIFF in DEST_DIR/xliff
    var gulp = require('gulp');
    var through = require('through2');
    var XliffConv = require('xliff-conv');

    var bundles; // bundles object generated by preprocess and leverage tasks

    // Generate bundles.{lang}.xlf
    gulp.task('export-xliff', function (callback) {
      var DEST_DIR = 'dist';
      var srcLanguage = 'en';
      var xliffPath = path.join(DEST_DIR, 'xliff');
      var xliffConv = new XliffConv();
      var promises = [];
      try {
        fs.mkdirSync(xliffPath);
      }
      catch (e) {
      }
      for (var lang in bundles) {
        if (lang) {
          (function (destLanguage) {
            promises.push(new Promise(function (resolve, reject) {
              xliffConv.parseJSON(bundles, {
                srcLanguage: srcLanguage,
                destLanguage: destLanguage
              }, function (output) {
                fs.writeFile(path.join(xliffPath, 'bundle.' + destLanguage + '.xlf'), output, resolve);
              });
            }));
          })(lang);
        }
      }
      Promise.all(promises).then(function (outputs) {
        callback();
      });
    });

API

Constructor

var xliffConv = new XliffConv(options)

options object

  • date: Date, default: new Date() - date attribute value for XLIFF
  • xliffStates: Object, default: XliffConv.xliffStates.default - todo.op to XLIFF state mapping table
  • patterns: Object, default: XliffConv.patterns - A set of named regular expressions for pattern matching
  • logger: Function, default: console.log - information logger
  • warnLogger: Function, default: console.warn - warning logger
  • errorLogger: Function, default: console.error - error logger

XliffConv.xliffStates object - predefined mapping tables for options.xliffStates

  XliffConv.xliffStates = {
    // All state-less unapproved strings are regarded as needs-translation
    'default': {
      'add'    : [ 'new' ],
      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '' ],
      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],
      'default': [ 'translated', 'signed-off', 'final', '[approved]' ]
    },
    // Aannotations {{name}} and tags <tag-name> are regarded as translated
    'annotationsAsTranslated': {
      'add'    : [ 'new' ],
      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '' ],
      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],
      'default': [ 'translated', 'signed-off', 'final', '[approved]', '[source~=annotationsAndTags]' ]
    },
    // Newly added annotations {{name}} and tags <tag-name> are regarded as translated
    'newAnnotationsAsTranslated': {
      'add'    : [ 'new' ],
      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '' ],
      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],
      'default': [ 'translated', 'signed-off', 'final', '[approved]', '[state==new&&source~=annotationsAndTags]' ]
    },
    // Newly added annotations {{name}} and tags <tag-name> are regarded as translated only at export
    'newAnnotationsAsTranslatedAtExport': {
      'add'    : [ 'new' ],
      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '' ],
      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],
      'default': [ 'translated', 'signed-off', 'final', '[approved]', '[export&&state==new&&source~=annotationsAndTags]' ]
    },
    // Annotations {{name}} and tags <tag-name> are skipped in translation by translate=no
    'annotationsAsNoTranslate': {
      'add'    : [ 'new' ],
      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '' ],
      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],
      'default': [ 'translated', 'signed-off', 'final', '[source~=annotationsAndTags&&translate:=no&&state:=final]', '[approved]' ],
    },
    /* === State Mapping Tables for migration from xliff2bundlejson === */
    // All state-less strings are regarded as approved=yes
    'approveAll': {
      'add'    : [ 'new' ],
      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n' ],
      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],
      'default': [ 'translated', 'signed-off', 'final', '' ]
    },
    // State-less translated strings need review
    'reviewTranslated': {
      'add'    : [ 'new' ],
      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '[!state&&!approved&&source==target]', '' ],
      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n', '[!state&&!approved&&source!=target]' ],
      'default': [ 'translated', 'signed-off', 'final', '[approved]' ]
    },
    // State-less translated strings are regarded as approved=yes
    'approveTranslated': {
      'add'    : [ 'new' ],
      'replace': [ 'needs-translation', 'needs-adaptation', 'needs-l10n', '[!state&&!approved&&source==target]', '' ],
      'review' : [ 'needs-review-translation', 'needs-review-adaptation', 'needs-review-l10n' ],
      'default': [ 'translated', 'signed-off', 'final', '[!state&&!approved&&source!=target]', '[approved]' ]
    }
    /*
      Expression format:
        [condition1&&condition2&&...&&effect1&&effect2&&...]
          - expression is true when all the conditions are true
          - optional effects are processed if the expression is true

      Operators for conditions:
        parameter
          - true if parameter is non-null
        !parameter
          - true if parameter is undefined, null, or ''
        parameter1==parameter2
          - true if parameter1 is equal to parameter2
        parameter1!=parameter2
          - true if parameter1 is not equal to parameter2
        parameter~=pattern
          - true if parameter matches the regular expression options.patterns.pattern
          - if options.patterns.pattern is undefined, pattern is treated as the matching string
        tag.attribute~=pattern
          - true if attribute value of tag matched the regular expression options.patterns.pattern
          - if options.patterns.pattern is undefined, pattern is treated as the matching string

      Operators for effects:
        tag.attribute:=value
          - assign attribute of tag with the string value
        attribute:=value
          - assign predefined alias attribute with the string value
        tag:=value
          - assign textContent of tag with the string value

      Predefined parameters: Undefined parameters are treated as strings for matching
        state
          - state attribute of target
        id
          - id attribute of trans-unit
        component
          - component name in id
        restype
          - restype attribute of trans-unit. 'x-json-string' for strings
        source
          - text content of source tag
        target
          - text content of target tag
        approved
          - true if approved attribute of trans-unit is 'yes'
        import
          - true on XLIFF import (parseXliff); false on XLIFF export (parseJSON)
        export
          - true on XLIFF export (parseJSON); false on XLIFF import (parseXliff)

      Predefined tags:
        file
          - file tag
        trans-unit
          - trans-unit tag
        source
          - source tag
        target
          - target tag

      Predefined alias attributes:
        translate
          - alias for trans-unit.translate
        approved
          - alias for trans-unit.approved
        state
          - alias for target.state
     */
  };

XliffConv.patterns object - predefined named regular expressions for options.patterns

  XliffConv.patterns = {
    'annotationsAndTags': /^({{[^{} ]*}}|\[\[[^\[\] ]*\]\]|<[-a-zA-Z]{1,}>)$/,
    'annotations': /^({{[^{} ]*}}|\[\[[^\[\] ]*\]\])$/,
    'numbers': /^[0-9.]{1,}$/,
    'tags': /^<[-a-zA-Z]{1,}>$/
  };

xliffConv.parseXliff(xliff, options, callback) method

  • xliff: String, XLIFF as a string
  • options: Object, options.bundle as target bundle JSON object
  • callback: Function, callback(output) with output JSON object

xliffConv.parseJSON(bundles, options, callback) method

  • bundles: Object, bundles object
  • options.srcLanguage: String, default: 'en' - <file source-language> attribute
  • options.destLanguage: String, default: 'fr' - <file target-language> attribute
  • options.xmlSpace: String, default: 'default' - <file xml:space> attribute
  • options.dataType: String, default: 'plaintext' - <file datatype> attribute
  • options.original: String, default: 'messages' - <file original> attribute
  • options.productName: String, default: 'messages' - <file product-name> attribute
  • options.xmlHeader: String, default:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xliff PUBLIC "-//XLIFF//DTD XLIFF//EN" "http://www.oasis-open.org/committees/xliff/documents/xliff.dtd">
  • options.xliffTemplate: String, default:
<xliff version="1.0">
  <file xml:space="[options.xmlSpace]"
      source-language="[options.srcLanguage]"
      target-language="[options.destLanguage]"
      datatype="[options.dataType]"
      original="[options.original]"
      date="[this.date.toISOString().replace(/[.][0-9]*Z$/, 'Z')]"
      product-name="[options.productName]">
    <header>
      <tool tool-id="xliff-conv" tool-name="xliff-conv" tool-version="[toolVersion]"/>
    </header>
    <body>
    </body>
  </file>
</xliff>
  • options.transUnitTemplate: String, default:
      <trans-unit>
        <source></source>
        <target></target>
      </trans-unit>
  • options.addNewAttr: Object, default: undefined
    • Customize id and add a new attribute to <trans-unit> with the original id value
    • labelArrayWithUniqueId is an Object mapping a new attribute value for each id
      xliffConv.parseJSON(bundles, {
        srcLanguage: srcLanguage,
        destLanguage: destLanguage,
        addNewAttr: {
          newAttrName: labelMapWithUniqueId
        }
      }, function (output) {
        fs.writeFile(path.join(xliffPath, 'bundle.' + destLanguage + '.xlf'), output, resolve);
      });
      // example labelMapWithUniqueId Object
      labelMapWithUniqueId =
        {
          // id: attribute value
          "Factory_audit_address": "ckv7ymf07ahqog4lur12bwobg1z3dsxzkqkdwxan",
          "alert_info_when_update_config_preferences": "ybsqyempsolypcf4poq1wdxxl8c04oam03ei27bc",
          "application_title": "rj7rtcdbefchcbrq9itw6sewjifd2v3c5dn99969",
          "back": "48gtruuew3ndd7pnj26lttt0kbgnlv2iyhtti99v",
          "barcode_section": "i2d0t2y11b5zlrlhbn5it8qkbxbp7ub0bdgxy7tr",
          "cancel_title": "bbzgu18z7wl6thj0eh9p83nlcrz4znyfox4khjuq",
          "client_initial_2_letter": "ilttwryn5jccb4wnhfu3nq9z72ds21m2ho7fnsgs"
        }
      <!-- example trans-unit -->
      <!-- without options.addNewAttr -->
      <trans-unit id="Factory_audit_address" approved="yes">
        <source>Address</source>
        <target state="translated">Adresse</target>
      </trans-unit>
      <!-- with options.addNewAttr = { resname: labelMapWithUniqueId } above -->
      <trans-unit id="ckv7ymf07ahqog4lur12bwobg1z3dsxzkqkdwxan" resname="Factory_audit_address" approved="yes">
        <source>Address</source>
        <target state="translated">Adresse</target>
      </trans-unit>
  • callback: Function, callback(output) with output XLIFF as a string

Notes:

  • 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.
  • With options.transUnitTemplate, XliffConv does NOT recognize <note> tags in the template in importing XLIFF and discards the contents.

Custom XLIFF restype attributes

| restype | JSON type | Note | |:-----------------|:----------|:---------------------------| | x-json-string | string | Omitted | | x-json-boolean | boolean | "true" or "false" in value | | x-json-number | number | | | x-json-object | object | Unused for now | | x-json-undefined | undefined | Empty string in value |

Default Mapping of todo.op and XLIFF states

JSON -> XLIFF

| todo.op | XLIFF state | |:--------|:-------------------------| | add | new | | replace | needs-translation | | review | needs-review-translation | | N/A | translated |

XLIFF -> JSON

| XLIFF state | approved | todo.op | Note | |:-------------------------|:----------|:--------|:------------| | new | no or N/A | add | | | needs-translation | no or N/A | replace | | | needs-adaptation | no or N/A | replace | | | needs-l10n | no or N/A | replace | | | N/A | no or N/A | replace | | | needs-review-translation | no or N/A | review | | | needs-review-adaptation | no or N/A | review | | | needs-review-l10n | no or N/A | review | | | translated | yes | N/A | Remove todo | | signed-off | yes | N/A | Remove todo | | final | yes | N/A | Remove todo | | N/A | yes | N/A | Remove todo |

License

BSD-2-Clause