Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Overide the interpolate using the new instance method `setInterpolateFn`.
- The concrete interpolation method `doInterpolate` is now public.

## [1.1.0] - 2024-09-09
### Fixed
Expand Down
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,29 @@ Note that this library currently only supports an algorithm for English-like plu

As seen above, the `count` option can be used both for pluralization and interpolation.

### Interpolation overriding

Sometimes it can be useful to transform a translation before or after interpolation variables get applied.
To do so, configure your translator:

```js
const prev = translate.setInterpolateFn((entry, options) => {
if (typeof entry !== 'string') {
// you may need to continue the process unless the entry is a string.
// for example, entry is a function when translation is pluralized
return entry;
}

let interpolated = entry;
interpolated = applyModificationBefore(interpolated, options);
interpolated = translate.doInterpolate(interpolated, options);
interpolated = applyModificationAfter(interpolated, options);
})

// you can restore previous function later
translate.setInterpolateFn(prev)
```

### Fallbacks

If for a key no translation could be found, `translate` returns an error string of the form "translation missing: %(key)s".
Expand Down
14 changes: 12 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class Counterpart extends EventTarget {
this._registry = {
locale: 'en',
interpolate: true,
interpolateFn: (entry, options) => {
return this.doInterpolate(entry, options);
},
fallbackLocales: [],
scope: null,
translations: {},
Expand Down Expand Up @@ -185,6 +188,13 @@ Counterpart.prototype.getInterpolate = function () {
return this._registry.interpolate;
};

Counterpart.prototype.setInterpolateFn = function (fn) {
var previous = this._registry.interpolateFn;
this._registry.interpolateFn = fn;

return previous;
};

Counterpart.prototype.setKeyTransformer = function (value) {
var previous = this._registry.keyTransformer;
this._registry.keyTransformer = value;
Expand Down Expand Up @@ -320,7 +330,7 @@ Counterpart.prototype.translate = function (key, options) {
entry = this._pluralize(locale, entry, options.count);

if (this._registry.interpolate !== false && options.interpolate !== false) {
entry = this._interpolate(entry, options);
entry = this._registry.interpolateFn(entry, options);
}

return entry;
Expand Down Expand Up @@ -442,7 +452,7 @@ Counterpart.prototype._normalizeKey = function (key, separator) {
return this._registry.normalizedKeys[separator][key];
};

Counterpart.prototype._interpolate = function (entry, values) {
Counterpart.prototype.doInterpolate = function (entry, values) {
if (typeof entry !== 'string') {
return entry;
}
Expand Down
2 changes: 2 additions & 0 deletions index.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,15 @@ export type ErrorHandler = (evt: {
}) => void;

declare function translate(key: string | string[], options?: Options): string;
declare function interpolateFn(string, Options): string;

declare class Counterpart {
constructor(): this;

translate: typeof translate;
localize(date: Date, options: { ... }): string;
setSeparator(value: string): string;
setInterpolateFn(fn: typeof interpolateFn): interpolateFn;
setMissingEntryGenerator(callback: (value: string) => void): void;
getLocale(): string;
setLocale(value: string): string;
Expand Down
90 changes: 90 additions & 0 deletions spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,70 @@ describe('translate', function () {
});
});
});

describe('with a custom #setInterpolateFn', function () {
it('returns the translation with a before & after modification', function () {
const prevFn = instance.setInterpolateFn((entry, options) => {
let interpolated = entry;

interpolated = interpolated.replaceAll('##', '**');
interpolated = instance.doInterpolate(interpolated, options);
interpolated = interpolated.replaceAll('__', '--');

return interpolated;
});

instance.registerTranslations('en', {
before:
'manipulate entry before ##, but not in params %(content)s',
after:
'manipulate entry after __, and also in params %(content)s',
});

const content = '## & __';

assert.equal(
instance.translate('before', {
content,
}),
'manipulate entry before **, but not in params ## & --',
);
assert.equal(
instance.translate('after', {
content,
}),
'manipulate entry after --, and also in params ## & --',
);

instance.setInterpolateFn(prevFn);
});

it('is able to use custom options', function () {
const prevFn = instance.setInterpolateFn((entry, options) => {
const params = options;
if (options.onlyParams) {
params.content = params.content.replaceAll('##', '++');
}
return instance.doInterpolate(entry, params);
});

instance.registerTranslations('en', {
key: '## manipulate content using a custom option: %(content)s',
});

const content = 'this is the content ##';

assert.equal(
instance.translate('key', {
content,
onlyParams: true,
}),
'## manipulate content using a custom option: this is the content ++',
);

instance.setInterpolateFn(prevFn);
});
});
});

describe('with a translation for a prefix of the key present', function () {
Expand Down Expand Up @@ -1345,6 +1409,32 @@ describe('translate', function () {
});
});

describe('#setInterpolateFn', function () {
it('is a function', function () {
assert.isFunction(instance.setInterpolateFn);
});

it('sets the interpolate function in the registry', function () {
var prev = instance._registry.interpolate;

const custom = () => {};
instance.setInterpolateFn(custom);
assert.equal(instance._registry.interpolateFn, custom);

instance._registry.interpolate = prev;
});

it('returns the previous interpolate function that was stored in the registry', function () {
var custom = entry => {
return this.doInterpolate(entry);
};
var prev = instance._registry.interpolateFn;
var previous = instance.setInterpolateFn(custom);
assert.equal(prev, previous);
assert.equal(instance.setInterpolateFn(previous), custom);
});
});

describe('#getKeyTransformer', function () {
it('is a function', function () {
assert.isFunction(instance.getKeyTransformer);
Expand Down
Loading