New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@actra-development-oss/ng-i18n-aot-loader

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@actra-development-oss/ng-i18n-aot-loader - npm Package Compare versions

Comparing version 0.0.5 to 1.0.0

CHANGELOG.md

56

index.js

@@ -40,3 +40,3 @@ /**

let query = loaderUtils.getOptions(context) || {};
let configKey = query.config || 'ng2I18nLoader';
let configKey = query.config || 'ngI18nAotLoader';
let config = context.options && context.options.hasOwnProperty(configKey) ? context.options[configKey] : {};

@@ -50,20 +50,20 @@

function random4Chars() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
};
/**
* Uniq ID generator for automatically inserted template references
*/
function uniqId() {
return (random4Chars() + random4Chars() + random4Chars() + random4Chars() + random4Chars() + random4Chars() + random4Chars() + random4Chars());
}
/**
* Recursive HTML visitor to render real HTML contents from parsed files
*/
class Visitor extends compiler.RecursiveVisitor {
s4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
};
/**
* Uniq ID generator for automatically inserted template references
*/
uniqId() {
return (this.s4() + this.s4() + this.s4() + this.s4() + this.s4() + this.s4() + this.s4() + this.s4());
}
/**
* Set if templates should be generated

@@ -101,3 +101,3 @@ */

if(!!this.templateGeneration) {
this.templateIds.push(this.uniqId());
this.templateIds.push(uniqId());
this.templates.push('<ng-template #automaticallyGeneratedTemplate' + this.templateIds[this.templateElementCount] + '>' + element + '</ng-template>');

@@ -171,18 +171,13 @@ }

let config = getLoaderConfig(this);
let binding = config.hasOwnProperty('localeBinding') && 'string' === typeof config.localeBinding && config.localeBinding.length ? config.localeBinding : 'i18nLocaleBindingProperty';
let result = content;
let formats = {'xliff': 'Xliff', 'xlf': 'Xliff', 'xliff2': 'Xliff2', 'xlf2': 'Xliff2', 'xmb': 'Xmb', 'xtb': 'Xtb'};
if(!config.hasOwnProperty('enabled') || !config.enabled) {
return result;
return content;
}
if('i18nLocaleBindingProperty' === binding) {
console.warn('It seems there was no "localeBinding" specified in the config, falling back to default "i18nLocaleBindingProperty".');
}
if(!config.hasOwnProperty('translationFiles') || !Array.isArray(config.translationFiles) || 1 > config.translationFiles.length) {
if(!config.hasOwnProperty('translationFiles') || !Array.isArray(config.translationFiles) ||
1 > config.translationFiles.filter(function(file) { return !!('string' === typeof file && 0 < file.length); }).length) {
console.warn('It seems there were no "translationFiles" specified in the config, skipping.');
return result;
return content;
}

@@ -193,5 +188,6 @@

return result;
return content;
}
let result = content;
let format = config.translationFormat.toLowerCase();

@@ -213,2 +209,3 @@ let serializer = new compiler[formats[format]]();

let templatesGenerated = false;
let identifier = uniqId();

