@kopynator/angular 1.0.12 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -92,23 +92,27 @@ O con header/selector:
92
92
  <button (click)="kopyService.setLocale('es')">Español</button>
93
93
  ```
94
94
 
95
- ### Evitar parpadeo (FOUT) con SSR / hidratación
96
-
97
- Si usas **Angular con SSR** o hidratación y ves un breve parpadeo de claves antes de las traducciones, añade en tu `index.html` la clase y el estilo para ocultar la app hasta que Kopynator esté listo:
98
-
99
- ```html
100
- <html lang="en" class="kopy-hydrating">
101
- <head>
102
- <style>html.kopy-hydrating{visibility:hidden}</style>
103
- ...
104
- </head>
95
+ ### SSR: idioma guardado sin parpadeo
96
+
97
+ Al cambiar de idioma se guarda en `localStorage` y en la cookie `kopy_locale`. Para que el **servidor** pinte ya con ese idioma (y no se vea español idioma guardado), proporciona `KOPY_INITIAL_LOCALE` desde la request en `app.config.server.ts`:
98
+
99
+ ```ts
100
+ import { inject, REQUEST } from '@angular/core';
101
+ import { KOPY_INITIAL_LOCALE, getKopyLocaleFromCookieHeader } from '@kopynator/angular';
102
+
103
+ // en providers del server:
104
+ {
105
+ provide: KOPY_INITIAL_LOCALE,
106
+ useFactory: () => {
107
+ const req = inject(REQUEST, { optional: true }) as { headers?: { cookie?: string } } | null;
108
+ return req?.headers?.cookie ? getKopyLocaleFromCookieHeader(req.headers.cookie) : null;
109
+ }
110
+ }
105
111
  ```
106
112
 
107
- La librería quita la clase `kopy-hydrating` cuando las traducciones están cargadas. Sin esto, el contenido puede mostrarse un instante con claves antes del bootstrap.
108
-
109
113
  ### (Opcional) Componente \<kopy-ready\>
110
114
 
111
- Solo si necesitas ocultar un bloque concreto hasta que estén listas las traducciones, puedes usar `<kopy-ready>`. En la mayoría de proyectos **no es necesario**; el `APP_INITIALIZER` y la clase `kopy-hydrating` evitan el parpadeo.
115
+ Solo si necesitas ocultar un bloque concreto hasta que estén listas las traducciones, puedes usar `<kopy-ready>`. En la mayoría de proyectos **no es necesario**; el `APP_INITIALIZER` carga las traducciones antes del bootstrap (igual que ngx-translate), con o sin SSR.
112
116
 
