typeorm-translatable
Version:
Translation classes, utils and decorators for i18n in TypeORM
671 lines (549 loc) • 21.1 kB
JavaScript
import { __decorate, __metadata } from 'tslib';
import { PrimaryGeneratedColumn, Column, ManyToOne, Entity, getMetadataArgsStorage, OneToMany } from 'typeorm';
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
Object.defineProperty(Constructor, "prototype", {
writable: false
});
return Constructor;
}
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
_setPrototypeOf(subClass, superClass);
}
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _isNativeReflectConstruct() {
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
return true;
} catch (e) {
return false;
}
}
function _construct(Parent, args, Class) {
if (_isNativeReflectConstruct()) {
_construct = Reflect.construct.bind();
} else {
_construct = function _construct(Parent, args, Class) {
var a = [null];
a.push.apply(a, args);
var Constructor = Function.bind.apply(Parent, a);
var instance = new Constructor();
if (Class) _setPrototypeOf(instance, Class.prototype);
return instance;
};
}
return _construct.apply(null, arguments);
}
function _isNativeFunction(fn) {
return Function.toString.call(fn).indexOf("[native code]") !== -1;
}
function _wrapNativeSuper(Class) {
var _cache = typeof Map === "function" ? new Map() : undefined;
_wrapNativeSuper = function _wrapNativeSuper(Class) {
if (Class === null || !_isNativeFunction(Class)) return Class;
if (typeof Class !== "function") {
throw new TypeError("Super expression must either be null or a function");
}
if (typeof _cache !== "undefined") {
if (_cache.has(Class)) return _cache.get(Class);
_cache.set(Class, Wrapper);
}
function Wrapper() {
return _construct(Class, arguments, _getPrototypeOf(this).constructor);
}
Wrapper.prototype = Object.create(Class.prototype, {
constructor: {
value: Wrapper,
enumerable: false,
writable: true,
configurable: true
}
});
return _setPrototypeOf(Wrapper, Class);
};
return _wrapNativeSuper(Class);
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _createForOfIteratorHelperLoose(o, allowArrayLike) {
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (it) return (it = it.call(o)).next.bind(it);
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
return function () {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
/**
* Thrown when an entity is not translatable
*/
var NotTranslatableException = /*#__PURE__*/function (_Error) {
_inheritsLoose(NotTranslatableException, _Error);
function NotTranslatableException(message) {
var _this;
_this = _Error.call(this, message) || this;
Object.setPrototypeOf(_assertThisInitialized(_this), NotTranslatableException.prototype);
return _this;
}
return NotTranslatableException;
}( /*#__PURE__*/_wrapNativeSuper(Error));
/**
* Thrown when translation entities are already generated
*/
var AlreadyGeneratedException = /*#__PURE__*/function (_Error2) {
_inheritsLoose(AlreadyGeneratedException, _Error2);
function AlreadyGeneratedException(message) {
var _this2;
_this2 = _Error2.call(this, message) || this;
Object.setPrototypeOf(_assertThisInitialized(_this2), AlreadyGeneratedException.prototype);
return _this2;
}
return AlreadyGeneratedException;
}( /*#__PURE__*/_wrapNativeSuper(Error));
/**
* Thrown when entity manager is not found
*/
var EntityManagerNotFoundException = /*#__PURE__*/function (_Error3) {
_inheritsLoose(EntityManagerNotFoundException, _Error3);
function EntityManagerNotFoundException(message) {
var _this3;
_this3 = _Error3.call(this, message) || this;
Object.setPrototypeOf(_assertThisInitialized(_this3), EntityManagerNotFoundException.prototype);
return _this3;
}
return EntityManagerNotFoundException;
}( /*#__PURE__*/_wrapNativeSuper(Error));
/**
* Throw when translation entity is not found
*/
var TranslationEntityNotFoundException = /*#__PURE__*/function (_Error4) {
_inheritsLoose(TranslationEntityNotFoundException, _Error4);
function TranslationEntityNotFoundException(message) {
var _this4;
_this4 = _Error4.call(this, message) || this;
Object.setPrototypeOf(_assertThisInitialized(_this4), TranslationEntityNotFoundException.prototype);
return _this4;
}
return TranslationEntityNotFoundException;
}( /*#__PURE__*/_wrapNativeSuper(Error));
/**
* Get translatable fields from translatable entity
*/
var getTranslatableFields = function getTranslatableFields(entity) {
return entity.constructor.translatableFields;
};
var isTranslation = function isTranslation(translation) {
if (typeof translation === 'object' && translation !== null && 'locale' in translation) {
return true;
}
return false;
};
/**
* Check if an entity is translatable or not
* @param entity Entity to check
* @returns True if entity is translatable, false otherwise
*/
var isTranslatable = function isTranslatable(entity) {
if (entity.translations === undefined || entity.translations.length === 0) {
return false;
}
for (var _iterator = _createForOfIteratorHelperLoose(entity.translations), _step; !(_step = _iterator()).done;) {
var translation = _step.value;
if (!isTranslation(translation)) {
return false;
}
}
return true;
};
/**
* Translate the entity to the given locale
* @param entity The entity to translate
* @param locale The locale to translate
* @param options Translation options
* @throws {NotTranslatableException} If entity is not translatable
* @returns Translated entity
*/
var translateEntity = function translateEntity(entity, locale, _temp) {
var _translatedEntity$tra;
if (locale === void 0) {
locale = TranslationConfig.getInstance().getLocale();
}
var _ref = _temp === void 0 ? {} : _temp,
_ref$shouldDelete = _ref.shouldDelete,
shouldDelete = _ref$shouldDelete === void 0 ? TranslationConfig.getInstance().shouldDelete : _ref$shouldDelete,
_ref$shouldMutate = _ref.shouldMutate,
shouldMutate = _ref$shouldMutate === void 0 ? TranslationConfig.getInstance().shouldMutate : _ref$shouldMutate;
if (!isTranslatable(entity)) {
throw new NotTranslatableException('Entity is not translatable.');
}
var translatedEntity;
if (shouldMutate) {
translatedEntity = entity;
} else {
translatedEntity = Object.create(Object.getPrototypeOf(entity), Object.getOwnPropertyDescriptors(entity));
}
var translation = (_translatedEntity$tra = translatedEntity.translations) == null ? void 0 : _translatedEntity$tra.find(function (t) {
return t.locale === locale;
});
if (shouldDelete) {
if (shouldMutate) {
delete entity.translations;
}
delete translatedEntity.translations;
}
if (translation === undefined) {
return translatedEntity;
}
Object.keys(translatedEntity).forEach(function (key) {
var translatableFields = getTranslatableFields(translatedEntity);
if (translatableFields === undefined) {
throw new NotTranslatableException('Entity has to translatable fields.');
}
if (translatableFields.has(key)) {
var translatedValue = translation[key];
translatedEntity[key] = translatedValue;
}
});
return translatedEntity;
};
/**
* Entity that can be translated
*/
var TranslatableEntity = /*#__PURE__*/function () {
function TranslatableEntity() {}
var _proto = TranslatableEntity.prototype;
_proto.translate = function translate(locale, options) {
return translateEntity(this, locale, options);
};
return TranslatableEntity;
}();
/**
* Entity that contains translations for source entity
*/
var TranslationEntity = function TranslationEntity() {};
__decorate([PrimaryGeneratedColumn({
type: 'bigint',
unsigned: true
}), __metadata("design:type", String)], TranslationEntity.prototype, "id", void 0);
__decorate([Column('varchar', {
length: 6
}), __metadata("design:type", String)], TranslationEntity.prototype, "locale", void 0);
var TranslationConfig = /*#__PURE__*/function () {
function TranslationConfig() {
this.getLocale = function () {
return undefined;
};
this._shouldDelete = true;
this._shouldMutate = false;
this._entitySuffix = 'Translation';
this._translationMetadataArgsStorage = {
translatableTables: [],
translatableColumns: [],
translationsOneToManyRelations: []
};
this._translationEntitiesMap = new Map();
this.getEntityManager = function () {
return undefined;
};
/**
* Whether or not translation entities are already generated
*/
this.hasGenerated = false;
}
var _proto = TranslationConfig.prototype;
_proto.getTranslationMetadataArgsStorage = function getTranslationMetadataArgsStorage() {
return this._translationMetadataArgsStorage;
};
_proto.getTranslationEntities = function getTranslationEntities() {
return Array.from(this._translationEntitiesMap.values());
}
/**
* Use provided translation config
* @param config Config to initialize
* @throws {AlreadyGeneratedException} when trying to change entitySuffix after translation entities are already generated
*/
;
TranslationConfig.use = function use(config) {
var getLocale = config.getLocale,
shouldDelete = config.shouldDelete,
shouldMutate = config.shouldMutate,
entitySuffix = config.entitySuffix,
getEntityManager = config.getEntityManager;
if (getLocale !== undefined) {
this._instance.getLocale = getLocale;
}
if (shouldDelete !== undefined) {
this._instance._shouldDelete = shouldDelete;
}
if (shouldMutate !== undefined) {
this._instance._shouldMutate = shouldMutate;
}
if (entitySuffix !== undefined) {
if (this._instance.hasGenerated) {
throw new AlreadyGeneratedException('Cannot change entity suffix after translation entities are generated.');
}
this._instance._entitySuffix = entitySuffix;
}
if (getEntityManager !== undefined) {
this._instance.getEntityManager = getEntityManager;
}
};
TranslationConfig.getInstance = function getInstance() {
return this._instance;
}
/**
* Generate translation entities for usage with decorators
* @throws {AlreadyGeneratedException} when trying to generate translation entities again
* @returns generated translation entities
* @experimental
*/
;
TranslationConfig.generate = function generate() {
var _this = this;
if (this._instance.hasGenerated) {
throw new AlreadyGeneratedException('Translation entities are already generated.');
}
var _this$_instance$_tran = this._instance._translationMetadataArgsStorage,
translatableTables = _this$_instance$_tran.translatableTables,
translatableColumns = _this$_instance$_tran.translatableColumns,
translationsOneToManyRelations = _this$_instance$_tran.translationsOneToManyRelations;
translatableTables.forEach(function (_ref) {
var target = _ref.target,
options = _ref.options;
var tableColumns = translatableColumns.filter(function (column) {
return column.target === target;
});
var SourceClass = typeof target === 'string' ? TranslatableEntity : target;
var GeneratedTranslatableEntity = /*#__PURE__*/function (_TranslationEntity) {
_inheritsLoose(GeneratedTranslatableEntity, _TranslationEntity);
function GeneratedTranslatableEntity() {
return _TranslationEntity.apply(this, arguments) || this;
}
return GeneratedTranslatableEntity;
}(TranslationEntity);
__decorate([ManyToOne(function () {
return SourceClass;
}, function (source) {
return source.translations;
}), __metadata("design:type", Object)], GeneratedTranslatableEntity.prototype, "source", void 0);
Object.defineProperty(GeneratedTranslatableEntity, 'name', {
value: "" + (typeof target === 'string' ? target : target.name) + _this._instance._entitySuffix,
writable: false
});
Entity(options)(GeneratedTranslatableEntity);
tableColumns.forEach(function (_ref2) {
var target = _ref2.target,
propertyName = _ref2.propertyName,
options = _ref2.options;
var sourceColumn = getMetadataArgsStorage().columns.find(function (column) {
return column.target === target && column.propertyName === propertyName;
});
var SourceClass = target;
SourceClass.translatableFields.add(propertyName);
Column(_extends({}, options, {
type: (options == null ? void 0 : options.type) || (sourceColumn == null ? void 0 : sourceColumn.options.type)
}))(new GeneratedTranslatableEntity(), propertyName);
});
var tableOneToManyRelations = translationsOneToManyRelations.filter(function (relation) {
return relation.target.constructor === target;
});
tableOneToManyRelations.forEach(function (_ref3) {
var target = _ref3.target,
propertyName = _ref3.propertyName,
options = _ref3.options;
OneToMany(function () {
return GeneratedTranslatableEntity;
}, function (translation) {
return translation.source;
}, options)(target, propertyName);
});
_this._instance._translationEntitiesMap.set(target, GeneratedTranslatableEntity);
});
this._instance.hasGenerated = true;
return this._instance.getTranslationEntities();
}
/**
* Get respective translation entity repository for given entity
* @param target entity to get translation entity for
* @param manager entity manager to get translation entity repository, if not provided, will try to get from default config
* @returns translation entity repository
* @experimental
*/
;
TranslationConfig.getTranslationRepository = function getTranslationRepository(target, manager) {
manager = this.getResolvedManager(manager);
return manager.getRepository(this.getTranslationEntity(target));
}
/**
* Get respective translation entity for given entity
* @param target entity to get translation entity for
* @param manager entity manager to get translation entity, if not provided, will try to get from default config
* @returns translation entity
* @experimental
*/
;
TranslationConfig.getTranslationEntity = function getTranslationEntity(target, manager) {
manager = this.getResolvedManager(manager);
var TranslationEntity = this._instance._translationEntitiesMap.get(manager.connection.getMetadata(target).target);
if (!TranslationEntity) {
throw new TranslationEntityNotFoundException('Could not find translation entity for entity' + target);
}
return TranslationEntity;
};
TranslationConfig.getResolvedManager = function getResolvedManager(manager) {
manager = manager || this._instance.getEntityManager();
if (!manager) {
throw new EntityManagerNotFoundException('Could not resolve entity manager. Provide in the function call or set default in config.');
}
return manager;
};
_createClass(TranslationConfig, [{
key: "shouldDelete",
get: function get() {
return this._shouldDelete;
}
}, {
key: "shouldMutate",
get: function get() {
return this._shouldMutate;
}
}, {
key: "entitySuffix",
get: function get() {
return this._entitySuffix;
}
}]);
return TranslationConfig;
}();
TranslationConfig._instance = /*#__PURE__*/new TranslationConfig();
/**
* Custom repository that intercepts all queries and adds translation
* @param manager Entity manager
* @param locale Locale to use
* @throws {NotTranslatableException} If locale cannot be resolved
* @returns empty object
* @experimental All methods might not work as expected
*/
var TranslatableRepository = function TranslatableRepository(manager, locale) {
manager.createQueryBuilder = function createQueryBuilder(entityClass, alias, queryRunner) {
var resolvedLocale = locale != null ? locale : TranslationConfig.getInstance().getLocale();
if (resolvedLocale === undefined) {
throw new NotTranslatableException('No locale specified');
}
if (alias) {
return this.connection.createQueryBuilder(entityClass, alias, queryRunner || this.queryRunner).leftJoinAndSelect(alias + ".translations", 'translation', 'translation.locale = :locale', {
locale: resolvedLocale
});
} else {
return this.connection.createQueryBuilder(entityClass || queryRunner || this.queryRunner);
}
};
return {};
};
/**
* Create a translation entity for the target entity
* @experimental
*/
var Translatable = function Translatable(options) {
return function (target) {
TranslationConfig.getInstance().getTranslationMetadataArgsStorage().translatableTables.push({
target: target,
options: options
});
};
};
/**
* Create a column in translation entity of the target entity and put the property name in the `translatableFields` of source entity.
* @experimental
*/
var TranslatableColumn = function TranslatableColumn(options) {
return function (target, propertyName) {
TranslationConfig.getInstance().getTranslationMetadataArgsStorage().translatableColumns.push({
target: target.constructor,
propertyName: propertyName.toString(),
options: options
});
};
};
/**
* Create a one-to-many relation between translation entity and target entity.
* @experimental
*/
var Translations = function Translations(options) {
return function (target, propertyName) {
TranslationConfig.getInstance().getTranslationMetadataArgsStorage().translationsOneToManyRelations.push({
target: target,
propertyName: propertyName.toString(),
options: options
});
};
};
export { AlreadyGeneratedException, EntityManagerNotFoundException, NotTranslatableException, Translatable, TranslatableColumn, TranslatableEntity, TranslatableRepository, TranslationConfig, TranslationEntity, TranslationEntityNotFoundException, Translations, getTranslatableFields, isTranslatable, isTranslation, translateEntity };
//# sourceMappingURL=typeorm-translatable.esm.js.map