@magic-translate/angular 0.0.0-stage → 1.0.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 +8 -0
- package/LICENSE +21 -0
- package/README.md +170 -2
- package/fesm2022/magic-translate-angular.mjs +313 -0
- package/fesm2022/magic-translate-angular.mjs.map +1 -0
- package/package.json +41 -3
- package/types/magic-translate-angular.d.ts +77 -0
- package/types/magic-translate-angular.d.ts.map +1 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 - PRESENT i42 GmbH
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,171 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @magic-translate/angular
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@magic-translate/angular)
|
|
4
|
+
[](https://www.npmjs.com/package/@magic-translate/angular)
|
|
5
|
+
|
|
6
|
+
Angular client for [Magic Translate](https://magictranslate.io). Write your
|
|
7
|
+
templates in one language and Magic Translate translates them on the fly.
|
|
8
|
+
|
|
9
|
+
Requires Angular 20 or newer. Works with and without zone.js.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install --save @magic-translate/angular
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or with yarn:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
yarn add @magic-translate/angular
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
Add `provideMagicTranslate` to your application config. You can get an API key
|
|
26
|
+
for free at [magictranslate.io](https://magictranslate.io).
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// app.config.ts
|
|
30
|
+
import { ApplicationConfig } from '@angular/core';
|
|
31
|
+
import { provideMagicTranslate } from '@magic-translate/angular';
|
|
32
|
+
|
|
33
|
+
export const appConfig: ApplicationConfig = {
|
|
34
|
+
providers: [
|
|
35
|
+
provideMagicTranslate({
|
|
36
|
+
apiKey: 'YOUR_API_KEY',
|
|
37
|
+
language: 'de',
|
|
38
|
+
}),
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
### `<t>` component
|
|
46
|
+
|
|
47
|
+
Wrap any text, including plain HTML, in `<t>`. The original content is shown
|
|
48
|
+
until its translation has loaded.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { Component, signal } from '@angular/core';
|
|
52
|
+
import { T } from '@magic-translate/angular';
|
|
53
|
+
|
|
54
|
+
@Component({
|
|
55
|
+
selector: 'app-welcome',
|
|
56
|
+
imports: [T],
|
|
57
|
+
template: `
|
|
58
|
+
<h1><t>Welcome to our shop</t></h1>
|
|
59
|
+
<p>
|
|
60
|
+
<t>Click <a href="/sale">here</a> to see <b>today's</b> deals.</t>
|
|
61
|
+
</p>
|
|
62
|
+
<p>
|
|
63
|
+
<t>Hello {{ name() }}</t>
|
|
64
|
+
</p>
|
|
65
|
+
`,
|
|
66
|
+
})
|
|
67
|
+
export class Welcome {
|
|
68
|
+
name = signal('Anna');
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The content is re-translated whenever it changes, for example when `name`
|
|
73
|
+
changes in the example above.
|
|
74
|
+
|
|
75
|
+
All translations requested at the same time are sent to the API in a single
|
|
76
|
+
request, and translations are cached, so you can use as many `<t>` components
|
|
77
|
+
as you like.
|
|
78
|
+
|
|
79
|
+
`<mt-translate>` works as an alternative selector, and `Translate` is the same
|
|
80
|
+
component as `T`.
|
|
81
|
+
|
|
82
|
+
Only text and plain HTML elements are allowed inside `<t>`. Other components
|
|
83
|
+
are not, because they cannot survive the translation. The translated markup
|
|
84
|
+
goes through Angular's HTML sanitizer.
|
|
85
|
+
|
|
86
|
+
### `t` pipe
|
|
87
|
+
|
|
88
|
+
Use the pipe for plain strings, such as attributes, or anywhere a component
|
|
89
|
+
does not fit:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { TranslatePipe } from '@magic-translate/angular';
|
|
93
|
+
|
|
94
|
+
@Component({
|
|
95
|
+
imports: [TranslatePipe],
|
|
96
|
+
template: `<input [placeholder]="'Search products' | t" />`,
|
|
97
|
+
})
|
|
98
|
+
export class Search {}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The pipe returns the original text until the translation has loaded.
|
|
102
|
+
|
|
103
|
+
### Options per translation
|
|
104
|
+
|
|
105
|
+
Both the component and the pipe can override the target language and the
|
|
106
|
+
formality:
|
|
107
|
+
|
|
108
|
+
```html
|
|
109
|
+
<t lang="fr" formality="formal">How are you?</t>
|
|
110
|
+
|
|
111
|
+
<input [placeholder]="'Your name' | t: { lang: 'fr', formality: 'formal' }" />
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Switching languages
|
|
115
|
+
|
|
116
|
+
Inject the `MagicTranslate` service to read or change the current language.
|
|
117
|
+
Every `<t>` component and `t` pipe updates automatically.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { Component, inject } from '@angular/core';
|
|
121
|
+
import { MagicTranslate } from '@magic-translate/angular';
|
|
122
|
+
|
|
123
|
+
@Component({
|
|
124
|
+
selector: 'app-language-switcher',
|
|
125
|
+
template: `
|
|
126
|
+
<select
|
|
127
|
+
[value]="magicTranslate.language()"
|
|
128
|
+
(change)="magicTranslate.setLanguage($any($event.target).value)"
|
|
129
|
+
>
|
|
130
|
+
<option value="en">English</option>
|
|
131
|
+
<option value="de">Deutsch</option>
|
|
132
|
+
<option value="fr">Français</option>
|
|
133
|
+
</select>
|
|
134
|
+
`,
|
|
135
|
+
})
|
|
136
|
+
export class LanguageSwitcher {
|
|
137
|
+
protected readonly magicTranslate = inject(MagicTranslate);
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`language` is a signal, so you can also use it in `computed` and `effect`.
|
|
142
|
+
|
|
143
|
+
### Translating in code
|
|
144
|
+
|
|
145
|
+
To translate a string in TypeScript, call `translate` on the service:
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
const magicTranslate = inject(MagicTranslate);
|
|
149
|
+
const message = await magicTranslate.translate('Your order has been placed');
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Configuration
|
|
153
|
+
|
|
154
|
+
`provideMagicTranslate` accepts:
|
|
155
|
+
|
|
156
|
+
| Option | Description |
|
|
157
|
+
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
158
|
+
| `apiKey` | Required. Your Magic Translate API key. |
|
|
159
|
+
| `language` | Required. The language content is translated to, e.g. `'de'`. |
|
|
160
|
+
| `sourceLanguage` | The language your templates are written in. Detected automatically by default; only set it if automatic detection gives wrong results. |
|
|
161
|
+
| `formality` | `'formal'` or `'informal'`. Not supported for all languages. Can be overridden per translation. |
|
|
162
|
+
| `debug` | Logs requests to the console. |
|
|
163
|
+
|
|
164
|
+
## Server-side rendering
|
|
165
|
+
|
|
166
|
+
Translations are only loaded in the browser. With SSR the server renders the
|
|
167
|
+
original content, and it is translated after hydration.
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT © [i42 GmbH](https://i42.ch)
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { DataLoader, cacheKeyFn, defaultLoaderFactory, libraryName, libraryWebsite } from "@magic-translate/core";
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, Injectable, InjectionToken, PLATFORM_ID, Pipe, SecurityContext, ViewEncapsulation, afterNextRender, computed, effect, inject, input, makeEnvironmentProviders, signal, viewChild } from "@angular/core";
|
|
4
|
+
import { DomSanitizer } from "@angular/platform-browser";
|
|
5
|
+
import { isPlatformServer } from "@angular/common";
|
|
6
|
+
export * from "@magic-translate/core";
|
|
7
|
+
const MAGIC_TRANSLATE_CONFIG = new InjectionToken("MAGIC_TRANSLATE_CONFIG");
|
|
8
|
+
var MagicTranslate = class MagicTranslate {
|
|
9
|
+
config = inject(MAGIC_TRANSLATE_CONFIG);
|
|
10
|
+
languageOverride = signal(null, ...ngDevMode ? [{ debugName: "languageOverride" }] : /* istanbul ignore next */ []);
|
|
11
|
+
apiKey = this.config.apiKey;
|
|
12
|
+
sourceLanguage = this.config.sourceLanguage;
|
|
13
|
+
language = computed(() => this.languageOverride() ?? this.config.language, ...ngDevMode ? [{ debugName: "language" }] : /* istanbul ignore next */ []);
|
|
14
|
+
dataLoader = computed(() => {
|
|
15
|
+
const { debug, apiKey, sourceLanguage, _apiUrl, formality } = this.config;
|
|
16
|
+
const loaderFactory = this.config._loaderFactory ?? defaultLoaderFactory;
|
|
17
|
+
const language = this.language();
|
|
18
|
+
return new DataLoader(loaderFactory({
|
|
19
|
+
debug: !!debug,
|
|
20
|
+
apiKey,
|
|
21
|
+
lang: language,
|
|
22
|
+
sourceLang: sourceLanguage,
|
|
23
|
+
apiUrl: _apiUrl,
|
|
24
|
+
formality
|
|
25
|
+
}), { cacheKeyFn: cacheKeyFn(apiKey, sourceLanguage, language) });
|
|
26
|
+
}, ...ngDevMode ? [{ debugName: "dataLoader" }] : /* istanbul ignore next */ []);
|
|
27
|
+
constructor() {
|
|
28
|
+
if (!this.config.apiKey) throw new Error(`Missing API key. Please get one at ${libraryWebsite}`);
|
|
29
|
+
}
|
|
30
|
+
setLanguage(language) {
|
|
31
|
+
this.languageOverride.set(language);
|
|
32
|
+
}
|
|
33
|
+
translate(text, params = {}) {
|
|
34
|
+
return this.dataLoader().load({
|
|
35
|
+
text,
|
|
36
|
+
...params
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
cacheKey(text, params = {}) {
|
|
40
|
+
return cacheKeyFn(this.apiKey, this.sourceLanguage, this.language())({
|
|
41
|
+
text,
|
|
42
|
+
...params
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
46
|
+
minVersion: "12.0.0",
|
|
47
|
+
version: "22.2.3",
|
|
48
|
+
ngImport: i0,
|
|
49
|
+
type: MagicTranslate,
|
|
50
|
+
deps: [],
|
|
51
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
52
|
+
});
|
|
53
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
54
|
+
minVersion: "12.0.0",
|
|
55
|
+
version: "22.2.3",
|
|
56
|
+
ngImport: i0,
|
|
57
|
+
type: MagicTranslate
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
61
|
+
minVersion: "12.0.0",
|
|
62
|
+
version: "22.2.3",
|
|
63
|
+
ngImport: i0,
|
|
64
|
+
type: MagicTranslate,
|
|
65
|
+
decorators: [{ type: Injectable }],
|
|
66
|
+
ctorParameters: () => []
|
|
67
|
+
});
|
|
68
|
+
function provideMagicTranslate(config) {
|
|
69
|
+
return makeEnvironmentProviders([{
|
|
70
|
+
provide: MAGIC_TRANSLATE_CONFIG,
|
|
71
|
+
useValue: config
|
|
72
|
+
}, MagicTranslate]);
|
|
73
|
+
}
|
|
74
|
+
function readSource(element) {
|
|
75
|
+
const clone = element.cloneNode(true);
|
|
76
|
+
const comments = [];
|
|
77
|
+
let scopeAttribute;
|
|
78
|
+
const walker = document.createTreeWalker(clone, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT);
|
|
79
|
+
for (let node = walker.nextNode(); node; node = walker.nextNode()) {
|
|
80
|
+
if (node.nodeType === Node.COMMENT_NODE) {
|
|
81
|
+
comments.push(node);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const el = node;
|
|
85
|
+
if (el.localName.includes("-")) throw new Error(`Components are not allowed inside \`<t>...</t>\` components. The component found inside the t component is <${el.localName}>.`);
|
|
86
|
+
for (const { name } of Array.from(el.attributes)) {
|
|
87
|
+
if (name.startsWith("_ngcontent-")) scopeAttribute = name;
|
|
88
|
+
if (name.startsWith("_ng") || name.startsWith("ng-reflect-")) el.removeAttribute(name);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
comments.forEach((comment) => comment.parentNode?.removeChild(comment));
|
|
92
|
+
const [, leadingWhitespace, html, trailingWhitespace] = /^(\s*)([\s\S]*?)(\s*)$/.exec(clone.innerHTML);
|
|
93
|
+
return {
|
|
94
|
+
html,
|
|
95
|
+
leadingWhitespace,
|
|
96
|
+
trailingWhitespace,
|
|
97
|
+
scopeAttribute
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
var Translate = class Translate {
|
|
101
|
+
lang = input(void 0, ...ngDevMode ? [{ debugName: "lang" }] : /* istanbul ignore next */ []);
|
|
102
|
+
formality = input(void 0, ...ngDevMode ? [{ debugName: "formality" }] : /* istanbul ignore next */ []);
|
|
103
|
+
magicTranslate = inject(MagicTranslate);
|
|
104
|
+
sanitizer = inject(DomSanitizer);
|
|
105
|
+
sourceRef = viewChild.required("source", ...ngDevMode ? [{ debugName: "sourceRef" }] : /* istanbul ignore next */ []);
|
|
106
|
+
targetRef = viewChild.required("target", ...ngDevMode ? [{ debugName: "targetRef" }] : /* istanbul ignore next */ []);
|
|
107
|
+
source = signal(null, ...ngDevMode ? [{ debugName: "source" }] : /* istanbul ignore next */ []);
|
|
108
|
+
translated = signal(false, ...ngDevMode ? [{ debugName: "translated" }] : /* istanbul ignore next */ []);
|
|
109
|
+
lastRequestId = 0;
|
|
110
|
+
constructor() {
|
|
111
|
+
const destroyRef = inject(DestroyRef);
|
|
112
|
+
afterNextRender(() => {
|
|
113
|
+
const element = this.sourceRef().nativeElement;
|
|
114
|
+
const read = () => this.source.set(readSource(element));
|
|
115
|
+
read();
|
|
116
|
+
const observer = new MutationObserver(read);
|
|
117
|
+
observer.observe(element, {
|
|
118
|
+
subtree: true,
|
|
119
|
+
childList: true,
|
|
120
|
+
characterData: true,
|
|
121
|
+
attributes: true
|
|
122
|
+
});
|
|
123
|
+
destroyRef.onDestroy(() => observer.disconnect());
|
|
124
|
+
});
|
|
125
|
+
effect(() => {
|
|
126
|
+
const source = this.source();
|
|
127
|
+
const lang = this.lang();
|
|
128
|
+
const formality = this.formality();
|
|
129
|
+
this.magicTranslate.language();
|
|
130
|
+
if (!source?.html) {
|
|
131
|
+
this.translated.set(false);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const requestId = ++this.lastRequestId;
|
|
135
|
+
this.magicTranslate.translate(source.html, {
|
|
136
|
+
lang,
|
|
137
|
+
formality
|
|
138
|
+
}).then((translation) => {
|
|
139
|
+
if (requestId === this.lastRequestId) this.render(source, translation);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
render(source, translation) {
|
|
144
|
+
const target = this.targetRef().nativeElement;
|
|
145
|
+
const html = this.sanitizer.sanitize(SecurityContext.HTML, translation);
|
|
146
|
+
if (html === null) {
|
|
147
|
+
console.warn(`[${libraryName}]: Could not render translation.`);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
target.innerHTML = `${source.leadingWhitespace}${html}${source.trailingWhitespace}`;
|
|
151
|
+
if (source.scopeAttribute) target.querySelectorAll("*").forEach((el) => el.setAttribute(source.scopeAttribute, ""));
|
|
152
|
+
this.translated.set(true);
|
|
153
|
+
}
|
|
154
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
155
|
+
minVersion: "12.0.0",
|
|
156
|
+
version: "22.2.3",
|
|
157
|
+
ngImport: i0,
|
|
158
|
+
type: Translate,
|
|
159
|
+
deps: [],
|
|
160
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
161
|
+
});
|
|
162
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
163
|
+
minVersion: "17.2.0",
|
|
164
|
+
version: "22.2.3",
|
|
165
|
+
type: Translate,
|
|
166
|
+
isStandalone: true,
|
|
167
|
+
selector: "t, mt-translate",
|
|
168
|
+
inputs: {
|
|
169
|
+
lang: {
|
|
170
|
+
classPropertyName: "lang",
|
|
171
|
+
publicName: "lang",
|
|
172
|
+
isSignal: true,
|
|
173
|
+
isRequired: false,
|
|
174
|
+
transformFunction: null
|
|
175
|
+
},
|
|
176
|
+
formality: {
|
|
177
|
+
classPropertyName: "formality",
|
|
178
|
+
publicName: "formality",
|
|
179
|
+
isSignal: true,
|
|
180
|
+
isRequired: false,
|
|
181
|
+
transformFunction: null
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
host: { styleAttribute: "display: contents" },
|
|
185
|
+
viewQueries: [{
|
|
186
|
+
propertyName: "sourceRef",
|
|
187
|
+
first: true,
|
|
188
|
+
predicate: ["source"],
|
|
189
|
+
descendants: true,
|
|
190
|
+
isSignal: true
|
|
191
|
+
}, {
|
|
192
|
+
propertyName: "targetRef",
|
|
193
|
+
first: true,
|
|
194
|
+
predicate: ["target"],
|
|
195
|
+
descendants: true,
|
|
196
|
+
isSignal: true
|
|
197
|
+
}],
|
|
198
|
+
ngImport: i0,
|
|
199
|
+
template: `<span #source [style.display]="translated() ? 'none' : 'contents'"
|
|
200
|
+
><ng-content /></span
|
|
201
|
+
><span
|
|
202
|
+
#target
|
|
203
|
+
[style.display]="translated() ? 'contents' : 'none'"
|
|
204
|
+
></span>`,
|
|
205
|
+
isInline: true,
|
|
206
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush,
|
|
207
|
+
encapsulation: i0.ViewEncapsulation.None
|
|
208
|
+
});
|
|
209
|
+
};
|
|
210
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
211
|
+
minVersion: "12.0.0",
|
|
212
|
+
version: "22.2.3",
|
|
213
|
+
ngImport: i0,
|
|
214
|
+
type: Translate,
|
|
215
|
+
decorators: [{
|
|
216
|
+
type: Component,
|
|
217
|
+
args: [{
|
|
218
|
+
selector: "t, mt-translate",
|
|
219
|
+
template: `<span #source [style.display]="translated() ? 'none' : 'contents'"
|
|
220
|
+
><ng-content /></span
|
|
221
|
+
><span
|
|
222
|
+
#target
|
|
223
|
+
[style.display]="translated() ? 'contents' : 'none'"
|
|
224
|
+
></span>`,
|
|
225
|
+
host: { style: "display: contents" },
|
|
226
|
+
encapsulation: ViewEncapsulation.None,
|
|
227
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
228
|
+
}]
|
|
229
|
+
}],
|
|
230
|
+
ctorParameters: () => [],
|
|
231
|
+
propDecorators: {
|
|
232
|
+
lang: [{
|
|
233
|
+
type: i0.Input,
|
|
234
|
+
args: [{
|
|
235
|
+
isSignal: true,
|
|
236
|
+
alias: "lang",
|
|
237
|
+
required: false
|
|
238
|
+
}]
|
|
239
|
+
}],
|
|
240
|
+
formality: [{
|
|
241
|
+
type: i0.Input,
|
|
242
|
+
args: [{
|
|
243
|
+
isSignal: true,
|
|
244
|
+
alias: "formality",
|
|
245
|
+
required: false
|
|
246
|
+
}]
|
|
247
|
+
}],
|
|
248
|
+
sourceRef: [{
|
|
249
|
+
type: i0.ViewChild,
|
|
250
|
+
args: ["source", { isSignal: true }]
|
|
251
|
+
}],
|
|
252
|
+
targetRef: [{
|
|
253
|
+
type: i0.ViewChild,
|
|
254
|
+
args: ["target", { isSignal: true }]
|
|
255
|
+
}]
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
const T = Translate;
|
|
259
|
+
var TranslatePipe = class TranslatePipe {
|
|
260
|
+
magicTranslate = inject(MagicTranslate);
|
|
261
|
+
changeDetectorRef = inject(ChangeDetectorRef);
|
|
262
|
+
isServer = isPlatformServer(inject(PLATFORM_ID));
|
|
263
|
+
key;
|
|
264
|
+
translation;
|
|
265
|
+
transform(text, params = {}) {
|
|
266
|
+
if (!text || this.isServer) return text;
|
|
267
|
+
const key = this.magicTranslate.cacheKey(text, params);
|
|
268
|
+
if (key !== this.key) {
|
|
269
|
+
this.key = key;
|
|
270
|
+
this.translation = void 0;
|
|
271
|
+
this.magicTranslate.translate(text, params).then((translation) => {
|
|
272
|
+
if (this.key === key) {
|
|
273
|
+
this.translation = translation;
|
|
274
|
+
this.changeDetectorRef.markForCheck();
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
return this.translation ?? text;
|
|
279
|
+
}
|
|
280
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
281
|
+
minVersion: "12.0.0",
|
|
282
|
+
version: "22.2.3",
|
|
283
|
+
ngImport: i0,
|
|
284
|
+
type: TranslatePipe,
|
|
285
|
+
deps: [],
|
|
286
|
+
target: i0.ɵɵFactoryTarget.Pipe
|
|
287
|
+
});
|
|
288
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({
|
|
289
|
+
minVersion: "14.0.0",
|
|
290
|
+
version: "22.2.3",
|
|
291
|
+
ngImport: i0,
|
|
292
|
+
type: TranslatePipe,
|
|
293
|
+
isStandalone: true,
|
|
294
|
+
name: "t",
|
|
295
|
+
pure: false
|
|
296
|
+
});
|
|
297
|
+
};
|
|
298
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
299
|
+
minVersion: "12.0.0",
|
|
300
|
+
version: "22.2.3",
|
|
301
|
+
ngImport: i0,
|
|
302
|
+
type: TranslatePipe,
|
|
303
|
+
decorators: [{
|
|
304
|
+
type: Pipe,
|
|
305
|
+
args: [{
|
|
306
|
+
name: "t",
|
|
307
|
+
pure: false
|
|
308
|
+
}]
|
|
309
|
+
}]
|
|
310
|
+
});
|
|
311
|
+
export { MAGIC_TRANSLATE_CONFIG, MagicTranslate, T, Translate, TranslatePipe, provideMagicTranslate };
|
|
312
|
+
|
|
313
|
+
//# sourceMappingURL=magic-translate-angular.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"magic-translate-angular.mjs","names":[],"sources":["../../src/lib/magic-translate-config.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 { 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';\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 type TranslateParams = Omit<DataLoaderLoadParams, 'text'>;\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(text: string, params: TranslateParams = {}): Promise<string> {\n return this.dataLoader().load({ text, ...params });\n }\n\n /** @ignore */\n cacheKey(text: string, params: TranslateParams = {}): 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 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';\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 template: `<span #source [style.display]=\"translated() ? '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 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\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 // 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 // make sure that we only ever use the response of the most recent request.\n const requestId = ++this.lastRequestId;\n this.magicTranslate\n .translate(source.html, { lang, formality })\n .then((translation) => {\n if (requestId === this.lastRequestId) {\n this.render(source, translation);\n }\n });\n });\n }\n\n private render(source: Source, translation: string) {\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 (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';\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@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, params: TranslateParams = {}): string {\n if (!text || this.isServer) {\n return text;\n }\n\n const key = this.magicTranslate.cacheKey(text, params);\n if (key !== this.key) {\n this.key = key;\n this.translation = undefined;\n this.magicTranslate.translate(text, params).then((translation) => {\n if (this.key === key) {\n this.translation = translation;\n this.changeDetectorRef.markForCheck();\n }\n });\n }\n\n return this.translation ?? text;\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@magic-translate/angular",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"angular",
|
|
6
|
+
"magic-translate",
|
|
7
|
+
"i18n",
|
|
8
|
+
"translations",
|
|
9
|
+
"multilanguage"
|
|
10
|
+
],
|
|
11
|
+
"description": "Angular client for Magic Translate (https://magictranslate.io)",
|
|
12
|
+
"author": "i42 GmbH <info@i42.ch>",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/magic-translate/magic-translate-angular.git"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://magictranslate.io",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=22.22.1"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"@angular/common": ">=20.0.0",
|
|
24
|
+
"@angular/core": ">=20.0.0",
|
|
25
|
+
"@angular/platform-browser": ">=20.0.0"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@magic-translate/core": "^1.4.0",
|
|
29
|
+
"tslib": "^2.8.1"
|
|
30
|
+
},
|
|
31
|
+
"module": "fesm2022/magic-translate-angular.mjs",
|
|
32
|
+
"typings": "types/magic-translate-angular.d.ts",
|
|
33
|
+
"exports": {
|
|
34
|
+
"./package.json": {
|
|
35
|
+
"default": "./package.json"
|
|
36
|
+
},
|
|
37
|
+
".": {
|
|
38
|
+
"types": "./types/magic-translate-angular.d.ts",
|
|
39
|
+
"default": "./fesm2022/magic-translate-angular.mjs"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"sideEffects": false,
|
|
43
|
+
"type": "module"
|
|
6
44
|
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { DataLoader, DataLoaderLoadParams, Language, MagicTranslateConfig } from "@magic-translate/core";
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
import { EnvironmentProviders, InjectionToken, PipeTransform } from "@angular/core";
|
|
4
|
+
export * from "@magic-translate/core";
|
|
5
|
+
export declare const MAGIC_TRANSLATE_CONFIG: InjectionToken<MagicTranslateConfig>;
|
|
6
|
+
/**
|
|
7
|
+
* Sets up Magic Translate for the application. Add it to the `providers` of
|
|
8
|
+
* your application config.
|
|
9
|
+
*/
|
|
10
|
+
export declare function provideMagicTranslate(config: MagicTranslateConfig): EnvironmentProviders;
|
|
11
|
+
/**
|
|
12
|
+
* Type alias to make the language enum more flexible to also allow passing language strings
|
|
13
|
+
* instead of just the enum.
|
|
14
|
+
*/
|
|
15
|
+
export type Languages = `${Language}`;
|
|
16
|
+
export type TranslateParams = Omit<DataLoaderLoadParams, 'text'>;
|
|
17
|
+
export declare class MagicTranslate {
|
|
18
|
+
private readonly config;
|
|
19
|
+
private readonly languageOverride;
|
|
20
|
+
readonly apiKey: string;
|
|
21
|
+
readonly sourceLanguage: "af" | "sq" | "am" | "ar" | "hy" | "az" | "bn" | "bs" | "bg" | "ca" | "zh" | "zh-TW" | "hr" | "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" | "it" | "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" | "th" | "tr" | "uk" | "ur" | "uz" | "vi" | "cy" | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* The language content is currently translated to.
|
|
24
|
+
*/
|
|
25
|
+
readonly language: import("@angular/core").Signal<"af" | "sq" | "am" | "ar" | "hy" | "az" | "bn" | "bs" | "bg" | "ca" | "zh" | "zh-TW" | "hr" | "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" | "it" | "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" | "th" | "tr" | "uk" | "ur" | "uz" | "vi" | "cy">;
|
|
26
|
+
readonly dataLoader: import("@angular/core").Signal<DataLoader<DataLoaderLoadParams, string, string>>;
|
|
27
|
+
constructor();
|
|
28
|
+
setLanguage(language: Languages): void;
|
|
29
|
+
translate(text: string, params?: TranslateParams): Promise<string>;
|
|
30
|
+
/** @ignore */
|
|
31
|
+
cacheKey(text: string, params?: TranslateParams): string;
|
|
32
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<MagicTranslate, never>;
|
|
33
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<any>;
|
|
34
|
+
}
|
|
35
|
+
export declare class Translate {
|
|
36
|
+
readonly lang: import("@angular/core").InputSignal<"af" | "sq" | "am" | "ar" | "hy" | "az" | "bn" | "bs" | "bg" | "ca" | "zh" | "zh-TW" | "hr" | "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" | "it" | "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" | "th" | "tr" | "uk" | "ur" | "uz" | "vi" | "cy" | undefined>;
|
|
37
|
+
readonly formality: import("@angular/core").InputSignal<"formal" | "informal" | undefined>;
|
|
38
|
+
private readonly magicTranslate;
|
|
39
|
+
private readonly sanitizer;
|
|
40
|
+
private readonly sourceRef;
|
|
41
|
+
private readonly targetRef;
|
|
42
|
+
private readonly source;
|
|
43
|
+
protected readonly translated: import("@angular/core").WritableSignal<boolean>;
|
|
44
|
+
private lastRequestId;
|
|
45
|
+
constructor();
|
|
46
|
+
private render;
|
|
47
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<Translate, never>;
|
|
48
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<Translate, "t, mt-translate", never, {
|
|
49
|
+
"lang": {
|
|
50
|
+
"alias": "lang";
|
|
51
|
+
"required": false;
|
|
52
|
+
"isSignal": true;
|
|
53
|
+
};
|
|
54
|
+
"formality": {
|
|
55
|
+
"alias": "formality";
|
|
56
|
+
"required": false;
|
|
57
|
+
"isSignal": true;
|
|
58
|
+
};
|
|
59
|
+
}, {}, never, ["*"], true, never>;
|
|
60
|
+
}
|
|
61
|
+
export declare const T: typeof Translate;
|
|
62
|
+
/**
|
|
63
|
+
* Translates a plain string, e.g. for attributes:
|
|
64
|
+
* `<input [placeholder]="'Search' | t" />`. Returns the original text until
|
|
65
|
+
* the translation has loaded.
|
|
66
|
+
*/
|
|
67
|
+
export declare class TranslatePipe implements PipeTransform {
|
|
68
|
+
private readonly magicTranslate;
|
|
69
|
+
private readonly changeDetectorRef;
|
|
70
|
+
private readonly isServer;
|
|
71
|
+
private key?;
|
|
72
|
+
private translation?;
|
|
73
|
+
transform(text: string, params?: TranslateParams): string;
|
|
74
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<TranslatePipe, never>;
|
|
75
|
+
static ɵpipe: i0.ɵɵPipeDeclaration<TranslatePipe, "t", true>;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=magic-translate-angular.d.ts.map
|
|
@@ -0,0 +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/magic-translate.service.ts","../../src/lib/translate.component.ts","../../src/lib/translate.pipe.ts"],"mappings":";;;;qBAGa,wBAAsB,eAAA;;;;;wBCMnB,sBACd,QAAQ,uBACP;;;;;YCIS,eAAe;YAEf,kBAAkB,KAAK;qBAGtB;mBACM;mBACA;WAER;WACA;;;;WAKA,kCAAQ;WAIR,oCAAU,OAAA,WAAA;;EAwBnB,YAAY,UAAU;EAItB,UAAU,cAAc,SAAQ,kBAAuB;;EAKvD,SAAS,cAAc,SAAQ;SA/CpB,MAAA,GAAA,qBAAA;;;qBC8DA;WACF,8BAAI;WACJ,mCAAS;mBAED;mBACA;mBACA;mBAEA;mBAGA;qBACE,oCAAU;UACrB;;UA6CA;SA1DG,MAAA,GAAA,qBAAA;SAAA,MAAA,GAAA,uBAAA;IAAS;MAAA;MAAA;MAAA;;IAAA;MAAA;MAAA;MAAA;;;;qBA4ET,UAAC;;;;;;qBC9ID,yBAAyB;mBACnB;mBACA;mBACA;UAET;UACA;EAER,UAAU,cAAc,SAAQ;SARrB,MAAA,GAAA,qBAAA;SAAA,OAAA,GAAA,kBAAA"}
|