113
117
  ```html
114
118
  <kopy-ready>
@@ -1,58 +1,62 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, signal, PLATFORM_ID, Inject, Injectable, Pipe, effect, Input, Directive, inject, Component, input, provideAppInitializer } from '@angular/core';
3
- import * as i1 from '@angular/common';
4
- import { isPlatformBrowser, CommonModule } from '@angular/common';
2
+ import { InjectionToken, signal, Inject, Optional, Injectable, Pipe, effect, Input, Directive, inject, Component, input, provideAppInitializer } from '@angular/core';
5
3
  import { Kopynator } from '@kopynator/core';
4
+ import * as i1 from '@angular/common';
5
+ import { CommonModule } from '@angular/common';
6
6
 
7
7
  const KOPY_CONFIG = new InjectionToken('KOPY_CONFIG');
8
- const KOPY_HYDRATING_CLASS = 'kopy-hydrating';
8
+ /** In SSR: provide this from the request cookie so the first paint uses the user's saved locale (no flicker). */
9
+ const KOPY_INITIAL_LOCALE = new InjectionToken('KOPY_INITIAL_LOCALE');
10
+ const COOKIE_NAME = 'kopy_locale';
11
+ const COOKIE_MAX_AGE = 365 * 24 * 60 * 60; // 1 year
12
+ /** Parse Cookie header (e.g. from req.headers.cookie) and return the value of kopy_locale, or null. */
13
+ function getKopyLocaleFromCookieHeader(cookieHeader) {
14
+ if (!cookieHeader || typeof cookieHeader !== 'string')
15
+ return null;
16
+ const match = cookieHeader.match(new RegExp(`(?:^|;\\s*)${COOKIE_NAME}=([^;]*)`));
17
+ return match ? decodeURIComponent(match[1].trim()) : null;
18
+ }
19
+ function readCookieFromDocument() {
20
+ if (typeof document === 'undefined')
21
+ return null;
22
+ return getKopyLocaleFromCookieHeader(document.cookie);
23
+ }
24
+ function setCookieInDocument(locale) {
25
+ if (typeof document === 'undefined')
26
+ return;
27
+ document.cookie = `${COOKIE_NAME}=${encodeURIComponent(locale)};path=/;max-age=${COOKIE_MAX_AGE};SameSite=Lax`;
28
+ }
9
29
  class KopyService {
10
30
  config;
11
31
  zone;
12
32
  kopy;
13
- isBrowser;
14
- // Signals for reactivity
15
33
  isReady = signal(false, ...(ngDevMode ? [{ debugName: "isReady" }] : []));
16
34
  availableLanguages = signal([], ...(ngDevMode ? [{ debugName: "availableLanguages" }] : []));
17
35
  currentLocale = signal('en', ...(ngDevMode ? [{ debugName: "currentLocale" }] : []));
18
- constructor(config, zone, platformId) {
36
+ constructor(config, zone, serverLocale) {
19
37
  this.config = config;
20
38
  this.zone = zone;
21
- this.isBrowser = isPlatformBrowser(platformId);
22
- const savedLocale = typeof localStorage !== 'undefined' ? localStorage.getItem('kopy_locale') : null;
23
- const initialLocale = savedLocale || config.defaultLocale || 'en';
24
- // Initialize core with the restored or default locale
39
+ const initialLocale = serverLocale ??
40
+ readCookieFromDocument() ??
41
+ (typeof localStorage !== 'undefined' ? localStorage.getItem(COOKIE_NAME) : null) ??
42
+ config.defaultLocale ??
43
+ 'en';
25
44
  this.kopy = new Kopynator({ ...config, defaultLocale: initialLocale });
26
45
  this.currentLocale.set(initialLocale);
27
- // Hide app until translations are ready (avoids FOUT with SSR/hydration)
28
- if (this.isBrowser && typeof document !== 'undefined') {
29
- this.injectHydratingStyles();
30
- document.documentElement.classList.add(KOPY_HYDRATING_CLASS);
31
- }
32
- }
33
- injectHydratingStyles() {
34
- if (document.getElementById('kopy-hydrating-styles'))
35
- return;
36
- const style = document.createElement('style');
37
- style.id = 'kopy-hydrating-styles';
38
- style.textContent = `html.${KOPY_HYDRATING_CLASS}{visibility:hidden}`;
39
- document.head.appendChild(style);
40
46
  }
41
47
  async init() {
42
48
  await this.kopy.init();
43
49
  this.zone.run(() => {
44
50
  this.availableLanguages.set(this.kopy.getLanguages());
45
51
  this.isReady.set(true);
46
- if (this.isBrowser && typeof document !== 'undefined') {
47
- document.documentElement.classList.remove(KOPY_HYDRATING_CLASS);
48
- }
49
52
  });
50
53
  }
51
54
  async setLocale(locale) {
52
55
  await this.kopy.setLocale(locale);
53
56
  if (typeof localStorage !== 'undefined') {
54
- localStorage.setItem('kopy_locale', locale);
57
+ localStorage.setItem(COOKIE_NAME, locale);
55
58
  }
59
+ setCookieInDocument(locale);
56
60
  this.zone.run(() => {
57
61
  this.currentLocale.set(locale);
58
62
  });
@@ -63,7 +67,7 @@ class KopyService {
63
67
  getKopynator() {
64
68
  return this.kopy;
65
69
  }
66
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: KopyService, deps: [{ token: KOPY_CONFIG }, { token: i0.NgZone }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable });
70
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: KopyService, deps: [{ token: KOPY_CONFIG }, { token: i0.NgZone }, { token: KOPY_INITIAL_LOCALE, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
67
71
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: KopyService, providedIn: 'root' });
68
72
  }
69
73
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: KopyService, decorators: [{
@@ -75,8 +79,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
75
79
  type: Inject,
76
80
  args: [KOPY_CONFIG]
77
81
  }] }, { type: i0.NgZone }, { type: undefined, decorators: [{
82
+ type: Optional
83
+ }, {
78
84
  type: Inject,
79
- args: [PLATFORM_ID]
85
+ args: [KOPY_INITIAL_LOCALE]
80
86
  }] }] });
81
87
 
82
88
  class KopyPipe {
@@ -302,5 +308,5 @@ function provideKopynator(config) {
302
308
  * Generated bundle index. Do not edit.
303
309
  */
304
310
 
305
- export { KOPY_CONFIG, KopyDirective, KopyPipe, KopyReadyComponent, KopySelectorComponent, KopyService, provideKopynator };
311
+ export { KOPY_CONFIG, KOPY_INITIAL_LOCALE, KopyDirective, KopyPipe, KopyReadyComponent, KopySelectorComponent, KopyService, getKopyLocaleFromCookieHeader, provideKopynator };
306
312
  //# sourceMappingURL=kopynator-angular.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"kopynator-angular.mjs","sources":["../../../../packages/angular/src/lib/kopy.service.ts","../../../../packages/angular/src/lib/kopy.pipe.ts","../../../../packages/angular/src/lib/kopy.directive.ts","../../../../packages/angular/src/lib/kopy.selector.component.ts","../../../../packages/angular/src/lib/kopy-ready.component.ts","../../../../packages/angular/src/public-api.ts","../../../../packages/angular/src/kopynator-angular.ts"],"sourcesContent":["import { Injectable, Inject, InjectionToken, signal, NgZone, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { Kopynator, KopyConfig } from '@kopynator/core';\n\nexport const KOPY_CONFIG = new InjectionToken<KopyConfig>('KOPY_CONFIG');\n\nconst KOPY_HYDRATING_CLASS = 'kopy-hydrating';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class KopyService {\n private kopy: Kopynator;\n private readonly isBrowser: boolean;\n\n // Signals for reactivity\n public isReady = signal(false);\n public availableLanguages = signal<string[]>([]);\n public currentLocale = signal<string>('en');\n\n constructor(\n @Inject(KOPY_CONFIG) private config: KopyConfig,\n private zone: NgZone,\n @Inject(PLATFORM_ID) platformId: object\n ) {\n this.isBrowser = isPlatformBrowser(platformId);\n const savedLocale = typeof localStorage !== 'undefined' ? localStorage.getItem('kopy_locale') : null;\n const initialLocale = savedLocale || config.defaultLocale || 'en';\n\n // Initialize core with the restored or default locale\n this.kopy = new Kopynator({ ...config, defaultLocale: initialLocale });\n this.currentLocale.set(initialLocale);\n\n // Hide app until translations are ready (avoids FOUT with SSR/hydration)\n if (this.isBrowser && typeof document !== 'undefined') {\n this.injectHydratingStyles();\n document.documentElement.classList.add(KOPY_HYDRATING_CLASS);\n }\n }\n\n private injectHydratingStyles(): void {\n if (document.getElementById('kopy-hydrating-styles')) return;\n const style = document.createElement('style');\n style.id = 'kopy-hydrating-styles';\n style.textContent = `html.${KOPY_HYDRATING_CLASS}{visibility:hidden}`;\n document.head.appendChild(style);\n }\n\n public async init(): Promise<void> {\n await this.kopy.init();\n\n this.zone.run(() => {\n this.availableLanguages.set(this.kopy.getLanguages());\n this.isReady.set(true);\n if (this.isBrowser && typeof document !== 'undefined') {\n document.documentElement.classList.remove(KOPY_HYDRATING_CLASS);\n }\n });\n }\n\n async setLocale(locale: string) {\n await this.kopy.setLocale(locale);\n \n if (typeof localStorage !== 'undefined') {\n localStorage.setItem('kopy_locale', locale);\n }\n\n this.zone.run(() => {\n this.currentLocale.set(locale);\n });\n }\n\n translate(key: string, params: Record<string, any> = {}): string {\n return this.kopy.translate(key, params);\n }\n\n getKopynator(): Kopynator {\n return this.kopy;\n }\n}\n","import { Pipe, PipeTransform } from '@angular/core';\nimport { KopyService } from './kopy.service';\n\n@Pipe({\n name: 'kopy',\n pure: false, // Must be false to react to signal changes inside transform\n standalone: true\n})\nexport class KopyPipe implements PipeTransform {\n constructor(\n private kopyService: KopyService\n ) {}\n\n transform(key: string, params: Record<string, any> = {}): string {\n const ready = this.kopyService.isReady();\n this.kopyService.currentLocale(); // reactive dependency\n if (!ready) return '';\n\n return this.kopyService.translate(key, params);\n }\n}\n","import { Directive, ElementRef, Input, OnChanges, SimpleChanges, effect } from '@angular/core';\nimport { KopyService } from './kopy.service';\n\n@Directive({\n selector: '[kopy]',\n standalone: true\n})\nexport class KopyDirective implements OnChanges {\n @Input('kopy') key!: string;\n @Input() kopyParams: Record<string, any> = {};\n\n constructor(\n private el: ElementRef,\n private kopyService: KopyService\n ) {\n // React to signal changes in KopyService\n effect(() => {\n this.kopyService.currentLocale();\n this.kopyService.isReady();\n this.render();\n });\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n this.render();\n }\n\n private render() {\n if (!this.key) return;\n if (!this.kopyService.isReady()) {\n this.el.nativeElement.textContent = '';\n return;\n }\n this.el.nativeElement.textContent = this.kopyService.translate(this.key, this.kopyParams);\n }\n}\n","import { Component, inject, signal } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { KopyService } from './kopy.service';\n\n@Component({\n selector: 'kopy-selector',\n standalone: true,\n imports: [CommonModule],\n template: `\n <div class=\"kopy-selector-container\" [class.open]=\"isOpen()\">\n <button class=\"kopy-selected-btn\" (click)=\"toggleDropdown()\">\n <span class=\"flag\">{{ getFlag(currentLocale()) }}</span>\n <span class=\"label uppercase\">{{ currentLocale() }}</span>\n <svg class=\"chevron\" [class.rotate]=\"isOpen()\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n\n <div class=\"kopy-dropdown\" *ngIf=\"isOpen()\">\n <button \n *ngFor=\"let lang of languages()\" \n class=\"kopy-dropdown-item\"\n [class.active]=\"lang === currentLocale()\"\n (click)=\"selectLanguage(lang)\"\n >\n <span class=\"flag\">{{ getFlag(lang) }}</span>\n <span class=\"label\">{{ getNativeName(lang) }}</span>\n </button>\n </div>\n </div>\n `,\n styles: [`\n .kopy-selector-container {\n position: relative;\n display: inline-block;\n font-family: inherit;\n }\n .kopy-selected-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 99px;\n color: white;\n cursor: pointer;\n transition: all 0.2s;\n font-size: 11px;\n font-weight: 700;\n min-width: 70px;\n justify-content: center;\n }\n .kopy-selected-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n }\n .chevron {\n width: 10px;\n height: 10px;\n opacity: 0.5;\n transition: transform 0.2s;\n }\n .chevron.rotate {\n transform: rotate(180deg);\n }\n .kopy-dropdown {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 8px;\n background: #1e293b;\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 12px;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);\n overflow: hidden;\n min-width: 140px;\n z-index: 100;\n animation: slideIn 0.2s ease-out;\n }\n .kopy-dropdown-item {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 16px;\n background: transparent;\n border: none;\n color: #94a3b8;\n cursor: pointer;\n text-align: left;\n transition: all 0.2s;\n font-size: 14px;\n }\n .kopy-dropdown-item:hover {\n background: rgba(255, 255, 255, 0.05);\n color: white;\n }\n .kopy-dropdown-item.active {\n color: #38bdf8;\n background: rgba(56, 189, 248, 0.05);\n }\n .label {\n flex: 1;\n }\n .flag {\n font-size: 16px;\n }\n @keyframes slideIn {\n from { opacity: 0; transform: translateY(-10px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `]\n})\nexport class KopySelectorComponent {\n private kopyService = inject(KopyService);\n \n public isOpen = signal(false);\n public languages = this.kopyService.availableLanguages;\n public currentLocale = this.kopyService.currentLocale;\n\n private flagMap: Record<string, string> = {\n 'en': '🇺🇸',\n 'es': '🇪🇸',\n 'fr': '🇫🇷',\n 'de': '🇩🇪',\n 'it': '🇮🇹',\n 'pt': '🇵🇹',\n 'ja': '🇯🇵',\n 'zh': '🇨🇳',\n 'ru': '🇷🇺'\n };\n\n private nameMap: Record<string, string> = {\n 'en': 'English',\n 'es': 'Español',\n 'fr': 'Français',\n 'de': 'Deutsch',\n 'it': 'Italiano',\n 'pt': 'Português',\n 'ja': '日本語',\n 'zh': '中文',\n 'ru': 'Русский',\n 'en-us': 'English (US)'\n };\n\n toggleDropdown() {\n this.isOpen.set(!this.isOpen());\n }\n\n selectLanguage(lang: string) {\n this.kopyService.setLocale(lang);\n this.isOpen.set(false);\n }\n\n getFlag(lang: string): string {\n const code = lang.split('-')[0].toLowerCase();\n return this.flagMap[code] || '🌐';\n }\n\n getNativeName(lang: string): string {\n return this.nameMap[lang.toLowerCase()] || lang.toUpperCase();\n }\n}\n","import { Component, inject, input } from '@angular/core';\nimport { KopyService } from './kopy.service';\n\n/**\n * Envuelve el contenido y solo lo muestra cuando las traducciones están cargadas (isReady).\n * Evita el parpadeo de claves (FOUT) sin tener que usar señales ni afterNextRender en la app.\n *\n * Uso en app.html:\n * <kopy-ready>\n * <router-outlet></router-outlet>\n * </kopy-ready>\n *\n * Opcional: showLoader=false para no mostrar spinner (solo espacio vacío hasta que cargue).\n */\n@Component({\n selector: 'kopy-ready',\n standalone: true,\n template: `\n @if (kopyService.isReady()) {\n <ng-content></ng-content>\n } @else if (showLoader()) {\n <div class=\"kopy-ready-loading\" aria-busy=\"true\" aria-label=\"Cargando traducciones\">\n <span class=\"kopy-ready-spinner\" aria-hidden=\"true\"></span>\n </div>\n }\n `,\n styles: [`\n .kopy-ready-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 60vh;\n }\n .kopy-ready-spinner {\n display: inline-block;\n width: 2rem;\n height: 2rem;\n border: 2px solid rgba(6, 182, 212, 0.3);\n border-top-color: rgb(6, 182, 212);\n border-radius: 50%;\n animation: kopy-spin 0.7s linear infinite;\n }\n @keyframes kopy-spin {\n to { transform: rotate(360deg); }\n }\n `]\n})\nexport class KopyReadyComponent {\n readonly kopyService = inject(KopyService);\n /** Si true (por defecto), muestra un spinner mientras cargan las traducciones. */\n readonly showLoader = input<boolean>(true);\n}\n","import { Provider, provideAppInitializer, inject, EnvironmentProviders } from '@angular/core';\nimport { KopyConfig } from '@kopynator/core';\nimport { KOPY_CONFIG, KopyService } from './lib/kopy.service';\n\nexport * from './lib/kopy.service';\nexport * from './lib/kopy.pipe';\nexport * from './lib/kopy.directive';\nexport * from './lib/kopy.selector.component';\nexport * from './lib/kopy-ready.component';\n\n/**\n * Provides the Kopynator SDK configuration to the application.\n * Like ngx-translate: translations are loaded in APP_INITIALIZER before the app\n * bootstraps, so no wrapper component is needed and the pipe never shows raw keys.\n */\nexport function provideKopynator(config: KopyConfig): (Provider | EnvironmentProviders)[] {\n return [\n {\n provide: KOPY_CONFIG,\n useValue: config\n },\n KopyService,\n provideAppInitializer(() => {\n const kopyService = inject(KopyService);\n return kopyService.init();\n })\n ];\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.KopyService"],"mappings":"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"}
