Transloco: Tell Us What Your Translation Process is Like

Created on 18 Aug 2019  路  17Comments  路  Source: ngneat/transloco

In order for us to further develop the library, and meet all your translation needs, we'd love to learn what the translation process in your company is like.

For instance, here in Datorama, we use a local JSON file. Each developer adds keys to the file for any missing translations, where the value is the text in English. The developer then uses the keys in the various component templates.

For example:

// locale_en_US.json
"sandbox": {
  "copy-error": "Copy to sandbox is temporarily not available"
}
<div>{{ 'sandbox.copy-error' | transloco }}</div>

The file is sent once a month to translators, who return a translation file with the same keys, and the values translated into a different language.

// locale_es.json
"sandbox": {
  "copy-error": "spanish translation"
}
discussion

Most helpful comment

In my current project, I first write the translation keys in the teplate / in the typescript code. Then I'll use ngx-translate-extract to extract the keys into my 4 translation json files (de, en, es, fr).
I'll then enter a default-translation into the english json file and hand the 4 files over to the customer for translation.
So for us the extract tool is really a relief.

All 17 comments

In our company, we need to provide more information to translators because some terms must be explained. We plan to add some description and suggest translator use Poeditor to translate

@zack9433 Thanks. Our translators also ask to add it. In our case, they want it to be added to the file itself.

{
  "copy-error": "value",
  "copy-error.comment": "explanation"
}

But this will increase the bundle size, so we move the comments to a separate file.

@NetanelBasal Is it possible this extra information which is for translator can remove at build time? By the way, I think angular i18n did a great job for improving translate file experience between developer and translator.

I think angular i18n did a great job for improving translate file experience between developer and translator.

@zack9433 can you elaborate more, please?

In my current project, I first write the translation keys in the teplate / in the typescript code. Then I'll use ngx-translate-extract to extract the keys into my 4 translation json files (de, en, es, fr).
I'll then enter a default-translation into the english json file and hand the 4 files over to the customer for translation.
So for us the extract tool is really a relief.

@ChristofFritz we'll add this tool soon.

@NetanelBasal I mean developer can output a file for poedit and translator rely on it to do their works. Our translator want to use a tool to help them.

Not necessarily related to translator / developer relationship, but what I've been doing with ngx-translate is that along my <feature>.module.ts (a "feature" being mostly a lazy loaded routed page, as I tend to provide already translated string to my common components intead of using translate directives / pipes inside them) I created <feature>.translations.ts, which is a module that I import in my <feature>.module.ts, this module

a) enables ngx-translate directive
b) merges its translations to the global scope, by using something the lines of

this._translate.setTranslation('cs', {
   pages: {
    about: CS // const containing all czech translations
  }
}, true);

After that you can do

<span translate="pages.about.myKey">

basically the idea behind it that you don't lazy load your module and then lazy loading its translations, but you lazy load the module along with its translations and that you don't have to have deeply nested objects in your translations object / file, since it's taken care of by defining the path inside the setTranslation.

@fxck If I understand you correctly you can easily do it with Transloco:

const routes: Routes = [
  {
    path: '',
    component: LazyComponent
  }
];

@NgModule({
  declarations: [LazyComponent],
  providers: [
    { provide: TRANSLOCO_SCOPE, useValue: 'admin-page' },
  ],
  imports: [CommonModule, RouterModule.forChild(routes), TranslocoModule]
})
export class LazyModule {}

This part will make sure we only load the admin-page/activeLang.json and everything inside the module will be scoped to admin-page translation:

<ng-container *transloco="let t;">
  <p>{{ t.title }}</p>
</ng-container>

So t.title will be taken from the admin-page file.

Yeah the problem with that (my colleague which is trying transloco out will probably create an issue, as I'm on holidays), is that inside of your lazy component you might be using some common components, so scoping it all to "admin-pages" might be contraproductive, since you won't have the access to the common translations. But then again, I haven't had a chance to try it out, only talking about what's been reported to me.

// edit https://github.com/ngneat/transloco/issues/24 basically you should still have access to the global/ common translations while scoping

@fxck I looked into your comment again, and it should work the same with Transloco:

this.translocoService.setTranslation({
   pages: {
    about: CS
  }
}, 'cs');

We're working about a built-in implementation to save you the boilerplate work.

I have just created a new ng app to play with transloco. Will drop my observations as I go, if you don't mind.

So far I have been using ngx-translate. Not sure what kind of difference transloco wants to make - so maybe my observations could be responded with "Hey, that's exactly what we find limiting and we do not want to take that path." Please excuse me if this is the case :) but since this issue is entitled "Tell us what you translation process is Like", I feel free to speak out :)

My first observation is how the translation files are organized. Transloco currently creates one file per language. I would say that in mid-sized apps this organization might be still too opinionated - users might want to split a language into some logical chunks. So far I have always been having en, fr as the name of the grouping folder, and then atomic json files, named like products.json, general.json and so on. The base name of the file was then corresponding to the first part in translation key, such as <button>{{ 'general.cancel' | translate }}</button>

Not sure how transloco is meant to load translations in big apps featuring many lazy-loaded modules - would the translations still reside in the main app assets or be loaded lazily along with the module? (an example would be a great thing to have!)

Transloco currently creates one file per language

Transloco doesn't force anything.

The base name of the file was then corresponding to the first part in translation key, such as

You need to write some code to make it work with ngx-translate, right? It's not magically appeared.

Not sure how transloco is meant to load translations in big apps featuring many lazy-loaded modules - would the translations still reside in the main app assets or be loaded lazily along with the module?

Everything will be lazy-loaded based on the current lang/scope, and will be merged into the active language.

You need to write some code to make it work with ngx-translate, right? It's not magically appeared.

Right. I am just describing my environment. You might want to consider it as an idea to allow a more split approach within one module and free users from writing custom loaders.

Everything will be lazy-loaded based on the current lang/scope, and will be merged into the active language.

That is cool!

We are aiming to save you the boilerplate work. You should only define the scope mapping, and we'll take care of the lazily loading and merging. For example:

{
  provide: TRANSLOCO_CONFIG,
  useValue: {
    scopeMapping: {
     'admin-page': 'admin'
    }
    ...  
  }
}

Then, when you define the admin-page scope in a lazy load module:

@NgModule({
  declarations: [LazyComponent],
  providers: [
    { provide: TRANSLOCO_SCOPE, useValue: 'admin-page' },
  ],
  imports: [CommonModule, RouterModule.forChild(routes), TranslocoModule]
})
export class LazyModule {}

It will load the scoped module for you, and will make the translation value available under the admin key:

<ng-container *transloco="let t;">
  <p>{{ t.admin.keyFromAdminFile }}</p>
</ng-container>

{{ 'admin.keyFromAdminFile' | transloco }}

@fxck @moniuch would love to hear your opinion about the upcoming feature:
https://github.com/ngneat/transloco/issues/24#issuecomment-524056486

@fxck I looked into your comment again, and it should work the same with Transloco:

this.translocoService.setTranslation({
   pages: {
    about: CS
  }
}, 'cs');

We're working about a built-in implementation to save you the boilerplate work.

Should this work with the currently release version? Because it doesn't seem to, not sure if I'm doing something wrong.

I'm getting NullInjectorError: No provider for InjectionToken TRANSLOCO_LOADER!, which I think I shouldn't even need when I'm providing translations manually, right?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

NetanelBasal picture NetanelBasal  路  6Comments

nulee picture nulee  路  6Comments

SparkMonkey picture SparkMonkey  路  7Comments

hc-codersatlas picture hc-codersatlas  路  3Comments

karmasakshi picture karmasakshi  路  6Comments