UNPKG

typeorm-translatable

Version:

Translation classes, utils and decorators for i18n in TypeORM

671 lines (549 loc) 21.1 kB
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