@magic-translate/angular 1.1.0 → 1.2.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.2.0](https://github.com/magic-translate/magic-translate/compare/angular-v1.1.0...angular-v1.2.0) (2026-11-06)
4
+
5
+
6
+ ### Features
7
+
8
+ * **angular:** translate with the secret key on the server ([5f6fae1](https://github.com/magic-translate/magic-translate/commit/5f6fae1fdbaebefe0cb7c62939eb3a03a8419950))
9
+ * id option to edit one use of a text on its own ([9127af3](https://github.com/magic-translate/magic-translate/commit/9127af36de4d63be076e8e192a16584968b4655a))
10
+
3
11
  ## [1.1.0](https://github.com/magic-translate/magic-translate/compare/angular-v1.0.2...angular-v1.1.0) (2026-11-02)
4
12
 
5
13
 
package/README.md CHANGED
@@ -160,6 +160,17 @@ formality:
160
160
  <input [placeholder]="'Your name' | t: { lang: 'fr', formality: 'formal' }" />
161
161
  ```
162
162
 
163
+ An `id` lets you edit one use of a text on its own in the webapp, e.g. to
164
+ translate the same "Save" differently on two buttons. Its edited translation
165
+ stays when the text changes. Ids are unique within your account and at most 128
166
+ characters.
167
+
168
+ ```html
169
+ <t id="checkout-save">Save</t>
170
+
171
+ <button [title]="'Save' | t: { id: 'checkout-save' }"></button>
172
+ ```
173
+
163
174
  ### Switching languages
164
175
 
165
176
  Inject the `MagicTranslate` service to read or change the current language.
@@ -217,6 +228,12 @@ original content, and it is translated after hydration. A `<t>` with `[v]`
217
228
  renders empty on the server, so `$name` never shows, and appears once the app
218
229
  runs in the browser.
219
230
 
231
+ Code that translates on the server, such as a resolver run while prerendering,
232
+ sends your secret key (`p-...`) from the `MAGIC_TRANSLATE_SECRET_KEY`
233
+ environment variable instead of the API key. Create it on your
234
+ [account page](https://magictranslate.io/account) and keep it out of
235
+ `provideMagicTranslate`, which also runs in the browser.
236
+
220
237
  ## License
221
238
 
222
239
  MIT © [i42 GmbH](https://i42.ch)
@@ -74,12 +74,13 @@ var MagicTranslate = class MagicTranslate {
74
74
  sourceLanguage = this.config.sourceLanguage;
75
75
  language = computed(() => this.languageOverride() ?? this.config.language, ...ngDevMode ? [{ debugName: "language" }] : /* istanbul ignore next */ []);
76
76
  dataLoader = computed(() => {
77
- const { debug, apiKey, sourceLanguage, _apiUrl, formality } = this.config;
77
+ const { debug, apiKey, secretKey, sourceLanguage, _apiUrl, formality } = this.config;
78
78
  const loaderFactory = this.config._loaderFactory ?? defaultLoaderFactory;
79
79
  const language = this.language();
80
80
  return new DataLoader(loaderFactory({
81
81
  debug: !!debug,
82
82
  apiKey,
83
+ secretKey,
83
84
  lang: language,
84
85
  sourceLang: sourceLanguage,
85
86
  apiUrl: _apiUrl,
@@ -168,6 +169,7 @@ function readSource(element) {
168
169
  var Translate = class Translate {
169
170
  lang = input(void 0, ...ngDevMode ? [{ debugName: "lang" }] : /* istanbul ignore next */ []);
170
171
  formality = input(void 0, ...ngDevMode ? [{ debugName: "formality" }] : /* istanbul ignore next */ []);
172
+ id = input(void 0, ...ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []);
171
173
  v = input(void 0, ...ngDevMode ? [{ debugName: "v" }] : /* istanbul ignore next */ []);
172
174
  magicTranslate = inject(MagicTranslate);
173
175
  sanitizer = inject(DomSanitizer);
@@ -196,6 +198,7 @@ var Translate = class Translate {
196
198
  const source = this.source();
197
199
  const lang = this.lang();
198
200
  const formality = this.formality();
201
+ const id = this.id();
199
202
  const variables = this.v();
200
203
  this.magicTranslate.language();
201
204
  if (!source?.html) {
@@ -215,7 +218,8 @@ var Translate = class Translate {
215
218
  const requestId = ++this.lastRequestId;
216
219
  this.magicTranslate.translate(template, {
217
220
  lang,
218
- formality
221
+ formality,
222
+ id
219
223
  }).then((translation) => {
220
224
  if (requestId === this.lastRequestId) this.render(source, translation, values);
221
225
  });
@@ -262,6 +266,13 @@ var Translate = class Translate {
262
266
  isRequired: false,
263
267
  transformFunction: null
264
268
  },
269
+ id: {
270
+ classPropertyName: "id",
271
+ publicName: "id",
272
+ isSignal: true,
273
+ isRequired: false,
274
+ transformFunction: null
275
+ },
265
276
  v: {
266
277
  classPropertyName: "v",
267
278
  publicName: "v",
@@ -270,7 +281,10 @@ var Translate = class Translate {
270
281
  transformFunction: null
271
282
  }
272
283
  },
273
- host: { styleAttribute: "display: contents" },
284
+ host: {
285
+ properties: { "attr.id": "null" },
286
+ styleAttribute: "display: contents"
287
+ },
274
288
  viewQueries: [{
275
289
  propertyName: "sourceRef",
276
290
  first: true,
@@ -315,7 +329,10 @@ i0.ɵɵngDeclareClassMetadata({
315
329
  #target
316
330
  [style.display]="translated() ? 'contents' : 'none'"
317
331
  ></span>`,
318
- host: { style: "display: contents" },
332
+ host: {
333
+ style: "display: contents",
334
+ "[attr.id]": "null"
335
+ },
319
336
  encapsulation: ViewEncapsulation.None,
320
337
  changeDetection: ChangeDetectionStrategy.OnPush
321
338
  }]
@@ -338,6 +355,14 @@ i0.ɵɵngDeclareClassMetadata({
338
355
  required: false
339
356
  }]
340
357
  }],
358
+ id: [{
359
+ type: i0.Input,
360
+ args: [{
361
+ isSignal: true,
362
+ alias: "id",
363
+ required: false
364
+ }]
365
+ }],
341
366
  v: [{
342
367
  type: i0.Input,
343
368
  args: [{
@@ -1 +1 @@
1
- {"version":3,"file":"magic-translate-angular.mjs","names":[],"sources":["../../src/lib/magic-translate-config.ts","../../src/lib/variables.ts","../../src/lib/magic-translate.service.ts","../../src/lib/provide-magic-translate.ts","../../src/lib/translate.component.ts","../../src/lib/translate.pipe.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nimport { MagicTranslateConfig } from '@magic-translate/core';\n\nexport const MAGIC_TRANSLATE_CONFIG = new InjectionToken<MagicTranslateConfig>(\n 'MAGIC_TRANSLATE_CONFIG'\n);\n","import { isDevMode } from '@angular/core';\nimport { libraryName } from '@magic-translate/core';\n\n/**\n * Values that are not translated, referenced as `$name` in the text.\n */\nexport type Variables = Record<string, unknown>;\n\nconst PLACEHOLDER = /\\{(\\d+)\\}/g;\n\nconst escapeRegExp = (text: string) =>\n text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/**\n * Replaces `$name` with numbered placeholders, `{0}`, `{1}`…, in the order the\n * names first appear, so the API sees the same template as from the React\n * client. Only names that are keys of `variables` are replaced, and the longest\n * key wins, so `$counts` is not read as `$count` followed by \"s\".\n *\n * `replace` can be called for several texts, e.g. every text node of an HTML\n * fragment, and numbers the placeholders across all of them.\n */\nexport function templater(variables: Variables) {\n const names = Object.keys(variables).sort((a, b) => b.length - a.length);\n const pattern =\n names.length > 0\n ? new RegExp(`\\\\$(${names.map(escapeRegExp).join('|')})`, 'g')\n : null;\n const indexes = new Map<string, number>();\n const values: string[] = [];\n\n return {\n values,\n replace(text: string): string {\n if (!pattern) {\n return text;\n }\n return text.replace(pattern, (_, name: string) => {\n let index = indexes.get(name);\n if (index === undefined) {\n index = values.push(String(variables[name] ?? '')) - 1;\n indexes.set(name, index);\n }\n return `{${index}}`;\n });\n },\n unused: () => names.filter((name) => !indexes.has(name)),\n };\n}\n\nexport interface Template {\n template: string;\n values: string[];\n // names that are not in the text, most likely misspelled\n unused: string[];\n}\n\nexport function warnAboutUnused(unused: readonly string[]) {\n if (isDevMode() && unused.length > 0) {\n console.warn(\n `[${libraryName}]: ${unused.map((name) => `$${name}`).join(', ')} not found in the text. Check the spelling, or remove ${unused.length === 1 ? 'it' : 'them'} from the variables.`\n );\n }\n}\n\nexport function toTemplate(text: string, variables: Variables): Template {\n const { replace, values, unused } = templater(variables);\n return { template: replace(text), values, unused: unused() };\n}\n\n/**\n * Puts the values back into a translated text. A placeholder without a value\n * is left as it is.\n */\nexport function fillPlaceholders(text: string, values: readonly string[]) {\n return text.replace(PLACEHOLDER, (placeholder, index: string) =>\n Number(index) < values.length ? values[Number(index)] : placeholder\n );\n}\n\nfunction textNodes(root: Node): Text[] {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);\n const nodes: Text[] = [];\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n nodes.push(node as Text);\n }\n return nodes;\n}\n\n/**\n * Like {@link toTemplate}, for HTML. Only text is replaced, never attributes,\n * because only text can be filled in again.\n */\nexport function toHtmlTemplate(html: string, variables: Variables): Template {\n const container = document.createElement('template');\n container.innerHTML = html;\n const { replace, values, unused } = templater(variables);\n textNodes(container.content).forEach((node) => {\n node.data = replace(node.data);\n });\n return { template: container.innerHTML, values, unused: unused() };\n}\n\n/**\n * Fills the placeholders in the text of an element. The values are set as\n * text, so they are never parsed as HTML.\n */\nexport function fillElement(element: Element, values: readonly string[]) {\n textNodes(element).forEach((node) => {\n const filled = fillPlaceholders(node.data, values);\n if (filled !== node.data) {\n node.data = filled;\n }\n });\n}\n","import { computed, inject, Injectable, signal } from '@angular/core';\nimport {\n cacheKeyFn,\n DataLoader,\n DataLoaderLoadParams,\n defaultLoaderFactory,\n Language,\n libraryWebsite,\n} from '@magic-translate/core';\nimport { MAGIC_TRANSLATE_CONFIG } from './magic-translate-config';\nimport {\n fillPlaceholders,\n toTemplate,\n Variables,\n warnAboutUnused,\n} from './variables';\n\n/**\n * Type alias to make the language enum more flexible to also allow passing language strings\n * instead of just the enum.\n */\nexport type Languages = `${Language}`;\n\nexport interface TranslateParams extends Omit<DataLoaderLoadParams, 'text'> {\n /**\n * Values that are not translated, referenced as `$name` in the text. The text\n * is translated once as a template and cached, whatever the values are.\n */\n v?: Variables;\n}\n\n@Injectable()\nexport class MagicTranslate {\n private readonly config = inject(MAGIC_TRANSLATE_CONFIG);\n private readonly languageOverride = signal<Languages | null>(null);\n\n readonly apiKey = this.config.apiKey;\n readonly sourceLanguage = this.config.sourceLanguage;\n\n /**\n * The language content is currently translated to.\n */\n readonly language = computed(\n () => this.languageOverride() ?? this.config.language\n );\n\n readonly dataLoader = computed(() => {\n const { debug, apiKey, sourceLanguage, _apiUrl, formality } = this.config;\n const loaderFactory = this.config._loaderFactory ?? defaultLoaderFactory;\n const language = this.language();\n\n return new DataLoader<DataLoaderLoadParams, string, string>(\n loaderFactory({\n debug: !!debug,\n apiKey,\n lang: language,\n sourceLang: sourceLanguage,\n apiUrl: _apiUrl,\n formality,\n }),\n { cacheKeyFn: cacheKeyFn(apiKey, sourceLanguage, language) }\n );\n });\n\n constructor() {\n if (!this.config.apiKey) {\n throw new Error(`Missing API key. Please get one at ${libraryWebsite}`);\n }\n }\n\n setLanguage(language: Languages): void {\n this.languageOverride.set(language);\n }\n\n translate(\n text: string,\n { v, ...params }: TranslateParams = {}\n ): Promise<string> {\n if (!v) {\n return this.dataLoader().load({ text, ...params });\n }\n const { template, values, unused } = toTemplate(text, v);\n warnAboutUnused(unused);\n return this.dataLoader()\n .load({ text: template, ...params })\n .then((translation) => fillPlaceholders(translation, values));\n }\n\n /** @ignore */\n cacheKey(text: string, params: Omit<TranslateParams, 'v'> = {}): string {\n return cacheKeyFn(\n this.apiKey,\n this.sourceLanguage,\n this.language()\n )({ text, ...params });\n }\n}\n","import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\nimport { MagicTranslateConfig } from '@magic-translate/core';\nimport { MAGIC_TRANSLATE_CONFIG } from './magic-translate-config';\nimport { MagicTranslate } from './magic-translate.service';\n\n/**\n * Sets up Magic Translate for the application. Add it to the `providers` of\n * your application config.\n */\nexport function provideMagicTranslate(\n config: MagicTranslateConfig\n): EnvironmentProviders {\n return makeEnvironmentProviders([\n { provide: MAGIC_TRANSLATE_CONFIG, useValue: config },\n MagicTranslate,\n ]);\n}\n","import {\n afterNextRender,\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n effect,\n ElementRef,\n inject,\n input,\n SecurityContext,\n signal,\n untracked,\n viewChild,\n ViewEncapsulation,\n} from '@angular/core';\nimport { DomSanitizer } from '@angular/platform-browser';\nimport { libraryName, TranslateOptions } from '@magic-translate/core';\nimport { Languages, MagicTranslate } from './magic-translate.service';\nimport {\n fillElement,\n toHtmlTemplate,\n Variables,\n warnAboutUnused,\n} from './variables';\n\ninterface Source {\n html: string;\n leadingWhitespace: string;\n trailingWhitespace: string;\n // The `_ngcontent-*` attribute of the host template, so its component\n // styles still apply to the translated markup.\n scopeAttribute?: string;\n}\n\n/**\n * Turns the projected content into the HTML string that gets translated,\n * without the comments and attributes Angular adds to the DOM.\n */\nfunction readSource(element: HTMLElement): Source {\n const clone = element.cloneNode(true) as HTMLElement;\n const comments: Node[] = [];\n let scopeAttribute: string | undefined;\n\n const walker = document.createTreeWalker(\n clone,\n NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT\n );\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n if (node.nodeType === Node.COMMENT_NODE) {\n comments.push(node);\n continue;\n }\n\n const el = node as Element;\n if (el.localName.includes('-')) {\n throw new Error(\n `Components are not allowed inside \\`<t>...</t>\\` components. The component found inside the t component is <${el.localName}>.`\n );\n }\n\n for (const { name } of Array.from(el.attributes)) {\n if (name.startsWith('_ngcontent-')) {\n scopeAttribute = name;\n }\n if (name.startsWith('_ng') || name.startsWith('ng-reflect-')) {\n el.removeAttribute(name);\n }\n }\n }\n comments.forEach((comment) => comment.parentNode?.removeChild(comment));\n\n const [, leadingWhitespace, html, trailingWhitespace] =\n /^(\\s*)([\\s\\S]*?)(\\s*)$/.exec(clone.innerHTML)!;\n\n return { html, leadingWhitespace, trailingWhitespace, scopeAttribute };\n}\n\n@Component({\n selector: 't, mt-translate',\n // With variables, the source would show `$name`, so it stays hidden and the\n // text is shown with the values filled in until the translation arrives.\n template: `<span\n #source\n [style.display]=\"translated() || v() ? 'none' : 'contents'\"\n ><ng-content /></span\n ><span\n #target\n [style.display]=\"translated() ? 'contents' : 'none'\"\n ></span>`,\n host: { style: 'display: contents' },\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class Translate {\n readonly lang = input<Languages | undefined>(undefined);\n readonly formality = input<TranslateOptions['formality']>(undefined);\n /**\n * Values that are not translated, referenced as `$name` in the content. The\n * text is translated once as a template and cached, whatever the values are.\n */\n readonly v = input<Variables | undefined>(undefined);\n\n private readonly magicTranslate = inject(MagicTranslate);\n private readonly sanitizer = inject(DomSanitizer);\n private readonly sourceRef =\n viewChild.required<ElementRef<HTMLElement>>('source');\n private readonly targetRef =\n viewChild.required<ElementRef<HTMLElement>>('target');\n\n private readonly source = signal<Source | null>(null);\n protected readonly translated = signal(false);\n private lastRequestId = 0;\n private lastTemplate?: string;\n\n constructor() {\n const destroyRef = inject(DestroyRef);\n\n afterNextRender(() => {\n const element = this.sourceRef().nativeElement;\n const read = () => this.source.set(readSource(element));\n read();\n\n // Picks up changes to the projected content, such as interpolations.\n const observer = new MutationObserver(read);\n observer.observe(element, {\n subtree: true,\n childList: true,\n characterData: true,\n attributes: true,\n });\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n effect(() => {\n const source = this.source();\n const lang = this.lang();\n const formality = this.formality();\n const variables = this.v();\n // a language switch has to re-translate the content\n this.magicTranslate.language();\n\n if (!source?.html) {\n this.translated.set(false);\n return;\n }\n\n const { template, values, unused } = variables\n ? toHtmlTemplate(source.html, variables)\n : { template: source.html, values: [], unused: [] };\n if (template !== this.lastTemplate) {\n this.lastTemplate = template;\n warnAboutUnused(unused);\n }\n if (variables && !untracked(this.translated)) {\n this.render(source, template, values);\n }\n\n // make sure that we only ever use the response of the most recent request.\n const requestId = ++this.lastRequestId;\n this.magicTranslate\n .translate(template, { lang, formality })\n .then((translation) => {\n if (requestId === this.lastRequestId) {\n this.render(source, translation, values);\n }\n });\n });\n }\n\n private render(\n source: Source,\n translation: string,\n values: readonly string[] = []\n ) {\n const target = this.targetRef().nativeElement;\n const html = this.sanitizer.sanitize(SecurityContext.HTML, translation);\n if (html === null) {\n console.warn(`[${libraryName}]: Could not render translation.`);\n return;\n }\n\n target.innerHTML = `${source.leadingWhitespace}${html}${source.trailingWhitespace}`;\n if (values.length > 0) {\n fillElement(target, values);\n }\n if (source.scopeAttribute) {\n target\n .querySelectorAll('*')\n .forEach((el) => el.setAttribute(source.scopeAttribute!, ''));\n }\n this.translated.set(true);\n }\n}\n\nexport const T = Translate;\n","import { isPlatformServer } from '@angular/common';\nimport {\n ChangeDetectorRef,\n inject,\n Pipe,\n PipeTransform,\n PLATFORM_ID,\n} from '@angular/core';\nimport { MagicTranslate, TranslateParams } from './magic-translate.service';\nimport { fillPlaceholders, toTemplate, warnAboutUnused } from './variables';\n\n/**\n * Translates a plain string, e.g. for attributes:\n * `<input [placeholder]=\"'Search' | t\" />`. Returns the original text until\n * the translation has loaded.\n *\n * Values that should not be translated go in `v` and are referenced as `$name`:\n * `'Search $count products' | t: { v: { count } }`.\n */\n@Pipe({ name: 't', pure: false })\nexport class TranslatePipe implements PipeTransform {\n private readonly magicTranslate = inject(MagicTranslate);\n private readonly changeDetectorRef = inject(ChangeDetectorRef);\n private readonly isServer = isPlatformServer(inject(PLATFORM_ID));\n\n private key?: string;\n private translation?: string;\n\n transform(text: string, { v, ...params }: TranslateParams = {}): string {\n // Only the template is translated, so new values reuse the translation.\n const { template, values, unused } = v\n ? toTemplate(text, v)\n : { template: text, values: [], unused: [] };\n\n if (!text || this.isServer) {\n return fillPlaceholders(template, values);\n }\n\n const key = this.magicTranslate.cacheKey(template, params);\n if (key !== this.key) {\n warnAboutUnused(unused);\n this.key = key;\n this.translation = undefined;\n this.magicTranslate.translate(template, params).then((translation) => {\n if (this.key === key) {\n this.translation = translation;\n this.changeDetectorRef.markForCheck();\n }\n });\n }\n\n return fillPlaceholders(this.translation ?? template, values);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"magic-translate-angular.mjs","names":[],"sources":["../../src/lib/magic-translate-config.ts","../../src/lib/variables.ts","../../src/lib/magic-translate.service.ts","../../src/lib/provide-magic-translate.ts","../../src/lib/translate.component.ts","../../src/lib/translate.pipe.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nimport { MagicTranslateConfig } from '@magic-translate/core';\n\nexport const MAGIC_TRANSLATE_CONFIG = new InjectionToken<MagicTranslateConfig>(\n 'MAGIC_TRANSLATE_CONFIG'\n);\n","import { isDevMode } from '@angular/core';\nimport { libraryName } from '@magic-translate/core';\n\n/**\n * Values that are not translated, referenced as `$name` in the text.\n */\nexport type Variables = Record<string, unknown>;\n\nconst PLACEHOLDER = /\\{(\\d+)\\}/g;\n\nconst escapeRegExp = (text: string) =>\n text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/**\n * Replaces `$name` with numbered placeholders, `{0}`, `{1}`…, in the order the\n * names first appear, so the API sees the same template as from the React\n * client. Only names that are keys of `variables` are replaced, and the longest\n * key wins, so `$counts` is not read as `$count` followed by \"s\".\n *\n * `replace` can be called for several texts, e.g. every text node of an HTML\n * fragment, and numbers the placeholders across all of them.\n */\nexport function templater(variables: Variables) {\n const names = Object.keys(variables).sort((a, b) => b.length - a.length);\n const pattern =\n names.length > 0\n ? new RegExp(`\\\\$(${names.map(escapeRegExp).join('|')})`, 'g')\n : null;\n const indexes = new Map<string, number>();\n const values: string[] = [];\n\n return {\n values,\n replace(text: string): string {\n if (!pattern) {\n return text;\n }\n return text.replace(pattern, (_, name: string) => {\n let index = indexes.get(name);\n if (index === undefined) {\n index = values.push(String(variables[name] ?? '')) - 1;\n indexes.set(name, index);\n }\n return `{${index}}`;\n });\n },\n unused: () => names.filter((name) => !indexes.has(name)),\n };\n}\n\nexport interface Template {\n template: string;\n values: string[];\n // names that are not in the text, most likely misspelled\n unused: string[];\n}\n\nexport function warnAboutUnused(unused: readonly string[]) {\n if (isDevMode() && unused.length > 0) {\n console.warn(\n `[${libraryName}]: ${unused.map((name) => `$${name}`).join(', ')} not found in the text. Check the spelling, or remove ${unused.length === 1 ? 'it' : 'them'} from the variables.`\n );\n }\n}\n\nexport function toTemplate(text: string, variables: Variables): Template {\n const { replace, values, unused } = templater(variables);\n return { template: replace(text), values, unused: unused() };\n}\n\n/**\n * Puts the values back into a translated text. A placeholder without a value\n * is left as it is.\n */\nexport function fillPlaceholders(text: string, values: readonly string[]) {\n return text.replace(PLACEHOLDER, (placeholder, index: string) =>\n Number(index) < values.length ? values[Number(index)] : placeholder\n );\n}\n\nfunction textNodes(root: Node): Text[] {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);\n const nodes: Text[] = [];\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n nodes.push(node as Text);\n }\n return nodes;\n}\n\n/**\n * Like {@link toTemplate}, for HTML. Only text is replaced, never attributes,\n * because only text can be filled in again.\n */\nexport function toHtmlTemplate(html: string, variables: Variables): Template {\n const container = document.createElement('template');\n container.innerHTML = html;\n const { replace, values, unused } = templater(variables);\n textNodes(container.content).forEach((node) => {\n node.data = replace(node.data);\n });\n return { template: container.innerHTML, values, unused: unused() };\n}\n\n/**\n * Fills the placeholders in the text of an element. The values are set as\n * text, so they are never parsed as HTML.\n */\nexport function fillElement(element: Element, values: readonly string[]) {\n textNodes(element).forEach((node) => {\n const filled = fillPlaceholders(node.data, values);\n if (filled !== node.data) {\n node.data = filled;\n }\n });\n}\n","import { computed, inject, Injectable, signal } from '@angular/core';\nimport {\n cacheKeyFn,\n DataLoader,\n DataLoaderLoadParams,\n defaultLoaderFactory,\n Language,\n libraryWebsite,\n} from '@magic-translate/core';\nimport { MAGIC_TRANSLATE_CONFIG } from './magic-translate-config';\nimport {\n fillPlaceholders,\n toTemplate,\n Variables,\n warnAboutUnused,\n} from './variables';\n\n/**\n * Type alias to make the language enum more flexible to also allow passing language strings\n * instead of just the enum.\n */\nexport type Languages = `${Language}`;\n\nexport interface TranslateParams extends Omit<DataLoaderLoadParams, 'text'> {\n /**\n * Values that are not translated, referenced as `$name` in the text. The text\n * is translated once as a template and cached, whatever the values are.\n */\n v?: Variables;\n}\n\n@Injectable()\nexport class MagicTranslate {\n private readonly config = inject(MAGIC_TRANSLATE_CONFIG);\n private readonly languageOverride = signal<Languages | null>(null);\n\n readonly apiKey = this.config.apiKey;\n readonly sourceLanguage = this.config.sourceLanguage;\n\n /**\n * The language content is currently translated to.\n */\n readonly language = computed(\n () => this.languageOverride() ?? this.config.language\n );\n\n readonly dataLoader = computed(() => {\n const { debug, apiKey, secretKey, sourceLanguage, _apiUrl, formality } =\n this.config;\n const loaderFactory = this.config._loaderFactory ?? defaultLoaderFactory;\n const language = this.language();\n\n return new DataLoader<DataLoaderLoadParams, string, string>(\n loaderFactory({\n debug: !!debug,\n apiKey,\n secretKey,\n lang: language,\n sourceLang: sourceLanguage,\n apiUrl: _apiUrl,\n formality,\n }),\n { cacheKeyFn: cacheKeyFn(apiKey, sourceLanguage, language) }\n );\n });\n\n constructor() {\n if (!this.config.apiKey) {\n throw new Error(`Missing API key. Please get one at ${libraryWebsite}`);\n }\n }\n\n setLanguage(language: Languages): void {\n this.languageOverride.set(language);\n }\n\n translate(\n text: string,\n { v, ...params }: TranslateParams = {}\n ): Promise<string> {\n if (!v) {\n return this.dataLoader().load({ text, ...params });\n }\n const { template, values, unused } = toTemplate(text, v);\n warnAboutUnused(unused);\n return this.dataLoader()\n .load({ text: template, ...params })\n .then((translation) => fillPlaceholders(translation, values));\n }\n\n /** @ignore */\n cacheKey(text: string, params: Omit<TranslateParams, 'v'> = {}): string {\n return cacheKeyFn(\n this.apiKey,\n this.sourceLanguage,\n this.language()\n )({ text, ...params });\n }\n}\n","import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\nimport { MagicTranslateConfig } from '@magic-translate/core';\nimport { MAGIC_TRANSLATE_CONFIG } from './magic-translate-config';\nimport { MagicTranslate } from './magic-translate.service';\n\n/**\n * Sets up Magic Translate for the application. Add it to the `providers` of\n * your application config.\n */\nexport function provideMagicTranslate(\n config: MagicTranslateConfig\n): EnvironmentProviders {\n return makeEnvironmentProviders([\n { provide: MAGIC_TRANSLATE_CONFIG, useValue: config },\n MagicTranslate,\n ]);\n}\n","import {\n afterNextRender,\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n effect,\n ElementRef,\n inject,\n input,\n SecurityContext,\n signal,\n untracked,\n viewChild,\n ViewEncapsulation,\n} from '@angular/core';\nimport { DomSanitizer } from '@angular/platform-browser';\nimport { libraryName, TranslateOptions } from '@magic-translate/core';\nimport { Languages, MagicTranslate } from './magic-translate.service';\nimport {\n fillElement,\n toHtmlTemplate,\n Variables,\n warnAboutUnused,\n} from './variables';\n\ninterface Source {\n html: string;\n leadingWhitespace: string;\n trailingWhitespace: string;\n // The `_ngcontent-*` attribute of the host template, so its component\n // styles still apply to the translated markup.\n scopeAttribute?: string;\n}\n\n/**\n * Turns the projected content into the HTML string that gets translated,\n * without the comments and attributes Angular adds to the DOM.\n */\nfunction readSource(element: HTMLElement): Source {\n const clone = element.cloneNode(true) as HTMLElement;\n const comments: Node[] = [];\n let scopeAttribute: string | undefined;\n\n const walker = document.createTreeWalker(\n clone,\n NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT\n );\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n if (node.nodeType === Node.COMMENT_NODE) {\n comments.push(node);\n continue;\n }\n\n const el = node as Element;\n if (el.localName.includes('-')) {\n throw new Error(\n `Components are not allowed inside \\`<t>...</t>\\` components. The component found inside the t component is <${el.localName}>.`\n );\n }\n\n for (const { name } of Array.from(el.attributes)) {\n if (name.startsWith('_ngcontent-')) {\n scopeAttribute = name;\n }\n if (name.startsWith('_ng') || name.startsWith('ng-reflect-')) {\n el.removeAttribute(name);\n }\n }\n }\n comments.forEach((comment) => comment.parentNode?.removeChild(comment));\n\n const [, leadingWhitespace, html, trailingWhitespace] =\n /^(\\s*)([\\s\\S]*?)(\\s*)$/.exec(clone.innerHTML)!;\n\n return { html, leadingWhitespace, trailingWhitespace, scopeAttribute };\n}\n\n@Component({\n selector: 't, mt-translate',\n // With variables, the source would show `$name`, so it stays hidden and the\n // text is shown with the values filled in until the translation arrives.\n template: `<span\n #source\n [style.display]=\"translated() || v() ? 'none' : 'contents'\"\n ><ng-content /></span\n ><span\n #target\n [style.display]=\"translated() ? 'contents' : 'none'\"\n ></span>`,\n // `id` is an input, not the element's id, which could clash with the page's.\n host: { style: 'display: contents', '[attr.id]': 'null' },\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class Translate {\n readonly lang = input<Languages | undefined>(undefined);\n readonly formality = input<TranslateOptions['formality']>(undefined);\n /**\n * Lets this use of the text be edited on its own in the webapp. Its edited\n * translation stays when the text changes.\n */\n readonly id = input<string | undefined>(undefined);\n /**\n * Values that are not translated, referenced as `$name` in the content. The\n * text is translated once as a template and cached, whatever the values are.\n */\n readonly v = input<Variables | undefined>(undefined);\n\n private readonly magicTranslate = inject(MagicTranslate);\n private readonly sanitizer = inject(DomSanitizer);\n private readonly sourceRef =\n viewChild.required<ElementRef<HTMLElement>>('source');\n private readonly targetRef =\n viewChild.required<ElementRef<HTMLElement>>('target');\n\n private readonly source = signal<Source | null>(null);\n protected readonly translated = signal(false);\n private lastRequestId = 0;\n private lastTemplate?: string;\n\n constructor() {\n const destroyRef = inject(DestroyRef);\n\n afterNextRender(() => {\n const element = this.sourceRef().nativeElement;\n const read = () => this.source.set(readSource(element));\n read();\n\n // Picks up changes to the projected content, such as interpolations.\n const observer = new MutationObserver(read);\n observer.observe(element, {\n subtree: true,\n childList: true,\n characterData: true,\n attributes: true,\n });\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n effect(() => {\n const source = this.source();\n const lang = this.lang();\n const formality = this.formality();\n const id = this.id();\n const variables = this.v();\n // a language switch has to re-translate the content\n this.magicTranslate.language();\n\n if (!source?.html) {\n this.translated.set(false);\n return;\n }\n\n const { template, values, unused } = variables\n ? toHtmlTemplate(source.html, variables)\n : { template: source.html, values: [], unused: [] };\n if (template !== this.lastTemplate) {\n this.lastTemplate = template;\n warnAboutUnused(unused);\n }\n if (variables && !untracked(this.translated)) {\n this.render(source, template, values);\n }\n\n // make sure that we only ever use the response of the most recent request.\n const requestId = ++this.lastRequestId;\n this.magicTranslate\n .translate(template, { lang, formality, id })\n .then((translation) => {\n if (requestId === this.lastRequestId) {\n this.render(source, translation, values);\n }\n });\n });\n }\n\n private render(\n source: Source,\n translation: string,\n values: readonly string[] = []\n ) {\n const target = this.targetRef().nativeElement;\n const html = this.sanitizer.sanitize(SecurityContext.HTML, translation);\n if (html === null) {\n console.warn(`[${libraryName}]: Could not render translation.`);\n return;\n }\n\n target.innerHTML = `${source.leadingWhitespace}${html}${source.trailingWhitespace}`;\n if (values.length > 0) {\n fillElement(target, values);\n }\n if (source.scopeAttribute) {\n target\n .querySelectorAll('*')\n .forEach((el) => el.setAttribute(source.scopeAttribute!, ''));\n }\n this.translated.set(true);\n }\n}\n\nexport const T = Translate;\n","import { isPlatformServer } from '@angular/common';\nimport {\n ChangeDetectorRef,\n inject,\n Pipe,\n PipeTransform,\n PLATFORM_ID,\n} from '@angular/core';\nimport { MagicTranslate, TranslateParams } from './magic-translate.service';\nimport { fillPlaceholders, toTemplate, warnAboutUnused } from './variables';\n\n/**\n * Translates a plain string, e.g. for attributes:\n * `<input [placeholder]=\"'Search' | t\" />`. Returns the original text until\n * the translation has loaded.\n *\n * Values that should not be translated go in `v` and are referenced as `$name`:\n * `'Search $count products' | t: { v: { count } }`.\n */\n@Pipe({ name: 't', pure: false })\nexport class TranslatePipe implements PipeTransform {\n private readonly magicTranslate = inject(MagicTranslate);\n private readonly changeDetectorRef = inject(ChangeDetectorRef);\n private readonly isServer = isPlatformServer(inject(PLATFORM_ID));\n\n private key?: string;\n private translation?: string;\n\n transform(text: string, { v, ...params }: TranslateParams = {}): string {\n // Only the template is translated, so new values reuse the translation.\n const { template, values, unused } = v\n ? toTemplate(text, v)\n : { template: text, values: [], unused: [] };\n\n if (!text || this.isServer) {\n return fillPlaceholders(template, values);\n }\n\n const key = this.magicTranslate.cacheKey(template, params);\n if (key !== this.key) {\n warnAboutUnused(unused);\n this.key = key;\n this.translation = undefined;\n this.magicTranslate.translate(template, params).then((translation) => {\n if (this.key === key) {\n this.translation = translation;\n this.changeDetectorRef.markForCheck();\n }\n });\n }\n\n return fillPlaceholders(this.translation ?? template, values);\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magic-translate/angular",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "keywords": [
5
5
  "angular",
6
6
  "angular-i18n",
@@ -35,7 +35,7 @@
35
35
  "@angular/platform-browser": ">=20.0.0"
36
36
  },
37
37
  "dependencies": {
38
- "@magic-translate/core": "^1.5.0",
38
+ "@magic-translate/core": "^1.6.0",
39
39
  "tslib": "^2.8.1"
40
40
  },
41
41
  "publishConfig": {
@@ -81,6 +81,11 @@ export declare class MagicTranslate {
81
81
  export declare class Translate {
82
82
  readonly lang: import("@angular/core").InputSignal<"it" | "hr" | "th" | "tr" | "af" | "sq" | "am" | "ar" | "hy" | "az" | "bn" | "bs" | "bg" | "ca" | "zh" | "zh-TW" | "cs" | "da" | "fa-AF" | "nl" | "en" | "et" | "fa" | "tl" | "fi" | "fr" | "fr-CA" | "ka" | "de" | "el" | "gu" | "ht" | "ha" | "he" | "hi" | "hu" | "is" | "id" | "ga" | "ja" | "kn" | "kk" | "ko" | "lv" | "lt" | "mk" | "ms" | "ml" | "mt" | "mr" | "mn" | "no" | "ps" | "pl" | "pt" | "pt-PT" | "pa" | "ro" | "ru" | "sr" | "si" | "sk" | "sl" | "so" | "es" | "es-MX" | "sw" | "sv" | "ta" | "te" | "uk" | "ur" | "uz" | "vi" | "cy" | undefined>;
83
83
  readonly formality: import("@angular/core").InputSignal<"formal" | "informal" | undefined>;
84
+ /**
85
+ * Lets this use of the text be edited on its own in the webapp. Its edited
86
+ * translation stays when the text changes.
87
+ */
88
+ readonly id: import("@angular/core").InputSignal<string | undefined>;
84
89
  /**
85
90
  * Values that are not translated, referenced as `$name` in the content. The
86
91
  * text is translated once as a template and cached, whatever the values are.
@@ -108,6 +113,11 @@ export declare class Translate {
108
113
  "required": false;
109
114
  "isSignal": true;
110
115
  };
116
+ "id": {
117
+ "alias": "id";
118
+ "required": false;
119
+ "isSignal": true;
120
+ };
111
121
  "v": {
112
122
  "alias": "v";
113
123
  "required": false;
@@ -1 +1 @@
1
- {"version":3,"file":"magic-translate-angular.d.ts","names":[],"sources":["../../src/lib/magic-translate-config.ts","../../src/lib/provide-magic-translate.ts","../../src/lib/variables.ts","../../src/lib/magic-translate.service.ts","../../src/lib/translate.component.ts","../../src/lib/translate.pipe.ts"],"mappings":";;;;qBAGa,wBAAsB,eAAA;;;;;wBCMnB,sBACd,QAAQ,uBACP;;;;KCLS,YAAY;;;;;;;;;;iBAgBR,UAAU,WAAW;;EAWnB,QAAA;;;UAiBD;EACf;EACA;EAEA;;iBAGc,gBAAgB;iBAQhB,WAAW,cAAc,WAAW,YAAY;;;;;iBAShD,iBAAiB,cAAc;;;;;iBAmB/B,eAAe,cAAc,WAAW,YAAY;;;;;iBAcpD,YAAY,SAAS,SAAS;;;;;YCtFlC,eAAe;iBAEV,wBAAwB,KAAK;;;;;EAK5C,IAAI;;qBAIO;mBACM;mBACA;WAER;WACA;;;;WAKA,kCAAQ;WAIR,oCAAU,OAAA,WAAA;;EAwBnB,YAAY,UAAU;EAItB,UACE,gBACE,MAAM,WAAU,kBACjB;;EAYH,SAAS,cAAc,SAAQ,KAAK;SAzDzB,MAAA,GAAA,qBAAA;;;qBC6DA;WACF,8BAAI;WACJ,mCAAS;;;;;WAKT,2BAAC,YAAA;mBAEO;mBACA;mBACA;mBAEA;mBAGA;qBACE,oCAAU;UACrB;UACA;;UAyDA;SA5EG,MAAA,GAAA,qBAAA;SAAA,MAAA,GAAA,uBAAA;IAAS;MAAA;MAAA;MAAA;;IAAA;MAAA;MAAA;MAAA;;IAAA;MAAA;MAAA;MAAA;;;;qBAqGT,UAAC;;;;;;;;;qBC9KD,yBAAyB;mBACnB;mBACA;mBACA;UAET;UACA;EAER,UAAU,gBAAgB,MAAM,WAAU;SAR/B,MAAA,GAAA,qBAAA;SAAA,OAAA,GAAA,kBAAA"}
1
+ {"version":3,"file":"magic-translate-angular.d.ts","names":[],"sources":["../../src/lib/magic-translate-config.ts","../../src/lib/provide-magic-translate.ts","../../src/lib/variables.ts","../../src/lib/magic-translate.service.ts","../../src/lib/translate.component.ts","../../src/lib/translate.pipe.ts"],"mappings":";;;;qBAGa,wBAAsB,eAAA;;;;;wBCMnB,sBACd,QAAQ,uBACP;;;;KCLS,YAAY;;;;;;;;;;iBAgBR,UAAU,WAAW;;EAWnB,QAAA;;;UAiBD;EACf;EACA;EAEA;;iBAGc,gBAAgB;iBAQhB,WAAW,cAAc,WAAW,YAAY;;;;;iBAShD,iBAAiB,cAAc;;;;;iBAmB/B,eAAe,cAAc,WAAW,YAAY;;;;;iBAcpD,YAAY,SAAS,SAAS;;;;;YCtFlC,eAAe;iBAEV,wBAAwB,KAAK;;;;;EAK5C,IAAI;;qBAIO;mBACM;mBACA;WAER;WACA;;;;WAKA,kCAAQ;WAIR,oCAAU,OAAA,WAAA;;EA0BnB,YAAY,UAAU;EAItB,UACE,gBACE,MAAM,WAAU,kBACjB;;EAYH,SAAS,cAAc,SAAQ,KAAK;SA3DzB,MAAA,GAAA,qBAAA;;;qBC8DA;WACF,8BAAI;WACJ,mCAAS;;;;;WAKT,4BAAE;;;;;WAKF,2BAAC,YAAA;mBAEO;mBACA;mBACA;mBAEA;mBAGA;qBACE,oCAAU;UACrB;UACA;;UA0DA;SAlFG,MAAA,GAAA,qBAAA;SAAA,MAAA,GAAA,uBAAA;IAAS;MAAA;MAAA;MAAA;;IAAA;MAAA;MAAA;MAAA;;IAAA;MAAA;MAAA;MAAA;;IAAA;MAAA;MAAA;MAAA;;;;qBA2GT,UAAC;;;;;;;;;qBCrLD,yBAAyB;mBACnB;mBACA;mBACA;UAET;UACA;EAER,UAAU,gBAAgB,MAAM,WAAU;SAR/B,MAAA,GAAA,qBAAA;SAAA,OAAA,GAAA,kBAAA"}