Gulp task for updating i18n localization ids in html files.
npm i -D gulp-i18n-update-localization-ids
const i18nUpdateLocalizationIds = require('gulp-i18n-update-localization-ids');
const task = i18nUpdateLocalizationIds({
// ...options...
});
The task is a transform stream that processes each file and emits updated files:
- For each tag that is whitelisted:
- It is ensured that localizable content and attributes have unique id's by...
- ...using existing ids,...
- ...regererating duplicates ids (per file)...
- ...or adding missing ids.
- When a localized attribute is not present, the localization id is removed.
- It is ensured that localizable content and attributes have unique id's by...
- Throw an error if a non-whitelisted tag is already localized or has text content.
- Throw an error if a tag contains both text and non-text content.
This option is required.
It defines a whitelist of tags and attributes that will be localized.
whitelist: [
{tagName: 'h1'},
{tagName: 'img', attrs: ['alt']},
{tagName: 'custom-elem', attrs: ['title', 'subtitle'], content: 'html'}
]
- whitelist
<array>
- An array that contains objects with the following properties:- tagName
<string>
- The tag name. - attrs
<iterable>
- An iterable of attribute names to localize. - content - Specify how tag content is localized:
'html'
- Localize content as html.'text'
- Localize content as text. This is the default if tagName does not contain a hyphen.false
- Don't localize content. This is the default if tagName contains a hyphen.
- tagName
Optional. Specify what parts of a html fragment are ignored.
Matching parts will not be modified or checked against errors.
ignore: [
// Ignore content that matches "ignore me":
{content: 'ignore me'},
// Ignore content like "${foo.bar}":
{content: v => v.startsWith('${') && v.endsWith('}')},
// Ignore <code> tags and all children:
{tagName: 'code'},
// Ignore attributes that contain aurelia-like interpolation:
{attr: v => /\$\{[^\}]+\}/}
]
- ignore
<IgnoreItem>
- This can be any of the following:<array>
- An array of ignore items.<object>
- An object with the following properties:- content
<Rule>
- Ignore tag text content if it matches the rule. - tagName
<Rule>
- Ignore a tag and it's subtree if it matches the rule. - attr
<Rule>
- Ignore attributes if the value matches the rule. Not
attributes will created for ignored attributes and they will not be modified or removed.
- content
<Rule>
can be one of the following:<string>
- If the value matches the specified one.<function>
- If the function returns true for the value.<RegExp>
- If the value matches the specified regexp. This is not recommended!
Optional. Control when to emit output files.
emit: 'always'
'always'
- Default. Emit always.'onChangeOnly'
- Emit only if the file was modified by the plugin. Choose this value, if you are using this plugin to overwrite files that you are currently working with.
Optional. A function to generate a new id. It will be automatically ensured that the generated id is unique for the target file.
idTemplate: (x, file) => `foo-${x}`
// Will produce id's like: foo-0, foo-1, ...
- x
<number>
- A number that should be included in the id. - file
<Vinyl>
- The input file. - knownIds
<Set>
- A set of ids that are known for that input file. - returns
<string>
- Any string matching/^[a-z0-9_.-]+$/
.
In addition, an id template can have a function that is called for every processed file after it has been scanned and before new ids are generated. This is internally used by the prefixFilename
template to avoid using prefixes that have been used in previous files.
function template(x, file, knownIds) { ... }
template.onFile = (file, knownIds) => {
// ...
};
Optional. Specify the attribute for storing localization keys.
Optional. Specify the encoding to use for de- and encoding files.
Optional. Configure, how specific exceptions are handled.
Currently, the following exceptions can be configured:
exceptions: {
// If a tag contains text content, and the tag or it's content is not whitelisted.
// (Consider using an ignore rule instead)
illegalContent: 'throw'
// If a tag has a `t` attribute, and the tag or a localized attribute is not whitelisted.
// (Consider whitelisting the attribute instead)
illegalAttribute: 'throw'
}
The following behaviour types are available: 'throw'
, 'warn'
and 'ignore'
.
Optional. Specify the class that represents a localization key.
The class must implement all members of the default one located in /lib/localization-key.js
.
If any prefix is already used in the processed file, that prefix will be used for new ids. Otherwise a prefix will be generated from the filename (without path and extension). If the same prefix has been used for previous files, an increasing number will be appended to the prefix.
const {prefixFilename} = require('gulp-i18n-update-localization-ids');
i18nUpdateLocalizationIds({
whitelist: [...],
idTemplate: prefixFilename()
})
- globalPrefixes
<Map>
- Optional. Provide your own empty map object to ensure prefix uniqueness across multiple plugin instances or executions. This map will be filled by the plugin while executing.
Filename | Generated ID |
---|---|
foo/bar.html |
bar.t0 |
baz/bar.html |
bar1.t0 |
FooBar-Baz.Example.html |
FooBar-Baz-example.t0 |
Warning! There is an edge case where the same prefix could be assigned to different files:
If you have a file /b/foo.html
which already has an id foo.t0
and you create a file /a/foo.html
, an id foo.t0
could be used for the new file as the prefixFilename template may not be aware of /b/foo.html
s prefix at the time, the new file is processed. If you need to avoid this problem in a production build, you have to consume all files from the plugin output without writing to disk first and then run your actual task. Both plugin instances must share the globalPrefixes
map.
Utility for merging plugin options.
const {mergeOptions} = require('gulp-i18n-update-localization-ids');
const task = i18nUpdateLocalizationIds(mergeOptions(defaults, overrides));
- defaults
<object>
- Default plugin options. - overrides
<object>
- Plugin options to override. - returns
<object>
- Merged plugin options.
Options are merged as follows:
whitelist
will contain all entries from defaults and overrides.ignore
will contain all ignore items from defaults and overrides.- all other options will be set from
overrides
ordefaults
if specified.
merge({
emit: 'onChangeOnly',
whitelist: [ {tagName: 'foo'} ],
ignore: {content: 'bar'}
}, {
idTemplate: x => `foo-${x}`,
whitelist: [ {tagName: 'bar'} ],
ignore: [
{content: 'foo'},
{tagName: 'code'}
]
});
// will be merged to:
{
whitelist: [
{tagName: 'foo'},
{tagName: 'bar'}
],
ignore: [
{content: 'bar'},
[
{content: 'foo'},
{tagName: 'code'}
]
],
emit: 'onChangeOnly',
idTemplate: x => `foo-${x}`
}
The following example will watch and process your html files during development.
You should be using an editor that reloads the file when it changes like vs code.
const gulp = require('gulp');
const i18nUpdateLocalizationIds = require('gulp-i18n-update-localization-ids');
exports.watch = () => gulp.watch(['./src/**.html'], () => {
return gulp.src('./src/**.html')
.pipe(i18nUpdateLocalizationIds({
emit: 'onChangeOnly',
whitelist: [
{tagName: 'h1'},
{tagName: 'img', attrs: ['alt']},
{tagName: 'custom-elem', attrs: ['title'], content: 'html'}
],
ignore: [
{content: v => v.startsWith('${') && v.endsWith('}')}
],
idTemplate: x => `foo-${x}`
}))
.pipe(gulp.dest('./src'));
});
If you run gulp watch
and save the following file...
<template>
<h1>Hello World!</h1>
<img t="[alt]foo-0" alt="Some image..">
<custom-elem t="[title]foo" title="Copy"></custom-elem>
<custom-elem t="[title]foo" title="and">paste</custom-elem>
<h1>${example.localizedTitle}</h1>
</template>
...it will be transformed into this:
<template>
<h1 t="foo-1">Hello World!</h1>
<img t="[alt]foo-0" alt="Some image..">
<custom-elem t="[title]foo" title="Copy"></custom-elem>
<custom-elem t="[title]foo-2;[html]foo-3" title="and">paste</custom-elem>
<h1>${example.localizedTitle}</h1>
</template>
git clone https://github.com/Netatwork-de/gulp-i18n-update-localization-ids
cd gulp-i18n-update-localization-ids
# Install dependencies:
# (this is also needed for publishing)
npm i
# Run tests and coverage:
npm test
# Run tests and watch for changes:
npm run watch