@@ -234,3 +231,3 @@ config.translationFiles.forEach(function(file) {

containers += '<ng-container *ngSwitchCase="\'' + String(locale) + '\'">' + compiler.visitAll(visitor, parsed.rootNodes).join('') + '</ng-container>';
containers += '<ng-container *ngI18nAot="\'' + identifier + '\'; locale: \'' + String(locale) + '\'">' + compiler.visitAll(visitor, parsed.rootNodes).join('') + '</ng-container>';
}

@@ -257,5 +254,6 @@ else {

containers += '<ng-container *ngSwitchDefault>' + compiler.visitAll(visitor, parsed.rootNodes).join('') + '</ng-container>';
result = '<ng-container [ngSwitch]="' + binding + '">' + containers + '</ng-container>' + visitor.getTemplates(true);
result =
containers +
'<ng-container *ngI18nAot="\'' + identifier + '\'; isDefault: true">' + compiler.visitAll(visitor, parsed.rootNodes).join('') + '</ng-container>' +
visitor.getTemplates(true);
}

@@ -262,0 +260,0 @@ else {

@@ -11,3 +11,3 @@ {

"license": "MIT",
"version": "0.0.5",
"version": "1.0.0",
"author": {

@@ -38,14 +38,49 @@ "name": "Gabriel Schuster - actra.development",

},
"devDependencies": {},
"peerDependencies": {},
"devDependencies": {
"mkdirp": "0.5.1",
"ncp": "2.0.0",
"npm-run-all": "4.0.2",
"rimraf": "2.6.1",
"rollup": "0.43.0",
"uglify-js": "3.0.21",
"yarn": "0.24.6"
},
"peerDependencies": {
"@angular/core": "^4.1.0"
},
"files": [
"index.js",
"LICENSE",
"package.json",
"README.md"
"dist/index.js",
"dist/index.umd.js",
"dist/index.umd.min.js",
"dist/CHANGELOG.md",
"dist/LICENSE",
"dist/package.json",
"dist/README.md"
],
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"build": "yarn run run-s -- build:clean build:copy",
"build:clean": "yarn run rimraf -- ./dist && yarn run mkdirp -- ./dist",
"build:copy": "yarn run run-s -- build:copy-1 build:copy-2 build:copy-3 build:copy-4 build:copy-5",
"build:copy-1": "yarn run ncp -- ./package.json ./dist/package.json",
"build:copy-2": "yarn run ncp -- ./CHANGELOG.md ./dist/CHANGELOG.md",
"build:copy-3": "yarn run ncp -- ./index.js ./dist/index.js",
"build:copy-4": "yarn run ncp -- ./LICENSE ./dist/LICENSE",
"build:copy-5": "yarn run ncp -- ./README.md ./dist/README.md",
"publishToNpmjs": "yarn run build && npm publish ./dist --access public --registry https://registry.npmjs.com/",
"mkdirp": "./node_modules/.bin/mkdirp",
"ncp": "./node_modules/.bin/ncp",
"rimraf": "./node_modules/.bin/rimraf",
"rollup": "./node_modules/.bin/rollup",
"run-s": "./node_modules/.bin/run-s",
"uglifyjs": "./node_modules/.bin/uglifyjs",
"yarn": "./node_modules/.bin/yarn"
}
}

@@ -9,6 +9,7 @@ # ng-i18n-aot-loader [Proof-Of-Concept]

## What it does
The loader modifies the application's HTML before it get's passed to angular's compiler by rendering it for each locale and wrapping all translations into `ng-container`s with `ng-switch`.
The loader modifies the application's HTML before it get's passed to angular's compiler by rendering it for each locale and wrapping all translations into `ng-container`s.
If you're using `ng-content` or `router-outlet` inside your templates those get filtered out and replaced by a template reference injected to the end of the HTML because they may only occur once per
document but would occur multiple times (your number of locales + 1) after modification.
All bindings and contexts stay intact and there's no need to do special magic to your code.
All bindings and contexts stay intact and there's no need to do special magic to your code.
To actually change the displayed locale, a service is provided (by `@actra-development-oss/ng-i18n-aot-module`) that you may include in your component(s) to call `setLocale('new_locale')` on it.

@@ -21,3 +22,3 @@

So the process would be: `change html` => `extract texts` => `update translations` => `rebuild html`.
Depending on your dev setup webpack may to the HTML rebuild automatically for you when the translation files change.
Depending on your dev setup webpack may do the HTML rebuild automatically for you when the translation files change.
If not you can trigger a HTML rebuild for individual files simply by updating the desired file, e.g. adding a new-line, and saving it for webpack to catch the change.

@@ -44,30 +45,28 @@

```html
<ng-container [ngSwitch]="locale">
<ng-container *ngSwitchCase="'de-DE'">
<div class="mat-app-background">
<ng-container *ngTemplateOutlet="automaticallyGeneratedTemplate1"></ng-container>
<md-chip-list>
<md-chip>Erster Chip</md-chip>
<md-chip color="primary" title="Zweiter Chip :)">Zweiter Chip</md-chip>
<md-chip color="accent">Dritter Chip</md-chip>
</md-chip-list>
<ng-container *ngTemplateOutlet="automaticallyGeneratedTemplate2"></ng-container>
</div>
</ng-container>
<ng-container *ngSwitcDefault>
<div class="mat-app-background">
<ng-container *ngTemplateOutlet="automaticallyGeneratedTemplate1"></ng-container>
<md-chip-list>
<md-chip>First chip</md-chip>
<md-chip color="primary" title="Second chip :-)">Second chip</md-chip>
<md-chip color="accent">Third chip</md-chip>
</md-chip-list>
<ng-container *ngTemplateOutlet="automaticallyGeneratedTemplate2"></ng-container>
</div>
</ng-container>
<ng-container *ngI18nAot="'automaticallyGeneratedUniqueIdPerHtmlFile'; locale: 'de-DE'">
<div class="mat-app-background">
<ng-container *ngTemplateOutlet="automaticallyGeneratedTemplate1"></ng-container>
<md-chip-list>
<md-chip>Erster Chip</md-chip>
<md-chip color="primary" title="Zweiter Chip :)">Zweiter Chip</md-chip>
<md-chip color="accent">Dritter Chip</md-chip>
</md-chip-list>
<ng-container *ngTemplateOutlet="automaticallyGeneratedTemplate2"></ng-container>
</div>
</ng-container>
<ng-container *ngI18nAot="'automaticallyGeneratedUniqueIdPerHtmlFile'; isDefault: true">
<div class="mat-app-background">
<ng-container *ngTemplateOutlet="automaticallyGeneratedTemplate1"></ng-container>
<md-chip-list>
<md-chip>First chip</md-chip>
<md-chip color="primary" title="Second chip :-)">Second chip</md-chip>
<md-chip color="accent">Third chip</md-chip>
</md-chip-list>
<ng-container *ngTemplateOutlet="automaticallyGeneratedTemplate2"></ng-container>
</div>
</ng-container>
<ng-template #automaticallyGeneratedTemplate1><ng-content></ng-content></ng-template>

@@ -85,3 +84,3 @@ <ng-template #automaticallyGeneratedTemplate2><router-outlet></router-outlet></ng-template>

## How to use it
Install the package `npm install @actra-development-oss/ng-i18n-aot-loader` and define it as a pre-loader in your webpack config:
Install the packages `npm install @actra-development-oss/ng-i18n-aot-loader @actra-development-oss/ng-i18n-aot-module` and define the loader as a pre-loader in your webpack config:
```js

@@ -98,4 +97,3 @@ module: {

enabled: true,
localeBinding: 'locale',
translationFiles: glob.sync('/path/to/src/locales/**/messages.*.xlf'),
translationFiles: ['/path/to/src/locales/messages.de.xlf'],
translationFormat: 'xliff'

@@ -116,37 +114,68 @@ }

```
NB: I'm using `glob.sync()` for the option `translationFiles` for convenience, any other tool would suffice as long as the result is an array of strings, you may even specify the paths by hand.
In every component that has a translatable template you now need to specify the public property `locale` in order for the `ng-switch` to fire:
Include the module into your applications main module:
```typescript
@Component({
import { NgI18nAotModule } from '@actra-development-oss/ng-i18n-aot-module';
// ...
@NgModule({
// ...
imports: [
NgI18nAotModule.forRoot(),
// ...
],
// ...
})
export class MyComponent {
public locale: string = 'en_US';
@Injectable()
export class ApplicationModule {
// ...
}
```
To actually switch the locale, the component has to be notified of changes to the locale, e.g. by subscribing to a service, using a redux-store or whatever you like.
In my test-project I used redux with it's `@select()`-syntax and subscribed my components like so:
Include the module into a) every module that uses translations *OR* b) once into your shared module that is included in all your modules.
Code shows option b), include in shared module:
```typescript
@Component({
import { NgI18nAotModule } from '@actra-development-oss/ng-i18n-aot-module';
// ...
@NgModule({
// ...
exports: [
NgI18nAotModule,
// ...
],
// ...
})
export class MyComponent {
@select(['application', 'locale']) public locale$: Observable<string>;
export class SharedModule {
}
```
As this now is an observable the loader-config needs to be sligthly adjusted so the `localeBinding` is recognized as async:
To actually change the displayed locale use the service:
```typescript
// ...
use: [
{
loader: '@actra-development-oss/ng-i18n-aot-loader',
options: {
localeBinding: 'locale$ | async'
}
}
]
// ...
import { NgI18nAotService } from '@actra-development-oss/ng-i18n-aot-module';
@Component({
// ...
template: `
<button (click)="setLocale('en_US')">en_US</button> <button (click)="setLocale('de_DE')">de_DE</button><br />
Current locale: {{locale}}
`
})
export class MyComponent {
public locale: string;
constructor(protected ngI18nAotService: NgI18nAotService) {
this.locale = this.ngI18nAotService.getLocale();
}
public setLocale(locale: string): void {
this.locale = locale;
this.ngI18nAotService.setLocale(this.locale);
}
}
```

@@ -159,10 +188,3 @@

| enabled | boolean | Whether the loader should modify the HTML or not. |
| localeBinding | string | Name of your component's property that holds the locale.<br />When using an observable don't forget to specify as such:<br />e.g. `locale$ \| async` |
| translationFiles | string[] | Paths of all your locale files to render. |
| translationFormat | string | Format of the translation files as used by angular:<br />xlf / xliff, xlf2 / xliff2, xmb, xtb |
## Known caveats
As `ng-switch` on the used `ng-containers` removes the dom entirely, angular may (think to) detect expression changes after the view has been checked.
This simply is a timing problem, I didn't find a solid workaround for this until now.
As those console messages are disabled for production builds by angular just forget about them.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc