├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── angular.json ├── package-lock.json ├── package.json ├── projects ├── ngx-translate-cache-example │ ├── browserslist │ ├── e2e │ │ ├── protractor.conf.js │ │ ├── src │ │ │ ├── app.e2e-spec.ts │ │ │ └── app.po.ts │ │ └── tsconfig.json │ ├── karma.conf.js │ ├── src │ │ ├── app │ │ │ ├── app.component.css │ │ │ ├── app.component.html │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ └── app.module.ts │ │ ├── assets │ │ │ ├── .gitkeep │ │ │ └── i18n │ │ │ │ ├── en.json │ │ │ │ ├── es.json │ │ │ │ └── it.json │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── styles.css │ │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── tslint.json └── ngx-translate-cache │ ├── LICENSE │ ├── README.md │ ├── karma.conf.js │ ├── ng-package.json │ ├── package.json │ ├── src │ ├── lib │ │ ├── ngx-translate-cache.module.ts │ │ └── ngx-translate-cache.service.ts │ ├── public-api.ts │ └── test.ts │ ├── tsconfig.lib.json │ ├── tsconfig.lib.prod.json │ ├── tsconfig.spec.json │ └── tslint.json ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | speed-measure-plugin*.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | .angular/ 44 | 45 | # System Files 46 | .DS_Store 47 | Thumbs.db 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Jaime Gonzalez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ngx-translate-cache 2 | [![NPM version][npm-version-image]][npm-url] 3 | [![MIT License][license-image]][license-url] 4 | 5 | Based on and extension of [ngx-translate][ngx-translate-url]. 6 | This is basically a simplified version of [localize-router][localize-router-url]. 7 | If you are already using *localize-router* you don't need this extension. 8 | This extension is aimed only to facilitate language cache with *ngx-translate*. 9 | 10 | | Angular version | Integration branch | Library version | 11 | |:---------------:|:------------------:|:---------------:| 12 | | 8 and below | angular1-8 | ^0.0.0 | 13 | | 9 | angular9 | ^9.0.0 | 14 | | 10 | angular10 | ^10.0.0 | 15 | | 11 | angular11 | ^11.0.0 | 16 | | 12 | angular12 | ^12.0.0 | 17 | | 13 | angular13 | ^13.0.0 | 18 | | 14 | angular14 | ^14.0.0 | 19 | | 15 | angular15 | ^15.0.0 | 20 | | 16 | angular16 | ^16.0.0 | 21 | | 17 | angular17 | ^17.0.0 | 22 | 23 | ## Installation 24 | 25 | To install this library, run: 26 | 27 | ```bash 28 | $ npm install ngx-translate-cache --save 29 | ``` 30 | 31 | ## Usage 32 | 33 | ```typescript 34 | import { TranslateModule, TranslateService } from '@ngx-translate/core'; 35 | import { TranslateCacheModule, TranslateCacheSettings, TranslateCacheService } from 'ngx-translate-cache'; 36 | 37 | @NgModule({ 38 | imports: [ 39 | TranslateModule.forRoot(), 40 | TranslateCacheModule.forRoot({ 41 | cacheService: { 42 | provide: TranslateCacheService, 43 | useFactory: (translateService, translateCacheSettings) => { 44 | return new TranslateCacheService(translateService, translateCacheSettings) 45 | }, 46 | deps: [ TranslateService, TranslateCacheSettings ] 47 | } 48 | }) 49 | ], 50 | ... 51 | }) 52 | export class AppModule {} 53 | ``` 54 | 55 | ### AoT 56 | 57 | If you are using AoT [AoT compilation][aot-compiler-url] 58 | or [Ionic][ionic-url], you must use an exported function instead of an inline function. 59 | 60 | ```ts 61 | import { TranslateModule, TranslateService } from '@ngx-translate/core'; 62 | import { TranslateCacheModule, TranslateCacheSettings, TranslateCacheService } from 'ngx-translate-cache'; 63 | 64 | export function TranslateCacheFactory(translateService, translateCacheSettings) { 65 | return new TranslateCacheService(translateService, translateCacheSettings); 66 | } 67 | 68 | @NgModule({ 69 | imports: [ 70 | TranslateModule.forRoot(), 71 | TranslateCacheModule.forRoot({ 72 | cacheService: { 73 | provide: TranslateCacheService, 74 | useFactory: TranslateCacheFactory, 75 | deps: [ TranslateService, TranslateCacheSettings ] 76 | } 77 | }) 78 | ], 79 | ... 80 | }) 81 | export class AppModule {} 82 | ``` 83 | 84 | ### Initializing 85 | 86 | To initialize *ngx-translate* you usually do 87 | 88 | ```typescript 89 | import { Component } from '@angular/core'; 90 | import { TranslateService } from '@ngx-translate/core'; 91 | 92 | @Component({ 93 | selector: 'app', 94 | template: ` 95 |
{{ 'HELLO' | translate }}
96 | ` 97 | }) 98 | export class AppComponent { 99 | 100 | constructor(translateService: TranslateService) { 101 | translateService.setDefaultLang('en'); 102 | translateService.use('en'); 103 | } 104 | } 105 | ``` 106 | 107 | To initialize *ngx-translate* with *ngx-translate-cache* 108 | 109 | ```typescript 110 | import { Component } from '@angular/core'; 111 | import { TranslateService } from '@ngx-translate/core'; 112 | import { TranslateCacheService } from 'ngx-translate-cache'; 113 | 114 | @Component({ 115 | selector: 'app', 116 | template: ` 117 |
{{ 'HELLO' | translate }}
118 | ` 119 | }) 120 | export class AppComponent { 121 | 122 | constructor(translateService: TranslateService, 123 | translateCacheService: TranslateCacheService) { 124 | translateService.setDefaultLang('en'); 125 | translateCacheService.init(); 126 | } 127 | } 128 | ``` 129 | 130 | `init` method will subscribe to `translateService.onLangChange` event and update the cached language accordingly. 131 | 132 | It also instruct *ngx-translate* to use the previous cached language if defined, or the browser current language if defined. 133 | 134 | The order of precedence is as described below: 135 | 136 | 1. Cached language. 137 | 2. Current language of the browser. 138 | 3. Default language (language used as a fallback for *ngx-translate*). 139 | 140 | You can also define the cache mechanism used (`LocalStorage` or `Cookie`), key used to store cached value and 141 | cookie duration (defined in hours). 142 | 143 | ```typescript 144 | import { TranslateModule, TranslateService } from '@ngx-translate/core'; 145 | import { TranslateCacheModule, TranslateCacheSettings, TranslateCacheService } from 'ngx-translate-cache'; 146 | 147 | @NgModule({ 148 | imports: [ 149 | TranslateModule.forRoot(), 150 | TranslateCacheModule.forRoot({ 151 | cacheService: { 152 | provide: TranslateCacheService, 153 | useFactory: (translateService, translateCacheSettings) => { 154 | return new TranslateCacheService(translateService, translateCacheSettings) 155 | }, 156 | deps: [ TranslateService, TranslateCacheSettings ] 157 | }, 158 | cacheName: 'mylang', // default value is 'lang'. 159 | cacheMechanism: 'Cookie', // default value is 'LocalStorage'. 160 | cookieExpiry: 1, // default value is 720, a month. Set to a negative value and the cookie becomes a session cookie. 161 | cookieAttributes: 'SameSite=Strict; Secure' // no default, optional specification of additional attributes. 162 | }) 163 | ], 164 | ... 165 | }) 166 | export class AppModule {} 167 | ``` 168 | 169 | ## License 170 | 171 | MIT © [Jaime](mailto:jaime.glez.pacheco@gmail.com) 172 | 173 | [npm-url]: https://www.npmjs.com/package/ngx-translate-cache 174 | [npm-version-image]: https://badge.fury.io/js/ngx-translate-cache.svg 175 | 176 | [license-image]: https://img.shields.io/npm/l/express.svg?style=flat 177 | [license-url]: LICENSE 178 | 179 | [ngx-translate-url]: https://github.com/ngx-translate/core 180 | [localize-router-url]: https://github.com/Greentube/localize-router 181 | [aot-compiler-url]: https://angular.io/docs/ts/latest/cookbook/aot-compiler.html 182 | [ionic-url]: http://ionic.io/ 183 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "ngx-translate-cache": { 7 | "projectType": "library", 8 | "root": "projects/ngx-translate-cache", 9 | "sourceRoot": "projects/ngx-translate-cache/src", 10 | "architect": { 11 | "build": { 12 | "builder": "@angular-devkit/build-angular:ng-packagr", 13 | "options": { 14 | "tsConfig": "projects/ngx-translate-cache/tsconfig.lib.json", 15 | "project": "projects/ngx-translate-cache/ng-package.json" 16 | }, 17 | "configurations": { 18 | "production": { 19 | "tsConfig": "projects/ngx-translate-cache/tsconfig.lib.prod.json" 20 | }, 21 | "development": {} 22 | }, 23 | "defaultConfiguration": "production" 24 | }, 25 | "test": { 26 | "builder": "@angular-devkit/build-angular:karma", 27 | "options": { 28 | "main": "projects/ngx-translate-cache/src/test.ts", 29 | "tsConfig": "projects/ngx-translate-cache/tsconfig.spec.json", 30 | "karmaConfig": "projects/ngx-translate-cache/karma.conf.js" 31 | } 32 | }, 33 | "lint": { 34 | "builder": "@angular-devkit/build-angular:tslint", 35 | "options": { 36 | "tsConfig": [ 37 | "projects/ngx-translate-cache/tsconfig.lib.json", 38 | "projects/ngx-translate-cache/tsconfig.spec.json" 39 | ], 40 | "exclude": [ 41 | "**/node_modules/**" 42 | ] 43 | } 44 | } 45 | } 46 | }, 47 | "ngx-translate-cache-example": { 48 | "projectType": "application", 49 | "schematics": {}, 50 | "root": "projects/ngx-translate-cache-example", 51 | "sourceRoot": "projects/ngx-translate-cache-example/src", 52 | "prefix": "app", 53 | "architect": { 54 | "build": { 55 | "builder": "@angular-devkit/build-angular:browser", 56 | "options": { 57 | "outputPath": "dist/ngx-translate-cache-example", 58 | "index": "projects/ngx-translate-cache-example/src/index.html", 59 | "main": "projects/ngx-translate-cache-example/src/main.ts", 60 | "polyfills": ["zone.js"], 61 | "tsConfig": "projects/ngx-translate-cache-example/tsconfig.app.json", 62 | "aot": true, 63 | "assets": [ 64 | "projects/ngx-translate-cache-example/src/favicon.ico", 65 | "projects/ngx-translate-cache-example/src/assets" 66 | ], 67 | "styles": [ 68 | "projects/ngx-translate-cache-example/src/styles.css" 69 | ], 70 | "scripts": [] 71 | }, 72 | "configurations": { 73 | "production": { 74 | "fileReplacements": [ 75 | { 76 | "replace": "projects/ngx-translate-cache-example/src/environments/environment.ts", 77 | "with": "projects/ngx-translate-cache-example/src/environments/environment.prod.ts" 78 | } 79 | ], 80 | "optimization": true, 81 | "outputHashing": "all", 82 | "sourceMap": false, 83 | "extractCss": true, 84 | "namedChunks": false, 85 | "extractLicenses": true, 86 | "vendorChunk": false, 87 | "buildOptimizer": true, 88 | "budgets": [ 89 | { 90 | "type": "initial", 91 | "maximumWarning": "2mb", 92 | "maximumError": "5mb" 93 | }, 94 | { 95 | "type": "anyComponentStyle", 96 | "maximumWarning": "6kb", 97 | "maximumError": "10kb" 98 | } 99 | ] 100 | }, 101 | "development": {} 102 | }, 103 | "defaultConfiguration": "production" 104 | }, 105 | "serve": { 106 | "builder": "@angular-devkit/build-angular:dev-server", 107 | "options": { 108 | }, 109 | "configurations": { 110 | "production": { 111 | "buildTarget": "ngx-translate-cache-example:build:production" 112 | }, 113 | "development": { 114 | "buildTarget": "ngx-translate-cache-example:build:development" 115 | } 116 | }, 117 | "defaultConfiguration": "development" 118 | }, 119 | "extract-i18n": { 120 | "builder": "@angular-devkit/build-angular:extract-i18n", 121 | "options": { 122 | "buildTarget": "ngx-translate-cache-example:build" 123 | } 124 | }, 125 | "test": { 126 | "builder": "@angular-devkit/build-angular:karma", 127 | "options": { 128 | "main": "projects/ngx-translate-cache-example/src/test.ts", 129 | "polyfills": ["zone.js"], 130 | "tsConfig": "projects/ngx-translate-cache-example/tsconfig.spec.json", 131 | "karmaConfig": "projects/ngx-translate-cache-example/karma.conf.js", 132 | "assets": [ 133 | "projects/ngx-translate-cache-example/src/favicon.ico", 134 | "projects/ngx-translate-cache-example/src/assets" 135 | ], 136 | "styles": [ 137 | "projects/ngx-translate-cache-example/src/styles.css" 138 | ], 139 | "scripts": [] 140 | } 141 | }, 142 | "lint": { 143 | "builder": "@angular-devkit/build-angular:tslint", 144 | "options": { 145 | "tsConfig": [ 146 | "projects/ngx-translate-cache-example/tsconfig.app.json", 147 | "projects/ngx-translate-cache-example/tsconfig.spec.json", 148 | "projects/ngx-translate-cache-example/e2e/tsconfig.json" 149 | ], 150 | "exclude": [ 151 | "**/node_modules/**" 152 | ] 153 | } 154 | }, 155 | "e2e": { 156 | "builder": "@angular-devkit/build-angular:protractor", 157 | "options": { 158 | "protractorConfig": "projects/ngx-translate-cache-example/e2e/protractor.conf.js" 159 | }, 160 | "configurations": { 161 | "production": { 162 | "devServerTarget": "ngx-translate-cache-example:serve:production" 163 | }, 164 | "development": { 165 | "devServerTarget": "ngx-translate-cache-example:serve:development" 166 | } 167 | }, 168 | "defaultConfiguration": "development" 169 | } 170 | } 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngx-translate-cache", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e", 11 | "build:lib": "ng build --configuration production ngx-translate-cache", 12 | "pack:lib": "npm run build:lib && cd dist/ngx-translate-cache && npm pack" 13 | }, 14 | "private": true, 15 | "dependencies": { 16 | "@angular/animations": "^17.0.8", 17 | "@angular/common": "^17.0.8", 18 | "@angular/compiler": "^17.0.8", 19 | "@angular/core": "^17.0.8", 20 | "@angular/forms": "^17.0.8", 21 | "@angular/platform-browser": "^17.0.8", 22 | "@angular/platform-browser-dynamic": "^17.0.8", 23 | "@angular/router": "^17.0.8", 24 | "@ngx-translate/core": "^14.0.0", 25 | "@ngx-translate/http-loader": "^7.0.0", 26 | "rxjs": "~6.5.4", 27 | "tslib": "^2.0.0", 28 | "zone.js": "~0.14.2" 29 | }, 30 | "devDependencies": { 31 | "@angular-devkit/build-angular": "^17.0.9", 32 | "@angular/cli": "^17.0.9", 33 | "@angular/compiler-cli": "^17.0.8", 34 | "@angular/language-service": "^17.0.8", 35 | "@types/node": "^12.11.1", 36 | "@types/jasmine": "~3.5.0", 37 | "@types/jasminewd2": "~2.0.3", 38 | "codelyzer": "^5.1.2", 39 | "jasmine-core": "~3.5.0", 40 | "jasmine-spec-reporter": "~5.0.0", 41 | "karma": "~6.4.1", 42 | "karma-chrome-launcher": "~3.1.0", 43 | "karma-coverage-istanbul-reporter": "~3.0.2", 44 | "karma-jasmine": "~4.0.0", 45 | "karma-jasmine-html-reporter": "^1.5.0", 46 | "ng-packagr": "^17.0.3", 47 | "protractor": "~7.0.0", 48 | "ts-node": "~8.3.0", 49 | "tslint": "~6.1.0", 50 | "typescript": "~5.2.2" 51 | } 52 | } -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | browserName: 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('ngx-translate-cache-example app is running!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo(): Promise { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText(): Promise { 9 | return element(by.css('app-root .content span')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es2018", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../../coverage/ngx-translate-cache-example'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgpacheco/ngx-translate-cache/c017da5d2a74307c53db27587065e9b098afda22/projects/ngx-translate-cache-example/src/app/app.component.css -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | {{ 'WELCOME' | translate }} to {{ title }}! 2 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async(() => { 6 | TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | })); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | import { TranslateService } from '@ngx-translate/core'; 4 | import { TranslateCacheService } from 'ngx-translate-cache'; 5 | 6 | @Component({ 7 | selector: 'app-root', 8 | templateUrl: './app.component.html', 9 | styleUrls: ['./app.component.css'] 10 | }) 11 | export class AppComponent { 12 | title = 'ngx-translate-cache-example'; 13 | 14 | constructor(translateService: TranslateService, translateCacheService: TranslateCacheService) { 15 | translateService.setDefaultLang('es'); 16 | translateCacheService.init(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { HttpClientModule, HttpClient } from '@angular/common/http'; 4 | import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core'; 5 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 6 | import { TranslateCacheModule, TranslateCacheSettings, TranslateCacheService } from 'ngx-translate-cache'; 7 | 8 | import { AppComponent } from './app.component'; 9 | 10 | export function HttpLoaderFactory(http: HttpClient) { 11 | return new TranslateHttpLoader(http); 12 | } 13 | 14 | export function TranslateCacheFactory(translateService, translateCacheSettings) { 15 | return new TranslateCacheService(translateService, translateCacheSettings); 16 | } 17 | 18 | @NgModule({ 19 | declarations: [ 20 | AppComponent 21 | ], 22 | imports: [ 23 | BrowserModule, 24 | HttpClientModule, 25 | TranslateModule.forRoot({ 26 | loader: { 27 | provide: TranslateLoader, 28 | useFactory: HttpLoaderFactory, 29 | deps: [HttpClient] 30 | } 31 | }), 32 | TranslateCacheModule.forRoot({ 33 | cacheService: { 34 | provide: TranslateCacheService, 35 | useFactory: TranslateCacheFactory, 36 | deps: [ TranslateService, TranslateCacheSettings ] 37 | } 38 | }) 39 | ], 40 | providers: [], 41 | bootstrap: [AppComponent] 42 | }) 43 | export class AppModule { } 44 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgpacheco/ngx-translate-cache/c017da5d2a74307c53db27587065e9b098afda22/projects/ngx-translate-cache-example/src/assets/.gitkeep -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/assets/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "WELCOME": "Welcome" 3 | } 4 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/assets/i18n/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "WELCOME": "Bienvenido" 3 | } 4 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/assets/i18n/it.json: -------------------------------------------------------------------------------- 1 | { 2 | "WELCOME": "Benvenuto" 3 | } 4 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgpacheco/ngx-translate-cache/c017da5d2a74307c53db27587065e9b098afda22/projects/ngx-translate-cache-example/src/favicon.ico -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NgxTranslateCacheExample 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | // First, initialize the Angular testing environment. 11 | getTestBed().initTestEnvironment( 12 | BrowserDynamicTestingModule, 13 | platformBrowserDynamicTesting() 14 | ); 15 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts" 9 | ], 10 | "include": [ 11 | "src/**/*.d.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache-example/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "app", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "app", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Jaime Gonzalez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache/README.md: -------------------------------------------------------------------------------- 1 | # ngx-translate-cache 2 | [![NPM version][npm-version-image]][npm-url] 3 | [![MIT License][license-image]][license-url] 4 | 5 | Based on and extension of [ngx-translate][ngx-translate-url]. 6 | This is basically a simplified version of [localize-router][localize-router-url]. 7 | If you are already using *localize-router* you don't need this extension. 8 | This extension is aimed only to facilitate language cache with *ngx-translate*. 9 | 10 | | Angular version | Integration branch | Library version | 11 | |:---------------:|:------------------:|:---------------:| 12 | | 8 and below | angular1-8 | ^0.0.0 | 13 | | 9 | angular9 | ^9.0.0 | 14 | | 10 | angular10 | ^10.0.0 | 15 | | 11 | angular11 | ^11.0.0 | 16 | | 12 | angular12 | ^12.0.0 | 17 | | 13 | angular13 | ^13.0.0 | 18 | | 14 | angular14 | ^14.0.0 | 19 | | 15 | angular15 | ^15.0.0 | 20 | | 16 | angular16 | ^16.0.0 | 21 | | 17 | angular17 | ^17.0.0 | 22 | 23 | ## Installation 24 | 25 | To install this library, run: 26 | 27 | ```bash 28 | $ npm install ngx-translate-cache --save 29 | ``` 30 | 31 | ## Usage 32 | 33 | ```typescript 34 | import { TranslateModule, TranslateService } from '@ngx-translate/core'; 35 | import { TranslateCacheModule, TranslateCacheSettings, TranslateCacheService } from 'ngx-translate-cache'; 36 | 37 | @NgModule({ 38 | imports: [ 39 | TranslateModule.forRoot(), 40 | TranslateCacheModule.forRoot({ 41 | cacheService: { 42 | provide: TranslateCacheService, 43 | useFactory: (translateService, translateCacheSettings) => { 44 | return new TranslateCacheService(translateService, translateCacheSettings) 45 | }, 46 | deps: [ TranslateService, TranslateCacheSettings ] 47 | } 48 | }) 49 | ], 50 | ... 51 | }) 52 | export class AppModule {} 53 | ``` 54 | 55 | ### AoT 56 | 57 | If you are using AoT [AoT compilation][aot-compiler-url] 58 | or [Ionic][ionic-url], you must use an exported function instead of an inline function. 59 | 60 | ```ts 61 | import { TranslateModule, TranslateService } from '@ngx-translate/core'; 62 | import { TranslateCacheModule, TranslateCacheSettings, TranslateCacheService } from 'ngx-translate-cache'; 63 | 64 | export function TranslateCacheFactory(translateService, translateCacheSettings) { 65 | return new TranslateCacheService(translateService, translateCacheSettings); 66 | } 67 | 68 | @NgModule({ 69 | imports: [ 70 | TranslateModule.forRoot(), 71 | TranslateCacheModule.forRoot({ 72 | cacheService: { 73 | provide: TranslateCacheService, 74 | useFactory: TranslateCacheFactory, 75 | deps: [ TranslateService, TranslateCacheSettings ] 76 | } 77 | }) 78 | ], 79 | ... 80 | }) 81 | export class AppModule {} 82 | ``` 83 | 84 | ### Initializing 85 | 86 | To initialize *ngx-translate* you usually do 87 | 88 | ```typescript 89 | import { Component } from '@angular/core'; 90 | import { TranslateService } from '@ngx-translate/core'; 91 | 92 | @Component({ 93 | selector: 'app', 94 | template: ` 95 |
{{ 'HELLO' | translate }}
96 | ` 97 | }) 98 | export class AppComponent { 99 | 100 | constructor(translateService: TranslateService) { 101 | translateService.setDefaultLang('en'); 102 | translateService.use('en'); 103 | } 104 | } 105 | ``` 106 | 107 | To initialize *ngx-translate* with *ngx-translate-cache* 108 | 109 | ```typescript 110 | import { Component } from '@angular/core'; 111 | import { TranslateService } from '@ngx-translate/core'; 112 | import { TranslateCacheService } from 'ngx-translate-cache'; 113 | 114 | @Component({ 115 | selector: 'app', 116 | template: ` 117 |
{{ 'HELLO' | translate }}
118 | ` 119 | }) 120 | export class AppComponent { 121 | 122 | constructor(translateService: TranslateService, 123 | translateCacheService: TranslateCacheService) { 124 | translateService.setDefaultLang('en'); 125 | translateCacheService.init(); 126 | } 127 | } 128 | ``` 129 | 130 | `init` method will subscribe to `translateService.onLangChange` event and update the cached language accordingly. 131 | 132 | It also instruct *ngx-translate* to use the previous cached language if defined, or the browser current language if defined. 133 | 134 | The order of precedence is as described below: 135 | 136 | 1. Cached language. 137 | 2. Current language of the browser. 138 | 3. Default language (language used as a fallback for *ngx-translate*). 139 | 140 | You can also define the cache mechanism used (`LocalStorage` or `Cookie`), key used to store cached value and 141 | cookie duration (defined in hours). 142 | 143 | ```typescript 144 | import { TranslateModule, TranslateService } from '@ngx-translate/core'; 145 | import { TranslateCacheModule, TranslateCacheSettings, TranslateCacheService } from 'ngx-translate-cache'; 146 | 147 | @NgModule({ 148 | imports: [ 149 | TranslateModule.forRoot(), 150 | TranslateCacheModule.forRoot({ 151 | cacheService: { 152 | provide: TranslateCacheService, 153 | useFactory: (translateService, translateCacheSettings) => { 154 | return new TranslateCacheService(translateService, translateCacheSettings) 155 | }, 156 | deps: [ TranslateService, TranslateCacheSettings ] 157 | }, 158 | cacheName: 'mylang', // default value is 'lang'. 159 | cacheMechanism: 'Cookie', // default value is 'LocalStorage'. 160 | cookieExpiry: 1, // default value is 720, a month. Set to a negative value and the cookie becomes a session cookie. 161 | cookieAttributes: 'SameSite=Strict; Secure' // no default, optional specification of additional attributes. 162 | }) 163 | ], 164 | ... 165 | }) 166 | export class AppModule {} 167 | ``` 168 | 169 | ## License 170 | 171 | MIT © [Jaime](mailto:jaime.glez.pacheco@gmail.com) 172 | 173 | [npm-url]: https://www.npmjs.com/package/ngx-translate-cache 174 | [npm-version-image]: https://badge.fury.io/js/ngx-translate-cache.svg 175 | 176 | [license-image]: https://img.shields.io/npm/l/express.svg?style=flat 177 | [license-url]: LICENSE 178 | 179 | [ngx-translate-url]: https://github.com/ngx-translate/core 180 | [localize-router-url]: https://github.com/Greentube/localize-router 181 | [aot-compiler-url]: https://angular.io/docs/ts/latest/cookbook/aot-compiler.html 182 | [ionic-url]: http://ionic.io/ 183 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../../coverage/ngx-translate-cache'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/ngx-translate-cache", 4 | "lib": { 5 | "entryFile": "src/public-api.ts" 6 | } 7 | } -------------------------------------------------------------------------------- /projects/ngx-translate-cache/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngx-translate-cache", 3 | "version": "17.0.0", 4 | "description": "ngx-translate extension to facilitate language cache.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/jgpacheco/ngx-translate-cache" 8 | }, 9 | "author": { 10 | "name": "Jaime", 11 | "email": "jaime.glez.pacheco@gmail.com" 12 | }, 13 | "keywords": [ 14 | "angular", 15 | "angular2", 16 | "ng2-translate", 17 | "ngx-translate", 18 | "translate", 19 | "translation", 20 | "i18n" 21 | ], 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/jgpacheco/ngx-translate-cache/issues" 25 | }, 26 | "peerDependencies": { 27 | "@angular/common": "^17.0.0", 28 | "@angular/core": "^17.0.0", 29 | "@ngx-translate/core": ">=14.0.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache/src/lib/ngx-translate-cache.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule, ModuleWithProviders } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { TranslateCacheConfig, CACHE_NAME, CACHE_MECHANISM, COOKIE_EXPIRY, 4 | COOKIE_ATTRIBUTES, TranslateCacheSettings } from './ngx-translate-cache.service'; 5 | 6 | @NgModule({ 7 | imports: [ 8 | CommonModule 9 | ], 10 | declarations: [], 11 | exports: [] 12 | }) 13 | export class TranslateCacheModule { 14 | static forRoot(config: TranslateCacheConfig): ModuleWithProviders { 15 | return { 16 | ngModule: TranslateCacheModule, 17 | providers: [ 18 | { provide: CACHE_NAME, useValue: config.cacheName }, 19 | { provide: CACHE_MECHANISM, useValue: config.cacheMechanism }, 20 | { provide: COOKIE_EXPIRY, useValue: config.cookieExpiry }, 21 | { provide: COOKIE_ATTRIBUTES, useValue: config.cookieAttributes }, 22 | TranslateCacheSettings, 23 | config.cacheService, 24 | ] 25 | }; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache/src/lib/ngx-translate-cache.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable, InjectionToken, Provider } from '@angular/core'; 2 | import { TranslateService, TranslationChangeEvent } from '@ngx-translate/core'; 3 | 4 | export type CacheMechanismType = 'LocalStorage' | 'Cookie'; 5 | export namespace CacheMechanism { 6 | export const LocalStorage: CacheMechanismType = 'LocalStorage'; 7 | export const Cookie: CacheMechanismType = 'Cookie'; 8 | } 9 | 10 | export const CACHE_NAME = new InjectionToken('CACHE_NAME'); 11 | export const CACHE_MECHANISM = new InjectionToken('CACHE_MECHANISM'); 12 | export const COOKIE_EXPIRY = new InjectionToken('COOKIE_EXPIRY'); 13 | export const COOKIE_ATTRIBUTES = new InjectionToken('COOKIE_ATTRIBUTES'); 14 | 15 | export interface TranslateCacheConfig { 16 | cacheService: Provider; 17 | cacheName?: string; 18 | cacheMechanism?: CacheMechanismType; 19 | cookieExpiry?: number; 20 | cookieAttributes?: string; 21 | } 22 | 23 | const DEFAULT_CACHE_NAME = 'lang'; 24 | const DEFAULT_CACHE_MECHANISM = CacheMechanism.LocalStorage; 25 | const DEFAULT_COOKIE_EXPIRY = 720; 26 | 27 | @Injectable() 28 | export class TranslateCacheSettings { 29 | constructor(@Inject(CACHE_NAME) public cacheName: string = DEFAULT_CACHE_NAME, 30 | @Inject(CACHE_MECHANISM) public cacheMechanism: string = DEFAULT_CACHE_MECHANISM, 31 | @Inject(COOKIE_EXPIRY) public cookieExpiry: number = DEFAULT_COOKIE_EXPIRY, 32 | @Inject(COOKIE_ATTRIBUTES) public cookieAttributes: string) {} 33 | } 34 | 35 | /* Not injectable */ 36 | export class TranslateCacheService { 37 | constructor(private translateService: TranslateService, 38 | private translateCacheSettings: TranslateCacheSettings) {} 39 | 40 | public init(): void { 41 | this.translateService.onLangChange 42 | .subscribe((event: TranslationChangeEvent) => { 43 | if (this.translateCacheSettings.cacheMechanism === CacheMechanism.LocalStorage) { 44 | return this.cacheWithLocalStorage(event.lang); 45 | } 46 | 47 | if (this.translateCacheSettings.cacheMechanism === CacheMechanism.Cookie) { 48 | return this.cacheWithCookies(event.lang); 49 | } 50 | }); 51 | 52 | const currentLang = this.getCachedLanguage() || this.translateService.getBrowserLang(); 53 | 54 | if (currentLang) { this.translateService.use(currentLang); } 55 | } 56 | 57 | public getCachedLanguage(): string { 58 | if (this.translateCacheSettings.cacheMechanism === CacheMechanism.LocalStorage) { 59 | return this.cacheWithLocalStorage(); 60 | } 61 | 62 | if (this.translateCacheSettings.cacheMechanism === CacheMechanism.Cookie) { 63 | return this.cacheWithCookies(); 64 | } 65 | } 66 | 67 | private cacheWithLocalStorage(value?: string): string { 68 | if (typeof window === 'undefined' || typeof window.localStorage === 'undefined') { return; } 69 | 70 | try { 71 | if (value) { window.localStorage.setItem(this.translateCacheSettings.cacheName, value); return; } 72 | 73 | return window.localStorage.getItem(this.translateCacheSettings.cacheName); 74 | } catch (e) { return; } 75 | } 76 | 77 | private cacheWithCookies(value?: string): string { 78 | if (typeof document === 'undefined' || typeof document.cookie === 'undefined') { return; } 79 | 80 | try { 81 | const name = encodeURIComponent(this.translateCacheSettings.cacheName); 82 | 83 | if (value) { 84 | let cookieString = `${name}=${encodeURIComponent(value)}`; 85 | 86 | if (this.translateCacheSettings.cookieExpiry >= 0) { 87 | const date: Date = new Date(); 88 | 89 | date.setTime(date.getTime() + this.translateCacheSettings.cookieExpiry * 3600000); 90 | cookieString += `;expires=${date.toUTCString()}`; 91 | } 92 | 93 | if (this.translateCacheSettings.cookieAttributes) { 94 | cookieString += ';' + this.translateCacheSettings.cookieAttributes; 95 | } 96 | 97 | document.cookie = cookieString; 98 | 99 | return; 100 | } 101 | const regexp = new RegExp('(?:^' + name + '|;\\s*' + name + ')=(.*?)(?:;|$)', 'g'); 102 | const result = regexp.exec(document.cookie); 103 | 104 | return decodeURIComponent(result[1]); 105 | } catch (e) { return; } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache/src/public-api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API Surface of ngx-translate-cache 3 | */ 4 | 5 | export * from './lib/ngx-translate-cache.service'; 6 | export * from './lib/ngx-translate-cache.module'; 7 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone'; 4 | import 'zone.js/dist/zone-testing'; 5 | import { getTestBed } from '@angular/core/testing'; 6 | import { 7 | BrowserDynamicTestingModule, 8 | platformBrowserDynamicTesting 9 | } from '@angular/platform-browser-dynamic/testing'; 10 | 11 | // First, initialize the Angular testing environment. 12 | getTestBed().initTestEnvironment( 13 | BrowserDynamicTestingModule, 14 | platformBrowserDynamicTesting() 15 | ); 16 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/lib", 5 | "declaration": true, 6 | "inlineSources": true, 7 | "types": [], 8 | "lib": [ 9 | "dom", 10 | "es2018" 11 | ] 12 | }, 13 | "angularCompilerOptions": { 14 | "skipTemplateCodegen": true, 15 | "strictMetadataEmit": true, 16 | "enableResourceInlining": true 17 | }, 18 | "exclude": [ 19 | "src/test.ts", 20 | "**/*.spec.ts" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "angularCompilerOptions": { 4 | "compilationMode": "partial" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts" 12 | ], 13 | "include": [ 14 | "**/*.spec.ts", 15 | "**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /projects/ngx-translate-cache/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "lib", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "lib", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "es2020", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "ES2022", 14 | "lib": [ 15 | "es2018", 16 | "dom" 17 | ], 18 | "paths": { 19 | "ngx-translate-cache": [ 20 | "dist/ngx-translate-cache/ngx-translate-cache", 21 | "dist/ngx-translate-cache" 22 | ] 23 | }, 24 | "useDefineForClassFields": false 25 | }, 26 | "angularCompilerOptions": { 27 | "fullTemplateTypeCheck": true, 28 | "strictInjectionParameters": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rulesDirectory": [ 4 | "codelyzer" 5 | ], 6 | "rules": { 7 | "align": { 8 | "options": [ 9 | "parameters", 10 | "statements" 11 | ] 12 | }, 13 | "array-type": false, 14 | "arrow-return-shorthand": true, 15 | "curly": true, 16 | "deprecation": { 17 | "severity": "warning" 18 | }, 19 | "eofline": true, 20 | "import-blacklist": [ 21 | true, 22 | "rxjs/Rx" 23 | ], 24 | "import-spacing": true, 25 | "indent": { 26 | "options": [ 27 | "spaces" 28 | ] 29 | }, 30 | "max-classes-per-file": false, 31 | "max-line-length": [ 32 | true, 33 | 140 34 | ], 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-console": [ 47 | true, 48 | "debug", 49 | "info", 50 | "time", 51 | "timeEnd", 52 | "trace" 53 | ], 54 | "no-empty": false, 55 | "no-inferrable-types": [ 56 | true, 57 | "ignore-params" 58 | ], 59 | "no-non-null-assertion": true, 60 | "no-redundant-jsdoc": true, 61 | "no-switch-case-fall-through": true, 62 | "no-var-requires": false, 63 | "object-literal-key-quotes": [ 64 | true, 65 | "as-needed" 66 | ], 67 | "quotemark": [ 68 | true, 69 | "single" 70 | ], 71 | "semicolon": { 72 | "options": [ 73 | "always" 74 | ] 75 | }, 76 | "space-before-function-paren": { 77 | "options": { 78 | "anonymous": "never", 79 | "asyncArrow": "always", 80 | "constructor": "never", 81 | "method": "never", 82 | "named": "never" 83 | } 84 | }, 85 | "typedef-whitespace": { 86 | "options": [ 87 | { 88 | "call-signature": "nospace", 89 | "index-signature": "nospace", 90 | "parameter": "nospace", 91 | "property-declaration": "nospace", 92 | "variable-declaration": "nospace" 93 | }, 94 | { 95 | "call-signature": "onespace", 96 | "index-signature": "onespace", 97 | "parameter": "onespace", 98 | "property-declaration": "onespace", 99 | "variable-declaration": "onespace" 100 | } 101 | ] 102 | }, 103 | "variable-name": { 104 | "options": [ 105 | "ban-keywords", 106 | "check-format", 107 | "allow-pascal-case" 108 | ] 109 | }, 110 | "whitespace": { 111 | "options": [ 112 | "check-branch", 113 | "check-decl", 114 | "check-operator", 115 | "check-separator", 116 | "check-type", 117 | "check-typecast" 118 | ] 119 | }, 120 | "component-class-suffix": true, 121 | "contextual-lifecycle": true, 122 | "directive-class-suffix": true, 123 | "no-conflicting-lifecycle": true, 124 | "no-host-metadata-property": true, 125 | "no-input-rename": true, 126 | "no-inputs-metadata-property": true, 127 | "no-output-native": true, 128 | "no-output-on-prefix": true, 129 | "no-output-rename": true, 130 | "no-outputs-metadata-property": true, 131 | "template-banana-in-box": true, 132 | "template-no-negated-async": true, 133 | "use-lifecycle-interface": true, 134 | "use-pipe-transform-interface": true 135 | } 136 | } 137 | --------------------------------------------------------------------------------