1
+ {"version":3,"file":"kopynator-angular.mjs","sources":["../../../../packages/angular/src/lib/kopy.service.ts","../../../../packages/angular/src/lib/kopy.pipe.ts","../../../../packages/angular/src/lib/kopy.directive.ts","../../../../packages/angular/src/lib/kopy.selector.component.ts","../../../../packages/angular/src/lib/kopy-ready.component.ts","../../../../packages/angular/src/public-api.ts","../../../../packages/angular/src/kopynator-angular.ts"],"sourcesContent":["import { Injectable, Inject, InjectionToken, signal, NgZone, Optional } from '@angular/core';\nimport { Kopynator, KopyConfig } from '@kopynator/core';\n\nexport const KOPY_CONFIG = new InjectionToken<KopyConfig>('KOPY_CONFIG');\n\n/** In SSR: provide this from the request cookie so the first paint uses the user's saved locale (no flicker). */\nexport const KOPY_INITIAL_LOCALE = new InjectionToken<string | null>('KOPY_INITIAL_LOCALE');\n\nconst COOKIE_NAME = 'kopy_locale';\nconst COOKIE_MAX_AGE = 365 * 24 * 60 * 60; // 1 year\n\n/** Parse Cookie header (e.g. from req.headers.cookie) and return the value of kopy_locale, or null. */\nexport function getKopyLocaleFromCookieHeader(cookieHeader: string | undefined): string | null {\n if (!cookieHeader || typeof cookieHeader !== 'string') return null;\n const match = cookieHeader.match(new RegExp(`(?:^|;\\\\s*)${COOKIE_NAME}=([^;]*)`));\n return match ? decodeURIComponent(match[1].trim()) : null;\n}\n\nfunction readCookieFromDocument(): string | null {\n if (typeof document === 'undefined') return null;\n return getKopyLocaleFromCookieHeader(document.cookie);\n}\n\nfunction setCookieInDocument(locale: string): void {\n if (typeof document === 'undefined') return;\n document.cookie = `${COOKIE_NAME}=${encodeURIComponent(locale)};path=/;max-age=${COOKIE_MAX_AGE};SameSite=Lax`;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class KopyService {\n private kopy: Kopynator;\n\n public isReady = signal(false);\n public availableLanguages = signal<string[]>([]);\n public currentLocale = signal<string>('en');\n\n constructor(\n @Inject(KOPY_CONFIG) private config: KopyConfig,\n private zone: NgZone,\n @Optional() @Inject(KOPY_INITIAL_LOCALE) serverLocale: string | null\n ) {\n const initialLocale =\n serverLocale ??\n readCookieFromDocument() ??\n (typeof localStorage !== 'undefined' ? localStorage.getItem(COOKIE_NAME) : null) ??\n config.defaultLocale ??\n 'en';\n\n this.kopy = new Kopynator({ ...config, defaultLocale: initialLocale });\n this.currentLocale.set(initialLocale);\n }\n\n public async init(): Promise<void> {\n await this.kopy.init();\n this.zone.run(() => {\n this.availableLanguages.set(this.kopy.getLanguages());\n this.isReady.set(true);\n });\n }\n\n async setLocale(locale: string) {\n await this.kopy.setLocale(locale);\n\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(COOKIE_NAME, locale);\n }\n setCookieInDocument(locale);\n\n this.zone.run(() => {\n this.currentLocale.set(locale);\n });\n }\n\n translate(key: string, params: Record<string, any> = {}): string {\n return this.kopy.translate(key, params);\n }\n\n getKopynator(): Kopynator {\n return this.kopy;\n }\n}\n","import { Pipe, PipeTransform } from '@angular/core';\nimport { KopyService } from './kopy.service';\n\n@Pipe({\n name: 'kopy',\n pure: false, // Must be false to react to signal changes inside transform\n standalone: true\n})\nexport class KopyPipe implements PipeTransform {\n constructor(\n private kopyService: KopyService\n ) {}\n\n transform(key: string, params: Record<string, any> = {}): string {\n const ready = this.kopyService.isReady();\n this.kopyService.currentLocale(); // reactive dependency\n if (!ready) return '';\n\n return this.kopyService.translate(key, params);\n }\n}\n","import { Directive, ElementRef, Input, OnChanges, SimpleChanges, effect } from '@angular/core';\nimport { KopyService } from './kopy.service';\n\n@Directive({\n selector: '[kopy]',\n standalone: true\n})\nexport class KopyDirective implements OnChanges {\n @Input('kopy') key!: string;\n @Input() kopyParams: Record<string, any> = {};\n\n constructor(\n private el: ElementRef,\n private kopyService: KopyService\n ) {\n // React to signal changes in KopyService\n effect(() => {\n this.kopyService.currentLocale();\n this.kopyService.isReady();\n this.render();\n });\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n this.render();\n }\n\n private render() {\n if (!this.key) return;\n if (!this.kopyService.isReady()) {\n this.el.nativeElement.textContent = '';\n return;\n }\n this.el.nativeElement.textContent = this.kopyService.translate(this.key, this.kopyParams);\n }\n}\n","import { Component, inject, signal } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { KopyService } from './kopy.service';\n\n@Component({\n selector: 'kopy-selector',\n standalone: true,\n imports: [CommonModule],\n template: `\n <div class=\"kopy-selector-container\" [class.open]=\"isOpen()\">\n <button class=\"kopy-selected-btn\" (click)=\"toggleDropdown()\">\n <span class=\"flag\">{{ getFlag(currentLocale()) }}</span>\n <span class=\"label uppercase\">{{ currentLocale() }}</span>\n <svg class=\"chevron\" [class.rotate]=\"isOpen()\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n\n <div class=\"kopy-dropdown\" *ngIf=\"isOpen()\">\n <button \n *ngFor=\"let lang of languages()\" \n class=\"kopy-dropdown-item\"\n [class.active]=\"lang === currentLocale()\"\n (click)=\"selectLanguage(lang)\"\n >\n <span class=\"flag\">{{ getFlag(lang) }}</span>\n <span class=\"label\">{{ getNativeName(lang) }}</span>\n </button>\n </div>\n </div>\n `,\n styles: [`\n .kopy-selector-container {\n position: relative;\n display: inline-block;\n font-family: inherit;\n }\n .kopy-selected-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 99px;\n color: white;\n cursor: pointer;\n transition: all 0.2s;\n font-size: 11px;\n font-weight: 700;\n min-width: 70px;\n justify-content: center;\n }\n .kopy-selected-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n }\n .chevron {\n width: 10px;\n height: 10px;\n opacity: 0.5;\n transition: transform 0.2s;\n }\n .chevron.rotate {\n transform: rotate(180deg);\n }\n .kopy-dropdown {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 8px;\n background: #1e293b;\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 12px;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);\n overflow: hidden;\n min-width: 140px;\n z-index: 100;\n animation: slideIn 0.2s ease-out;\n }\n .kopy-dropdown-item {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 16px;\n background: transparent;\n border: none;\n color: #94a3b8;\n cursor: pointer;\n text-align: left;\n transition: all 0.2s;\n font-size: 14px;\n }\n .kopy-dropdown-item:hover {\n background: rgba(255, 255, 255, 0.05);\n color: white;\n }\n .kopy-dropdown-item.active {\n color: #38bdf8;\n background: rgba(56, 189, 248, 0.05);\n }\n .label {\n flex: 1;\n }\n .flag {\n font-size: 16px;\n }\n @keyframes slideIn {\n from { opacity: 0; transform: translateY(-10px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `]\n})\nexport class KopySelectorComponent {\n private kopyService = inject(KopyService);\n \n public isOpen = signal(false);\n public languages = this.kopyService.availableLanguages;\n public currentLocale = this.kopyService.currentLocale;\n\n private flagMap: Record<string, string> = {\n 'en': '🇺🇸',\n 'es': '🇪🇸',\n 'fr': '🇫🇷',\n 'de': '🇩🇪',\n 'it': '🇮🇹',\n 'pt': '🇵🇹',\n 'ja': '🇯🇵',\n 'zh': '🇨🇳',\n 'ru': '🇷🇺'\n };\n\n private nameMap: Record<string, string> = {\n 'en': 'English',\n 'es': 'Español',\n 'fr': 'Français',\n 'de': 'Deutsch',\n 'it': 'Italiano',\n 'pt': 'Português',\n 'ja': '日本語',\n 'zh': '中文',\n 'ru': 'Русский',\n 'en-us': 'English (US)'\n };\n\n toggleDropdown() {\n this.isOpen.set(!this.isOpen());\n }\n\n selectLanguage(lang: string) {\n this.kopyService.setLocale(lang);\n this.isOpen.set(false);\n }\n\n getFlag(lang: string): string {\n const code = lang.split('-')[0].toLowerCase();\n return this.flagMap[code] || '🌐';\n }\n\n getNativeName(lang: string): string {\n return this.nameMap[lang.toLowerCase()] || lang.toUpperCase();\n }\n}\n","import { Component, inject, input } from '@angular/core';\nimport { KopyService } from './kopy.service';\n\n/**\n * Envuelve el contenido y solo lo muestra cuando las traducciones están cargadas (isReady).\n * Evita el parpadeo de claves (FOUT) sin tener que usar señales ni afterNextRender en la app.\n *\n * Uso en app.html:\n * <kopy-ready>\n * <router-outlet></router-outlet>\n * </kopy-ready>\n *\n * Opcional: showLoader=false para no mostrar spinner (solo espacio vacío hasta que cargue).\n */\n@Component({\n selector: 'kopy-ready',\n standalone: true,\n template: `\n @if (kopyService.isReady()) {\n <ng-content></ng-content>\n } @else if (showLoader()) {\n <div class=\"kopy-ready-loading\" aria-busy=\"true\" aria-label=\"Cargando traducciones\">\n <span class=\"kopy-ready-spinner\" aria-hidden=\"true\"></span>\n </div>\n }\n `,\n styles: [`\n .kopy-ready-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 60vh;\n }\n .kopy-ready-spinner {\n display: inline-block;\n width: 2rem;\n height: 2rem;\n border: 2px solid rgba(6, 182, 212, 0.3);\n border-top-color: rgb(6, 182, 212);\n border-radius: 50%;\n animation: kopy-spin 0.7s linear infinite;\n }\n @keyframes kopy-spin {\n to { transform: rotate(360deg); }\n }\n `]\n})\nexport class KopyReadyComponent {\n readonly kopyService = inject(KopyService);\n /** Si true (por defecto), muestra un spinner mientras cargan las traducciones. */\n readonly showLoader = input<boolean>(true);\n}\n","import { Provider, provideAppInitializer, inject, EnvironmentProviders } from '@angular/core';\nimport { KopyConfig } from '@kopynator/core';\nimport { KOPY_CONFIG, KopyService } from './lib/kopy.service';\n\nexport * from './lib/kopy.service';\nexport * from './lib/kopy.pipe';\nexport * from './lib/kopy.directive';\nexport * from './lib/kopy.selector.component';\nexport * from './lib/kopy-ready.component';\n\n/**\n * Provides the Kopynator SDK configuration to the application.\n * Like ngx-translate: translations are loaded in APP_INITIALIZER before the app\n * bootstraps, so no wrapper component is needed and the pipe never shows raw keys.\n */\nexport function provideKopynator(config: KopyConfig): (Provider | EnvironmentProviders)[] {\n return [\n {\n provide: KOPY_CONFIG,\n useValue: config\n },\n KopyService,\n provideAppInitializer(() => {\n const kopyService = inject(KopyService);\n return kopyService.init();\n })\n ];\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.KopyService"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kopynator/angular",
3
- "version": "1.0.12",
3
+ "version": "1.0.15",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -3,21 +3,23 @@ import { InjectionToken, NgZone, PipeTransform, OnChanges, ElementRef, SimpleCha
3
3
  import { KopyConfig, Kopynator } from '@kopynator/core';
4
4
 
5
5
  declare const KOPY_CONFIG: InjectionToken<KopyConfig>;
6
+ /** In SSR: provide this from the request cookie so the first paint uses the user's saved locale (no flicker). */
7
+ declare const KOPY_INITIAL_LOCALE: InjectionToken<string>;
8
+ /** Parse Cookie header (e.g. from req.headers.cookie) and return the value of kopy_locale, or null. */
9
+ declare function getKopyLocaleFromCookieHeader(cookieHeader: string | undefined): string | null;
6
10
  declare class KopyService {
7
11
  private config;
8
12
  private zone;
9
13
  private kopy;
10
- private readonly isBrowser;
11
14
  isReady: i0.WritableSignal<boolean>;
12
15
  availableLanguages: i0.WritableSignal<string[]>;
13
16
  currentLocale: i0.WritableSignal<string>;
14
- constructor(config: KopyConfig, zone: NgZone, platformId: object);
15
- private injectHydratingStyles;
17
+ constructor(config: KopyConfig, zone: NgZone, serverLocale: string | null);
16
18
  init(): Promise<void>;
17
19
  setLocale(locale: string): Promise<void>;
18
20
  translate(key: string, params?: Record<string, any>): string;
19
21
  getKopynator(): Kopynator;
20
- static ɵfac: i0.ɵɵFactoryDeclaration<KopyService, never>;
22
+ static ɵfac: i0.ɵɵFactoryDeclaration<KopyService, [null, null, { optional: true; }]>;
21
23
  static ɵprov: i0.ɵɵInjectableDeclaration<KopyService>;
22
24
  }
23
25
 
@@ -82,4 +84,4 @@ declare class KopyReadyComponent {
82
84
  */
83
85
  declare function provideKopynator(config: KopyConfig): (Provider | EnvironmentProviders)[];
84
86
 
85
- export { KOPY_CONFIG, KopyDirective, KopyPipe, KopyReadyComponent, KopySelectorComponent, KopyService, provideKopynator };
87
+ export { KOPY_CONFIG, KOPY_INITIAL_LOCALE, KopyDirective, KopyPipe, KopyReadyComponent, KopySelectorComponent, KopyService, getKopyLocaleFromCookieHeader, provideKopynator };