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

typeorm-translatable

v0.2.0

Published

Translation classes, utils and decorators for i18n in TypeORM

Downloads

232

Readme

typeorm-translatable · GitHub license npm version

Translation classes, utils, custom repositories and decorators for i18n in TypeORM.

Installation

NPM

npm install typeorm-translatable

Yarn

yarn add typeorm-translatable

Architecture

This library is not supposed to be used for adding translation columns in the same table. Instead, a separate table is used for translation. For each source/target entity (table), a translation entity (table) must be created. The source entity has One-To-Many relation with the created translation entity. (e.g Post has many PostTranslation.)

Usage

import { TranslatableEntity, Translation } from 'typeorm-translatable';
import { PostTranslation } from './post-translation.entity';
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class Post extends TranslatableEntity<PostTranslation> {
  @PrimaryGeneratedColumn({ type: 'bigint', unsigned: true })
  id?: number;

  @Column('varchar')
  title?: string;

  @Column('text')
  body?: string;

  @OneToMany(
    () => PostTranslation,
    postTranslation => postTranslation.source
  )
  translations?: Translation<PostTranslation>[] | undefined;

  static translatableFields = new Set(['title', 'body']);
}
import { Post } from './post.entity';
import { TranslationEntity } from 'typeorm-translatable';
import { Column, Entity, ManyToOne } from 'typeorm';

@Entity()
export class PostTranslation extends TranslationEntity<Post> {
  @Column('varchar')
  title?: string;

  @Column('text')
  body?: string;

  @ManyToOne(
    () => Post,
    post => post.translations
  )
  source?: Post | undefined;
}

For the target or source entity, extend TranslatableEntity class, add translations as one-to-many relation and add translatableFields static property. translatableFields must include fields that can be translated when using entity.translate method or translateEntity util function.

For the translation entity (table that has translations), extend TranslationEntity class, define translatable columns and add source as many-to-one relation.

Then when you retrieve data, left join translation entity.

let posts = await postRepository
  .createQueryBuilder('post')
  .leftJoinAndSelect(
    'post.translations',
    'translation',
    `translation.locale = :locale`,
    {
      locale,
    }
  )
  .getMany();

Output:

[
  {
    "id": "1",
    "title": "This is a title",
    "body": "This is a post",
    "translations": [
      {
        "id": "1",
        "locale": "my",
        "title": "ခေါင်းစဉ်",
        "body": "အကြောင်းအရာ"
      }
    ]
  }
]

For the above output, You may use entity.translate method to replace title and body with translated values.

posts = posts.map(post => post.translate());

Output:

[
  {
    "id": "1",
    "title": "ခေါင်းစဉ်",
    "body": "အကြောင်းအရာ"
  }
]

Use TranslationConfig to configure default options. You can use TranslationConfig.use many times (except for entitySuffix).

await appDataSource.initialize();

TranslationConfig.use({
  getLocale: () => 'my', // default locale that is used when translating, typically from req.locale or als.getStore().locale
  getEntityManager: () => appDataSource.manager, // only needed for using with decorators
  entitySuffix: 'Translation', // only needed for using with decorators
  shouldDelete: true, // whether or not translations should be deleted after translation
  shouldMutate: false, // whether or not given entity should be mutated after translation
});

Usage for repository extension (Experimental)

This is rather overriding the repository instead of extending it. TranslatableRepository will override the entityManager of repository to left join translation entity automatically when doing select operations. *Important since entityManager's createQueryBuilder will be overridden, you need to create new entityManager. You can reuse this entityManager for all repositories with translation. But not the repositories without translation. Not doing so will result in issues like this .

const postManager = appDataSource.createEntityManager();
let postRepository = postManager.getRepository(Post);

postRepository = postRepository.extend(
  TranslatableRepository(postManager)
);

Then when you query entities, just use normal repository methods.

let posts = await postRepository.find();

This will output the same result as above. Also need to use entity.translate method for translation.

Caveats

TranslatableRepository.query method will not left join. It will just execute the given query and return the result.

Usage with decorators (Experimental)

You still need to extends the above mentioned classes. Classes decorated with Translatable wil generate a translation entity automatically. Class properties decorated with TranslatableColumn wil generate a column in the generated translation entity. Class property decorated with Translations will have one-to-many relation with the generated translation entity.

import {
  Translatable,
  TranslatableColumn,
  TranslatableEntity,
  Translation,
  TranslationEntity,
  Translations,
} from 'typeorm-translatable';
import { Column, Entity, PrimaryGeneratedColumn, ObjectLiteral } from 'typeorm';

@Translatable()
@Entity()
export class PostWithDecorators extends TranslatableEntity<
  TranslationEntity<ObjectLiteral>
> {
  @PrimaryGeneratedColumn({ type: 'bigint', unsigned: true })
  id?: number;

  @TranslatableColumn()
  @Column('varchar')
  title?: string;

  @TranslatableColumn()
  @Column('text')
  body?: string;

  @Translations()
  translations?: Translation<TranslationEntity<ObjectLiteral>>[] | undefined;

  static translatableFields = new Set(['title', 'body']);
}

Then translation entities need to be generated and need to be added into TypeORM dataSourceOptions.entities. Use TranslationConfig.generate method to generate and get translation entities.

entities: [
  PostWithDecorators,
  ...TranslationConfig.generate(),
],

You can access the generated translation entity by using getTranslationEntity method.

const PostTranslation = TranslationConfig.getTranslationEntity(
  PostWithDecorators
);

See more examples here.

API

Coming soon..., please read the source code for now :)

Credits