piral-translate 1.4.0-beta.6260 → 1.4.0-beta.6280

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/esm/create.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { PiralPlugin } from 'piral-core';
2
- import { PiletLocaleApi, LocalizationMessages, Localizable } from './types';
2
+ import type { PiletLocaleApi, Localizable, AnyLocalizationMessages } from './types';
3
3
  export interface TranslationFallback {
4
4
  (key: string, language: string): string;
5
5
  }
@@ -14,7 +14,7 @@ export interface LocaleConfig {
14
14
  * Sets the default (global) localization messages.
15
15
  * @default {}
16
16
  */
17
- messages?: LocalizationMessages;
17
+ messages?: AnyLocalizationMessages;
18
18
  /**
19
19
  * Sets the default language to use.
20
20
  */
package/esm/create.js CHANGED
@@ -2,6 +2,7 @@ import * as deepmerge from 'deepmerge';
2
2
  import { createActions } from './actions';
3
3
  import { Localizer } from './localize';
4
4
  import { DefaultPicker } from './default';
5
+ import { flattenTranslations } from './flatten-translations';
5
6
  /**
6
7
  * Sets up a new localizer by using the given config.
7
8
  * @param config The configuration for the new localizer.
@@ -36,16 +37,13 @@ export function createLocaleApi(localizer = setupLocalizer()) {
36
37
  }));
37
38
  return (api) => {
38
39
  let localTranslations = {};
40
+ const setTranslations = (messages) => {
41
+ localTranslations = flattenTranslations(messages);
42
+ };
39
43
  return {
40
44
  addTranslations(messages, isOverriding = true) {
41
- const messagesToMerge = messages;
42
- if (isOverriding) {
43
- messagesToMerge.unshift(localizer.messages);
44
- }
45
- else {
46
- messagesToMerge.push(localizer.messages);
47
- }
48
- this.setTranslations(deepmerge.all(messagesToMerge));
45
+ const current = localizer.messages;
46
+ setTranslations(deepmerge.all(isOverriding ? [current, ...messages] : [...messages, current]));
49
47
  },
50
48
  getCurrentLanguage(cb) {
51
49
  const selected = context.readState((s) => s.language.selected);
@@ -59,9 +57,7 @@ export function createLocaleApi(localizer = setupLocalizer()) {
59
57
  }
60
58
  return selected;
61
59
  },
62
- setTranslations(messages) {
63
- localTranslations = messages;
64
- },
60
+ setTranslations,
65
61
  getTranslations() {
66
62
  return localTranslations;
67
63
  },
package/esm/create.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { LocalizationMessages, NestedLocalizationMessages } from './types';
2
+ export declare function flattenTranslations(messages: LocalizationMessages | NestedLocalizationMessages): LocalizationMessages;
@@ -0,0 +1,23 @@
1
+ function flat(source) {
2
+ const target = {};
3
+ flatten(source, target);
4
+ return target;
5
+ }
6
+ function flatten(source, target, prop = '') {
7
+ if (typeof source === 'string') {
8
+ target[prop] = source;
9
+ return;
10
+ }
11
+ if (typeof source === 'object' && source !== null) {
12
+ Object.keys(source).forEach((key) => {
13
+ flatten(source[key], target, prop ? `${prop}.${key}` : key);
14
+ });
15
+ return;
16
+ }
17
+ }
18
+ export function flattenTranslations(messages) {
19
+ return Object.fromEntries(Object.entries(messages).map(([language, translations]) => {
20
+ return [language, flat(translations)];
21
+ }));
22
+ }
23
+ //# sourceMappingURL=flatten-translations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flatten-translations.js","sourceRoot":"","sources":["../src/flatten-translations.ts"],"names":[],"mappings":"AAEA,SAAS,IAAI,CAAC,MAA+B;IAC3C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,OAAO,CAAC,MAAW,EAAE,MAA8B,EAAE,IAAI,GAAG,EAAE;IACrE,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QAC9B,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;QAEtB,OAAO;KACR;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE;QACjD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YAClC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;QAEH,OAAO;KACR;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAA2D;IAC7F,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,EAAE;QACxD,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
package/esm/localize.d.ts CHANGED
@@ -1,14 +1,14 @@
1
- import { LocalizationMessages, Localizable } from './types';
1
+ import { LocalizationMessages, Localizable, NestedLocalizationMessages } from './types';
2
2
  declare function defaultFallback(key: string, language: string): string;
3
3
  export declare class Localizer implements Localizable {
4
- messages: LocalizationMessages;
5
4
  language: string;
6
5
  languages: Array<string>;
7
6
  private fallback;
7
+ messages: LocalizationMessages;
8
8
  /**
9
9
  * Creates a new instance of a localizer.
10
10
  */
11
- constructor(messages: LocalizationMessages, language: string, languages: Array<string>, fallback?: typeof defaultFallback);
11
+ constructor(messages: LocalizationMessages | NestedLocalizationMessages, language: string, languages: Array<string>, fallback?: typeof defaultFallback);
12
12
  /**
13
13
  * Localizes the given key via the global translations.
14
14
  * @param key The key of the translation snippet.
package/esm/localize.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { flattenTranslations } from './flatten-translations';
1
2
  function defaultFallback(key, language) {
2
3
  if (process.env.NODE_ENV === 'production') {
3
4
  return language ? '...' : '';
@@ -22,10 +23,10 @@ export class Localizer {
22
23
  * Creates a new instance of a localizer.
23
24
  */
24
25
  constructor(messages, language, languages, fallback = defaultFallback) {
25
- this.messages = messages;
26
26
  this.language = language;
27
27
  this.languages = languages;
28
28
  this.fallback = fallback;
29
+ this.messages = flattenTranslations(messages);
29
30
  }
30
31
  /**
31
32
  * Localizes the given key via the global translations.
@@ -1 +1 @@
1
- {"version":3,"file":"localize.js","sourceRoot":"","sources":["../src/localize.ts"],"names":[],"mappings":"AAEA,SAAS,eAAe,CAAC,GAAW,EAAE,QAAgB;IACpD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE;QACzC,OAAO,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9B;SAAM;QACL,IAAI,QAAQ,EAAE;YACZ,OAAO,CAAC,IAAI,CAAC,2BAA2B,GAAG,kBAAkB,QAAQ,IAAI,CAAC,CAAC;YAC3E,OAAO,KAAK,QAAQ,IAAI,GAAG,IAAI,CAAC;SACjC;aAAM;YACL,OAAO,EAAE,CAAC;SACX;KACF;AACH,CAAC;AAED,SAAS,aAAa,CAAmB,OAAe,EAAE,SAAY;IACpE,OAAO,OAAO,CAAC,OAAO,CAAC,6BAA6B,EAAE,CAAC,MAAc,EAAE,EAAU,EAAE,EAAE;QACnF,OAAO,EAAE,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,OAAO,SAAS;IACpB;;OAEG;IACH,YACS,QAA8B,EAC9B,QAAgB,EAChB,SAAwB,EACvB,WAAW,eAAe;QAH3B,aAAQ,GAAR,QAAQ,CAAsB;QAC9B,aAAQ,GAAR,QAAQ,CAAQ;QAChB,cAAS,GAAT,SAAS,CAAe;QACvB,aAAQ,GAAR,QAAQ,CAAkB;IACjC,CAAC;IAEJ;;;;OAIG;IACI,cAAc,CAAmB,GAAW,EAAE,SAAa;QAChE,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;;OAMG;IACI,aAAa,CAAmB,aAAmC,EAAE,GAAW,EAAE,SAAa;QACpG,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAErE,IAAI,OAAO,KAAK,SAAS,EAAE;YACzB,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;SAC1C;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,YAAY,CAAmB,GAAW,EAAE,SAAa;QAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAErE,IAAI,OAAO,KAAK,SAAS,EAAE;YACzB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;SAC1C;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,gBAAgB,CAAmB,QAA8B,EAAE,GAAW,EAAE,SAAa;QACnG,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,MAAM,YAAY,GAAG,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACpD,MAAM,WAAW,GAAG,YAAY,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC;QACtD,OAAO,WAAW,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1F,CAAC;CACF"}
1
+ {"version":3,"file":"localize.js","sourceRoot":"","sources":["../src/localize.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,SAAS,eAAe,CAAC,GAAW,EAAE,QAAgB;IACpD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE;QACzC,OAAO,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9B;SAAM;QACL,IAAI,QAAQ,EAAE;YACZ,OAAO,CAAC,IAAI,CAAC,2BAA2B,GAAG,kBAAkB,QAAQ,IAAI,CAAC,CAAC;YAC3E,OAAO,KAAK,QAAQ,IAAI,GAAG,IAAI,CAAC;SACjC;aAAM;YACL,OAAO,EAAE,CAAC;SACX;KACF;AACH,CAAC;AAED,SAAS,aAAa,CAAmB,OAAe,EAAE,SAAY;IACpE,OAAO,OAAO,CAAC,OAAO,CAAC,6BAA6B,EAAE,CAAC,MAAc,EAAE,EAAU,EAAE,EAAE;QACnF,OAAO,EAAE,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,OAAO,SAAS;IAGpB;;OAEG;IACH,YACE,QAA2D,EACpD,QAAgB,EAChB,SAAwB,EACvB,WAAW,eAAe;QAF3B,aAAQ,GAAR,QAAQ,CAAQ;QAChB,cAAS,GAAT,SAAS,CAAe;QACvB,aAAQ,GAAR,QAAQ,CAAkB;QAElC,IAAI,CAAC,QAAQ,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAChD,CAAC;IAED;;;;OAIG;IACI,cAAc,CAAmB,GAAW,EAAE,SAAa;QAChE,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;;OAMG;IACI,aAAa,CAAmB,aAAmC,EAAE,GAAW,EAAE,SAAa;QACpG,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAErE,IAAI,OAAO,KAAK,SAAS,EAAE;YACzB,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;SAC1C;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,YAAY,CAAmB,GAAW,EAAE,SAAa;QAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAErE,IAAI,OAAO,KAAK,SAAS,EAAE;YACzB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;SAC1C;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,gBAAgB,CAAmB,QAA8B,EAAE,GAAW,EAAE,SAAa;QACnG,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,MAAM,YAAY,GAAG,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACpD,MAAM,WAAW,GAAG,YAAY,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC;QACtD,OAAO,WAAW,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1F,CAAC;CACF"}
package/esm/types.d.ts CHANGED
@@ -91,6 +91,12 @@ export interface Translations {
91
91
  */
92
92
  [tag: string]: string;
93
93
  }
94
+ export interface NestedTranslations {
95
+ /**
96
+ * The available wordings (tag to translation or nested translations).
97
+ */
98
+ [tag: string]: string | NestedTranslations;
99
+ }
94
100
  export interface LanguageLoader {
95
101
  (language: string, current: LanguageData): Promise<LanguageData>;
96
102
  }
@@ -107,6 +113,13 @@ export interface LocalizationMessages {
107
113
  */
108
114
  [lang: string]: Translations;
109
115
  }
116
+ export interface NestedLocalizationMessages {
117
+ /**
118
+ * The available languages (lang to wordings or nested wordings).
119
+ */
120
+ [lang: string]: NestedTranslations;
121
+ }
122
+ export type AnyLocalizationMessages = LocalizationMessages | NestedLocalizationMessages;
110
123
  export interface PiletLocaleApi {
111
124
  /**
112
125
  * Adds a list of translations to the existing translations.
@@ -117,7 +130,7 @@ export interface PiletLocaleApi {
117
130
  * @param messagesList The list of messages that extend the existing translations
118
131
  * @param [isOverriding=true] Indicates whether the new translations overwrite the existing translations
119
132
  */
120
- addTranslations(messagesList: LocalizationMessages[], isOverriding?: boolean): void;
133
+ addTranslations(messagesList: Array<AnyLocalizationMessages>, isOverriding?: boolean): void;
121
134
  /**
122
135
  * Gets the currently selected language directly.
123
136
  */
@@ -139,7 +152,7 @@ export interface PiletLocaleApi {
139
152
  * The translations will be exclusively used for retrieving translations for the pilet.
140
153
  * @param messages The messages to use as translation basis.
141
154
  */
142
- setTranslations(messages: LocalizationMessages): void;
155
+ setTranslations(messages: AnyLocalizationMessages): void;
143
156
  /**
144
157
  * Gets the currently provided translations by the pilet.
145
158
  */
package/lib/create.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { PiralPlugin } from 'piral-core';
2
- import { PiletLocaleApi, LocalizationMessages, Localizable } from './types';
2
+ import type { PiletLocaleApi, Localizable, AnyLocalizationMessages } from './types';
3
3
  export interface TranslationFallback {
4
4
  (key: string, language: string): string;
5
5
  }
@@ -14,7 +14,7 @@ export interface LocaleConfig {
14
14
  * Sets the default (global) localization messages.
15
15
  * @default {}
16
16
  */
17
- messages?: LocalizationMessages;
17
+ messages?: AnyLocalizationMessages;
18
18
  /**
19
19
  * Sets the default language to use.
20
20
  */
package/lib/create.js CHANGED
@@ -5,6 +5,7 @@ const deepmerge = require("deepmerge");
5
5
  const actions_1 = require("./actions");
6
6
  const localize_1 = require("./localize");
7
7
  const default_1 = require("./default");
8
+ const flatten_translations_1 = require("./flatten-translations");
8
9
  /**
9
10
  * Sets up a new localizer by using the given config.
10
11
  * @param config The configuration for the new localizer.
@@ -40,16 +41,13 @@ function createLocaleApi(localizer = setupLocalizer()) {
40
41
  }));
41
42
  return (api) => {
42
43
  let localTranslations = {};
44
+ const setTranslations = (messages) => {
45
+ localTranslations = (0, flatten_translations_1.flattenTranslations)(messages);
46
+ };
43
47
  return {
44
48
  addTranslations(messages, isOverriding = true) {
45
- const messagesToMerge = messages;
46
- if (isOverriding) {
47
- messagesToMerge.unshift(localizer.messages);
48
- }
49
- else {
50
- messagesToMerge.push(localizer.messages);
51
- }
52
- this.setTranslations(deepmerge.all(messagesToMerge));
49
+ const current = localizer.messages;
50
+ setTranslations(deepmerge.all(isOverriding ? [current, ...messages] : [...messages, current]));
53
51
  },
54
52
  getCurrentLanguage(cb) {
55
53
  const selected = context.readState((s) => s.language.selected);
@@ -63,9 +61,7 @@ function createLocaleApi(localizer = setupLocalizer()) {
63
61
  }
64
62
  return selected;
65
63
  },
66
- setTranslations(messages) {
67
- localTranslations = messages;
68
- },
64
+ setTranslations,
69
65
  getTranslations() {
70
66
  return localTranslations;
71
67
  },
package/lib/create.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":";;;AAAA,uCAAuC;AAGvC,uCAA0C;AAC1C,yCAAuC;AACvC,uCAA0C;AAC1C,iEAA6D;AAoC7D;;;GAGG;AACH,SAAgB,cAAc,CAAC,SAAuB,EAAE;IACtD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;IACnC,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACzC,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC;IACpC,MAAM,QAAQ,GAAG,OAAO,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IAC7G,MAAM,QAAQ,GAAG,QAAQ,IAAI,WAAW,CAAC;IACzC,OAAO,IAAI,oBAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;AACnG,CAAC;AARD,wCAQC;AAED;;;GAGG;AACH,SAAgB,eAAe,CAAC,YAAyB,cAAc,EAAE;IACvE,OAAO,CAAC,OAAO,EAAE,EAAE;QACjB,OAAO,CAAC,aAAa,CAAC,IAAA,uBAAa,EAAC,SAAS,CAAC,CAAC,CAAC;QAEhD,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC3B,GAAG,KAAK;YACR,UAAU,EAAE;gBACV,eAAe,EAAE,uBAAa;gBAC9B,GAAG,KAAK,CAAC,UAAU;aACpB;YACD,QAAQ,EAAE;gBACR,OAAO,EAAE,KAAK;gBACd,SAAS,EAAE,SAAS,CAAC,SAAS;gBAC9B,QAAQ,EAAE,SAAS,CAAC,QAAQ;aAC7B;SACF,CAAC,CAAC,CAAC;QAEJ,OAAO,CAAC,GAAG,EAAE,EAAE;YACb,IAAI,iBAAiB,GAAyB,EAAE,CAAC;YAEjD,MAAM,eAAe,GAAG,CAAC,QAAiC,EAAE,EAAE;gBAC5D,iBAAiB,GAAG,IAAA,0CAAmB,EAAC,QAAQ,CAAC,CAAC;YACpD,CAAC,CAAC;YAEF,OAAO;gBACL,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI;oBAC3C,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC;oBACnC,eAAe,CACb,SAAS,CAAC,GAAG,CAA0B,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,EAAE,OAAO,CAAC,CAAC,CACvG,CAAC;gBACJ,CAAC;gBACD,kBAAkB,CAAC,EAAwB;oBACzC,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;oBAE/D,IAAI,EAAE,EAAE;wBACN,EAAE,CAAC,QAAQ,CAAC,CAAC;wBACb,MAAM,OAAO,GAAG,CAAC,EAA4B,EAAE,EAAE;4BAC/C,EAAE,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC;wBACzB,CAAC,CAAC;wBACF,GAAG,CAAC,EAAE,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;wBACnC,OAAO,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;qBAClD;oBAED,OAAO,QAAQ,CAAC;gBAClB,CAAC;gBACD,eAAe;gBACf,eAAe;oBACb,OAAO,iBAAiB,CAAC;gBAC3B,CAAC;gBACD,SAAS,CAAC,GAAG,EAAE,SAAS;oBACtB,OAAO,SAAS,CAAC,aAAa,CAAC,iBAAiB,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;gBACpE,CAAC;aACF,CAAC;QACJ,CAAC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAvDD,0CAuDC"}
@@ -0,0 +1,2 @@
1
+ import type { LocalizationMessages, NestedLocalizationMessages } from './types';
2
+ export declare function flattenTranslations(messages: LocalizationMessages | NestedLocalizationMessages): LocalizationMessages;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.flattenTranslations = void 0;
4
+ function flat(source) {
5
+ const target = {};
6
+ flatten(source, target);
7
+ return target;
8
+ }
9
+ function flatten(source, target, prop = '') {
10
+ if (typeof source === 'string') {
11
+ target[prop] = source;
12
+ return;
13
+ }
14
+ if (typeof source === 'object' && source !== null) {
15
+ Object.keys(source).forEach((key) => {
16
+ flatten(source[key], target, prop ? `${prop}.${key}` : key);
17
+ });
18
+ return;
19
+ }
20
+ }
21
+ function flattenTranslations(messages) {
22
+ return Object.fromEntries(Object.entries(messages).map(([language, translations]) => {
23
+ return [language, flat(translations)];
24
+ }));
25
+ }
26
+ exports.flattenTranslations = flattenTranslations;
27
+ //# sourceMappingURL=flatten-translations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flatten-translations.js","sourceRoot":"","sources":["../src/flatten-translations.ts"],"names":[],"mappings":";;;AAEA,SAAS,IAAI,CAAC,MAA+B;IAC3C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,OAAO,CAAC,MAAW,EAAE,MAA8B,EAAE,IAAI,GAAG,EAAE;IACrE,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QAC9B,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;QAEtB,OAAO;KACR;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE;QACjD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YAClC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;QAEH,OAAO;KACR;AACH,CAAC;AAED,SAAgB,mBAAmB,CAAC,QAA2D;IAC7F,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,EAAE;QACxD,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAND,kDAMC"}
package/lib/localize.d.ts CHANGED
@@ -1,14 +1,14 @@
1
- import { LocalizationMessages, Localizable } from './types';
1
+ import { LocalizationMessages, Localizable, NestedLocalizationMessages } from './types';
2
2
  declare function defaultFallback(key: string, language: string): string;
3
3
  export declare class Localizer implements Localizable {
4
- messages: LocalizationMessages;
5
4
  language: string;
6
5
  languages: Array<string>;
7
6
  private fallback;
7
+ messages: LocalizationMessages;
8
8
  /**
9
9
  * Creates a new instance of a localizer.
10
10
  */
11
- constructor(messages: LocalizationMessages, language: string, languages: Array<string>, fallback?: typeof defaultFallback);
11
+ constructor(messages: LocalizationMessages | NestedLocalizationMessages, language: string, languages: Array<string>, fallback?: typeof defaultFallback);
12
12
  /**
13
13
  * Localizes the given key via the global translations.
14
14
  * @param key The key of the translation snippet.
package/lib/localize.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Localizer = void 0;
4
+ const flatten_translations_1 = require("./flatten-translations");
4
5
  function defaultFallback(key, language) {
5
6
  if (process.env.NODE_ENV === 'production') {
6
7
  return language ? '...' : '';
@@ -25,10 +26,10 @@ class Localizer {
25
26
  * Creates a new instance of a localizer.
26
27
  */
27
28
  constructor(messages, language, languages, fallback = defaultFallback) {
28
- this.messages = messages;
29
29
  this.language = language;
30
30
  this.languages = languages;
31
31
  this.fallback = fallback;
32
+ this.messages = (0, flatten_translations_1.flattenTranslations)(messages);
32
33
  }
33
34
  /**
34
35
  * Localizes the given key via the global translations.
@@ -1 +1 @@
1
- {"version":3,"file":"localize.js","sourceRoot":"","sources":["../src/localize.ts"],"names":[],"mappings":";;;AAEA,SAAS,eAAe,CAAC,GAAW,EAAE,QAAgB;IACpD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE;QACzC,OAAO,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9B;SAAM;QACL,IAAI,QAAQ,EAAE;YACZ,OAAO,CAAC,IAAI,CAAC,2BAA2B,GAAG,kBAAkB,QAAQ,IAAI,CAAC,CAAC;YAC3E,OAAO,KAAK,QAAQ,IAAI,GAAG,IAAI,CAAC;SACjC;aAAM;YACL,OAAO,EAAE,CAAC;SACX;KACF;AACH,CAAC;AAED,SAAS,aAAa,CAAmB,OAAe,EAAE,SAAY;IACpE,OAAO,OAAO,CAAC,OAAO,CAAC,6BAA6B,EAAE,CAAC,MAAc,EAAE,EAAU,EAAE,EAAE;QACnF,OAAO,EAAE,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAa,SAAS;IACpB;;OAEG;IACH,YACS,QAA8B,EAC9B,QAAgB,EAChB,SAAwB,EACvB,WAAW,eAAe;QAH3B,aAAQ,GAAR,QAAQ,CAAsB;QAC9B,aAAQ,GAAR,QAAQ,CAAQ;QAChB,cAAS,GAAT,SAAS,CAAe;QACvB,aAAQ,GAAR,QAAQ,CAAkB;IACjC,CAAC;IAEJ;;;;OAIG;IACI,cAAc,CAAmB,GAAW,EAAE,SAAa;QAChE,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;;OAMG;IACI,aAAa,CAAmB,aAAmC,EAAE,GAAW,EAAE,SAAa;QACpG,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAErE,IAAI,OAAO,KAAK,SAAS,EAAE;YACzB,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;SAC1C;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,YAAY,CAAmB,GAAW,EAAE,SAAa;QAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAErE,IAAI,OAAO,KAAK,SAAS,EAAE;YACzB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;SAC1C;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,gBAAgB,CAAmB,QAA8B,EAAE,GAAW,EAAE,SAAa;QACnG,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,MAAM,YAAY,GAAG,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACpD,MAAM,WAAW,GAAG,YAAY,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC;QACtD,OAAO,WAAW,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1F,CAAC;CACF;AArDD,8BAqDC"}
1
+ {"version":3,"file":"localize.js","sourceRoot":"","sources":["../src/localize.ts"],"names":[],"mappings":";;;AACA,iEAA6D;AAE7D,SAAS,eAAe,CAAC,GAAW,EAAE,QAAgB;IACpD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE;QACzC,OAAO,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9B;SAAM;QACL,IAAI,QAAQ,EAAE;YACZ,OAAO,CAAC,IAAI,CAAC,2BAA2B,GAAG,kBAAkB,QAAQ,IAAI,CAAC,CAAC;YAC3E,OAAO,KAAK,QAAQ,IAAI,GAAG,IAAI,CAAC;SACjC;aAAM;YACL,OAAO,EAAE,CAAC;SACX;KACF;AACH,CAAC;AAED,SAAS,aAAa,CAAmB,OAAe,EAAE,SAAY;IACpE,OAAO,OAAO,CAAC,OAAO,CAAC,6BAA6B,EAAE,CAAC,MAAc,EAAE,EAAU,EAAE,EAAE;QACnF,OAAO,EAAE,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAa,SAAS;IAGpB;;OAEG;IACH,YACE,QAA2D,EACpD,QAAgB,EAChB,SAAwB,EACvB,WAAW,eAAe;QAF3B,aAAQ,GAAR,QAAQ,CAAQ;QAChB,cAAS,GAAT,SAAS,CAAe;QACvB,aAAQ,GAAR,QAAQ,CAAkB;QAElC,IAAI,CAAC,QAAQ,GAAG,IAAA,0CAAmB,EAAC,QAAQ,CAAC,CAAC;IAChD,CAAC;IAED;;;;OAIG;IACI,cAAc,CAAmB,GAAW,EAAE,SAAa;QAChE,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;;OAMG;IACI,aAAa,CAAmB,aAAmC,EAAE,GAAW,EAAE,SAAa;QACpG,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAErE,IAAI,OAAO,KAAK,SAAS,EAAE;YACzB,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;SAC1C;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,YAAY,CAAmB,GAAW,EAAE,SAAa;QAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAErE,IAAI,OAAO,KAAK,SAAS,EAAE;YACzB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;SAC1C;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,gBAAgB,CAAmB,QAA8B,EAAE,GAAW,EAAE,SAAa;QACnG,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,MAAM,YAAY,GAAG,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACpD,MAAM,WAAW,GAAG,YAAY,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC;QACtD,OAAO,WAAW,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1F,CAAC;CACF;AAzDD,8BAyDC"}
package/lib/types.d.ts CHANGED
@@ -91,6 +91,12 @@ export interface Translations {
91
91
  */
92
92
  [tag: string]: string;
93
93
  }
94
+ export interface NestedTranslations {
95
+ /**
96
+ * The available wordings (tag to translation or nested translations).
97
+ */
98
+ [tag: string]: string | NestedTranslations;
99
+ }
94
100
  export interface LanguageLoader {
95
101
  (language: string, current: LanguageData): Promise<LanguageData>;
96
102
  }
@@ -107,6 +113,13 @@ export interface LocalizationMessages {
107
113
  */
108
114
  [lang: string]: Translations;
109
115
  }
116
+ export interface NestedLocalizationMessages {
117
+ /**
118
+ * The available languages (lang to wordings or nested wordings).
119
+ */
120
+ [lang: string]: NestedTranslations;
121
+ }
122
+ export type AnyLocalizationMessages = LocalizationMessages | NestedLocalizationMessages;
110
123
  export interface PiletLocaleApi {
111
124
  /**
112
125
  * Adds a list of translations to the existing translations.
@@ -117,7 +130,7 @@ export interface PiletLocaleApi {
117
130
  * @param messagesList The list of messages that extend the existing translations
118
131
  * @param [isOverriding=true] Indicates whether the new translations overwrite the existing translations
119
132
  */
120
- addTranslations(messagesList: LocalizationMessages[], isOverriding?: boolean): void;
133
+ addTranslations(messagesList: Array<AnyLocalizationMessages>, isOverriding?: boolean): void;
121
134
  /**
122
135
  * Gets the currently selected language directly.
123
136
  */
@@ -139,7 +152,7 @@ export interface PiletLocaleApi {
139
152
  * The translations will be exclusively used for retrieving translations for the pilet.
140
153
  * @param messages The messages to use as translation basis.
141
154
  */
142
- setTranslations(messages: LocalizationMessages): void;
155
+ setTranslations(messages: AnyLocalizationMessages): void;
143
156
  /**
144
157
  * Gets the currently provided translations by the pilet.
145
158
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "piral-translate",
3
- "version": "1.4.0-beta.6260",
3
+ "version": "1.4.0-beta.6280",
4
4
  "description": "Plugin for providing translated messages in Piral.",
5
5
  "keywords": [
6
6
  "piral",
@@ -68,8 +68,8 @@
68
68
  "devDependencies": {
69
69
  "@types/deepmerge": "^2.2.0",
70
70
  "@types/react": "^18.0.0",
71
- "piral-core": "1.4.0-beta.6260",
71
+ "piral-core": "1.4.0-beta.6280",
72
72
  "react": "^18.0.0"
73
73
  },
74
- "gitHead": "07d38da0658c5f4dc20143f0c8c3527b53de268c"
74
+ "gitHead": "8402e4d3d6f5de2e76c48bcc5ce79279a3c957e4"
75
75
  }
@@ -1 +1 @@
1
- var piralTranslate=(()=>{var k=Object.create;var p=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var I=Object.getPrototypeOf,R=Object.prototype.hasOwnProperty;var T=e=>p(e,"__esModule",{value:!0});var l=(e=>typeof require!="undefined"?require:typeof Proxy!="undefined"?new Proxy(e,{get:(t,r)=>(typeof require!="undefined"?require:t)[r]}):e)(function(e){if(typeof require!="undefined")return require.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')});var F=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),U=(e,t)=>{T(e);for(var r in t)p(e,r,{get:t[r],enumerable:!0})},$=(e,t,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of G(t))!R.call(e,a)&&a!=="default"&&p(e,a,{get:()=>t[a],enumerable:!(r=w(t,a))||r.enumerable});return e},i=e=>$(T(p(e!=null?k(I(e)):{},"default",e&&e.__esModule&&"default"in e?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);var j=F((ue,O)=>{"use strict";var D=function(t){return N(t)&&!B(t)};function N(e){return!!e&&typeof e=="object"}function B(e){var t=Object.prototype.toString.call(e);return t==="[object RegExp]"||t==="[object Date]"||Y(e)}var V=typeof Symbol=="function"&&Symbol.for,K=V?Symbol.for("react.element"):60103;function Y(e){return e.$$typeof===K}function Z(e){return Array.isArray(e)?[]:{}}function g(e,t){return t.clone!==!1&&t.isMergeableObject(e)?c(Z(e),e,t):e}function q(e,t,r){return e.concat(t).map(function(a){return g(a,r)})}function H(e,t){if(!t.customMerge)return c;var r=t.customMerge(e);return typeof r=="function"?r:c}function J(e){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(e).filter(function(t){return Object.propertyIsEnumerable.call(e,t)}):[]}function x(e){return Object.keys(e).concat(J(e))}function h(e,t){try{return t in e}catch{return!1}}function Q(e,t){return h(e,t)&&!(Object.hasOwnProperty.call(e,t)&&Object.propertyIsEnumerable.call(e,t))}function W(e,t,r){var a={};return r.isMergeableObject(e)&&x(e).forEach(function(n){a[n]=g(e[n],r)}),x(t).forEach(function(n){Q(e,n)||(h(e,n)&&r.isMergeableObject(t[n])?a[n]=H(n,r)(e[n],t[n],r):a[n]=g(t[n],r))}),a}function c(e,t,r){r=r||{},r.arrayMerge=r.arrayMerge||q,r.isMergeableObject=r.isMergeableObject||D,r.cloneUnlessOtherwiseSpecified=g;var a=Array.isArray(t),n=Array.isArray(e),s=a===n;return s?a?r.arrayMerge(e,t,r):W(e,t,r):g(t,r)}c.all=function(t,r){if(!Array.isArray(t))throw new Error("first argument should be an array");return t.reduce(function(a,n){return c(a,n,r)},{})};var X=c;O.exports=X});var le={};U(le,{Languages:()=>ie,PiralLanguagesPicker:()=>L,createLocaleApi:()=>re,getUserLocale:()=>ne,setupLocalizer:()=>z,useDynamicLanguage:()=>se,useTranslate:()=>oe});var M=i(l("piral-core")),L=(0,M.getPiralComponent)("LanguagesPicker");var v=i(j());function P(e){return{selectLanguage(t,r){t.dispatch(a=>{e.language=r;let n=a.language.selected,s=r;return setTimeout(()=>{t.emit("select-language",{previousLanguage:n,currentLanguage:s})},0),{...a,language:{...a.language,loading:r===void 0,selected:r}}})},translate(t,r,a){return e&&e.localizeGlobal(r,a)},setTranslations(t,r,a){e.messages[r]=a.global;for(let n of a.locals){let s=t.apis[n.name];if(s){let o=s.getTranslations();o[r]=n.value,s.setTranslations(o)}}},getTranslations(t,r){return{global:e.messages[r],locals:Object.keys(t.apis).map(a=>({name:a,value:t.apis[a].getTranslations()[r]}))}}}}function ee(e,t){return t?"...":""}function te(e,t){return e.replace(/{{\s*([A-Za-z0-9_.]+)\s*}}/g,(r,a)=>a in t?t[a]||"":`{{${a}}}`)}var y=class{constructor(t,r,a,n=ee){this.messages=t;this.language=r;this.languages=a;this.fallback=n}localizeGlobal(t,r){return this.localizeBase(t,r)}localizeLocal(t,r,a){let n=this.translateMessage(t,r,a);return n===void 0?this.localizeBase(r,a):n}localizeBase(t,r){let a=this.translateMessage(this.messages,t,r);return a===void 0?this.fallback(t,this.language):a}translateMessage(t,r,a){let n=this.language,s=n&&t[n],o=s&&s[r];return o&&(a?te(o,a):o)}};var A=i(l("piral-core")),S=e=>(0,A.defaultRender)(void 0);function z(e={}){let t=e.messages||{},r=Object.keys(t),a=r[0]||"en",n=e.language,o=(typeof n=="function"?n(r,a,"en"):n)||a;return new y(t,o,r.length?r:[o],e.fallback)}function re(e=z()){return t=>(t.defineActions(P(e)),t.dispatch(r=>({...r,components:{LanguagesPicker:S,...r.components},language:{loading:!1,available:e.languages,selected:e.language}})),r=>{let a={};return{addTranslations(n,s=!0){let o=n;s?o.unshift(e.messages):o.push(e.messages),this.setTranslations(v.all(o))},getCurrentLanguage(n){let s=t.readState(o=>o.language.selected);if(n){n(s);let o=f=>{n(f.currentLanguage)};return r.on("select-language",o),()=>r.off("select-language",o)}return s},setTranslations(n){a=n},getTranslations(){return a},translate(n,s){return e.localizeLocal(a,n,s)}}})}var m=i(l("piral-core"));function ae(e,t){let r=m.cookie.getItem("_culture")||m.storage.getItem("locale");return r||(t?t.toLowerCase().substring(0,2):navigator.language?navigator.language.substring(0,2):e)}function ne(e,t,r){let a=ae(t,r||"");return e.indexOf(a)!==-1?a:t}var b=i(l("react")),u=i(l("piral-core"));function se(e,t){let[r,a]=(0,b.useState)(e),{selectLanguage:n,setTranslations:s,getTranslations:o}=(0,u.useActions)();return(0,b.useEffect)(()=>{let f=!0,_=o(r);return n(void 0),t(r,_).then(d=>{f&&(s(r,d),n(r))},d=>console.error(d)),()=>{f=!1}},[r]),[r,a]}function oe(){let{translate:e}=(0,u.useActions)();return(0,u.useGlobalState)(t=>t.language.selected),e}var E=i(l("react")),C=i(l("piral-core"));var ie=()=>{let{available:e,selected:t}=(0,C.useGlobalState)(r=>r.language);return E.createElement(L,{selected:t,available:e})};return le;})();
1
+ var piralTranslate=(()=>{var R=Object.create;var p=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var $=Object.getPrototypeOf,I=Object.prototype.hasOwnProperty;var j=e=>p(e,"__esModule",{value:!0});var c=(e=>typeof require!="undefined"?require:typeof Proxy!="undefined"?new Proxy(e,{get:(t,r)=>(typeof require!="undefined"?require:t)[r]}):e)(function(e){if(typeof require!="undefined")return require.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')});var F=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),U=(e,t)=>{j(e);for(var r in t)p(e,r,{get:t[r],enumerable:!0})},D=(e,t,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of N(t))!I.call(e,n)&&n!=="default"&&p(e,n,{get:()=>t[n],enumerable:!(r=G(t,n))||r.enumerable});return e},l=e=>D(j(p(e!=null?R($(e)):{},"default",e&&e.__esModule&&"default"in e?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);var h=F((me,z)=>{"use strict";var B=function(t){return V(t)&&!K(t)};function V(e){return!!e&&typeof e=="object"}function K(e){var t=Object.prototype.toString.call(e);return t==="[object RegExp]"||t==="[object Date]"||q(e)}var Y=typeof Symbol=="function"&&Symbol.for,Z=Y?Symbol.for("react.element"):60103;function q(e){return e.$$typeof===Z}function H(e){return Array.isArray(e)?[]:{}}function u(e,t){return t.clone!==!1&&t.isMergeableObject(e)?g(H(e),e,t):e}function J(e,t,r){return e.concat(t).map(function(n){return u(n,r)})}function Q(e,t){if(!t.customMerge)return g;var r=t.customMerge(e);return typeof r=="function"?r:g}function W(e){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(e).filter(function(t){return Object.propertyIsEnumerable.call(e,t)}):[]}function x(e){return Object.keys(e).concat(W(e))}function A(e,t){try{return t in e}catch{return!1}}function X(e,t){return A(e,t)&&!(Object.hasOwnProperty.call(e,t)&&Object.propertyIsEnumerable.call(e,t))}function ee(e,t,r){var n={};return r.isMergeableObject(e)&&x(e).forEach(function(a){n[a]=u(e[a],r)}),x(t).forEach(function(a){X(e,a)||(A(e,a)&&r.isMergeableObject(t[a])?n[a]=Q(a,r)(e[a],t[a],r):n[a]=u(t[a],r))}),n}function g(e,t,r){r=r||{},r.arrayMerge=r.arrayMerge||J,r.isMergeableObject=r.isMergeableObject||B,r.cloneUnlessOtherwiseSpecified=u;var n=Array.isArray(t),a=Array.isArray(e),s=n===a;return s?n?r.arrayMerge(e,t,r):ee(e,t,r):u(t,r)}g.all=function(t,r){if(!Array.isArray(t))throw new Error("first argument should be an array");return t.reduce(function(n,a){return g(n,a,r)},{})};var te=g;z.exports=te});var ue={};U(ue,{Languages:()=>ge,PiralLanguagesPicker:()=>M,createLocaleApi:()=>se,getUserLocale:()=>ie,setupLocalizer:()=>_,useDynamicLanguage:()=>le,useTranslate:()=>ce});var O=l(c("piral-core")),M=(0,O.getPiralComponent)("LanguagesPicker");var C=l(h());function P(e){return{selectLanguage(t,r){t.dispatch(n=>{e.language=r;let a=n.language.selected,s=r;return setTimeout(()=>{t.emit("select-language",{previousLanguage:a,currentLanguage:s})},0),{...n,language:{...n.language,loading:r===void 0,selected:r}}})},translate(t,r,n){return e&&e.localizeGlobal(r,n)},setTranslations(t,r,n){e.messages[r]=n.global;for(let a of n.locals){let s=t.apis[a.name];if(s){let o=s.getTranslations();o[r]=a.value,s.setTranslations(o)}}},getTranslations(t,r){return{global:e.messages[r],locals:Object.keys(t.apis).map(n=>({name:n,value:t.apis[n].getTranslations()[r]}))}}}}function re(e){let t={};return S(e,t),t}function S(e,t,r=""){if(typeof e=="string"){t[r]=e;return}if(typeof e=="object"&&e!==null){Object.keys(e).forEach(n=>{S(e[n],t,r?`${r}.${n}`:n)});return}}function m(e){return Object.fromEntries(Object.entries(e).map(([t,r])=>[t,re(r)]))}function ne(e,t){return t?"...":""}function ae(e,t){return e.replace(/{{\s*([A-Za-z0-9_.]+)\s*}}/g,(r,n)=>n in t?t[n]||"":`{{${n}}}`)}var T=class{constructor(t,r,n,a=ne){this.language=r;this.languages=n;this.fallback=a;this.messages=m(t)}localizeGlobal(t,r){return this.localizeBase(t,r)}localizeLocal(t,r,n){let a=this.translateMessage(t,r,n);return a===void 0?this.localizeBase(r,n):a}localizeBase(t,r){let n=this.translateMessage(this.messages,t,r);return n===void 0?this.fallback(t,this.language):n}translateMessage(t,r,n){let a=this.language,s=a&&t[a],o=s&&s[r];return o&&(n?ae(o,n):o)}};var v=l(c("piral-core")),E=e=>(0,v.defaultRender)(void 0);function _(e={}){let t=e.messages||{},r=Object.keys(t),n=r[0]||"en",a=e.language,o=(typeof a=="function"?a(r,n,"en"):a)||n;return new T(t,o,r.length?r:[o],e.fallback)}function se(e=_()){return t=>(t.defineActions(P(e)),t.dispatch(r=>({...r,components:{LanguagesPicker:E,...r.components},language:{loading:!1,available:e.languages,selected:e.language}})),r=>{let n={},a=s=>{n=m(s)};return{addTranslations(s,o=!0){let i=e.messages;a(C.all(o?[i,...s]:[...s,i]))},getCurrentLanguage(s){let o=t.readState(i=>i.language.selected);if(s){s(o);let i=L=>{s(L.currentLanguage)};return r.on("select-language",i),()=>r.off("select-language",i)}return o},setTranslations:a,getTranslations(){return n},translate(s,o){return e.localizeLocal(n,s,o)}}})}var b=l(c("piral-core"));function oe(e,t){let r=b.cookie.getItem("_culture")||b.storage.getItem("locale");return r||(t?t.toLowerCase().substring(0,2):navigator.language?navigator.language.substring(0,2):e)}function ie(e,t,r){let n=oe(t,r||"");return e.indexOf(n)!==-1?n:t}var d=l(c("react")),f=l(c("piral-core"));function le(e,t){let[r,n]=(0,d.useState)(e),{selectLanguage:a,setTranslations:s,getTranslations:o}=(0,f.useActions)();return(0,d.useEffect)(()=>{let i=!0,L=o(r);return a(void 0),t(r,L).then(y=>{i&&(s(r,y),a(r))},y=>console.error(y)),()=>{i=!1}},[r]),[r,n]}function ce(){let{translate:e}=(0,f.useActions)();return(0,f.useGlobalState)(t=>t.language.selected),e}var k=l(c("react")),w=l(c("piral-core"));var ge=()=>{let{available:e,selected:t}=(0,w.useGlobalState)(r=>r.language);return k.createElement(M,{selected:t,available:e})};return ue;})();
@@ -73,6 +73,22 @@ describe('Create Localize API', () => {
73
73
  expect(result).toEqual('bár');
74
74
  });
75
75
 
76
+ it('createApi can translate from local-global translations using the current language and passed nested translations', () => {
77
+ const config = {
78
+ language: 'en'
79
+ };
80
+ const api = (createLocaleApi(setupLocalizer(config))(context) as any)();
81
+ api.setTranslations({
82
+ en: {
83
+ header: {
84
+ title: 'Hello world'
85
+ }
86
+ }
87
+ });
88
+ const result = api.translate('header.title');
89
+ expect(result).toBe('Hello world');
90
+ });
91
+
76
92
  it('createApi falls back to standard string if language is not found', () => {
77
93
  const config = {
78
94
  language: 'en',
package/src/create.ts CHANGED
@@ -4,7 +4,14 @@ import type { PiralPlugin } from 'piral-core';
4
4
  import { createActions } from './actions';
5
5
  import { Localizer } from './localize';
6
6
  import { DefaultPicker } from './default';
7
- import { PiletLocaleApi, LocalizationMessages, Localizable, PiralSelectLanguageEvent } from './types';
7
+ import { flattenTranslations } from './flatten-translations';
8
+ import type {
9
+ PiletLocaleApi,
10
+ LocalizationMessages,
11
+ Localizable,
12
+ PiralSelectLanguageEvent,
13
+ AnyLocalizationMessages,
14
+ } from './types';
8
15
 
9
16
  export interface TranslationFallback {
10
17
  (key: string, language: string): string;
@@ -22,7 +29,7 @@ export interface LocaleConfig {
22
29
  * Sets the default (global) localization messages.
23
30
  * @default {}
24
31
  */
25
- messages?: LocalizationMessages;
32
+ messages?: AnyLocalizationMessages;
26
33
  /**
27
34
  * Sets the default language to use.
28
35
  */
@@ -71,18 +78,15 @@ export function createLocaleApi(localizer: Localizable = setupLocalizer()): Pira
71
78
  return (api) => {
72
79
  let localTranslations: LocalizationMessages = {};
73
80
 
74
- return {
75
- addTranslations(messages: LocalizationMessages[], isOverriding: boolean = true) {
76
- const messagesToMerge: LocalizationMessages[] = messages;
77
-
78
- if (isOverriding) {
79
- messagesToMerge.unshift(localizer.messages);
80
- } else {
81
- messagesToMerge.push(localizer.messages);
82
- }
81
+ const setTranslations = (messages: AnyLocalizationMessages) => {
82
+ localTranslations = flattenTranslations(messages);
83
+ };
83
84
 
84
- this.setTranslations(
85
- deepmerge.all(messagesToMerge),
85
+ return {
86
+ addTranslations(messages, isOverriding = true) {
87
+ const current = localizer.messages;
88
+ setTranslations(
89
+ deepmerge.all<AnyLocalizationMessages>(isOverriding ? [current, ...messages] : [...messages, current]),
86
90
  );
87
91
  },
88
92
  getCurrentLanguage(cb?: (l: string) => void): any {
@@ -99,9 +103,7 @@ export function createLocaleApi(localizer: Localizable = setupLocalizer()): Pira
99
103
 
100
104
  return selected;
101
105
  },
102
- setTranslations(messages) {
103
- localTranslations = messages;
104
- },
106
+ setTranslations,
105
107
  getTranslations() {
106
108
  return localTranslations;
107
109
  },
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @vitest-environment jsdom
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { flattenTranslations } from './flatten-translations';
6
+
7
+ describe('Flatten translations', () => {
8
+ it('flattenTranslations can handle flat keys', () => {
9
+ const messages = {
10
+ en: {
11
+ key: 'value'
12
+ },
13
+ fr: {
14
+ key: 'value (fr)'
15
+ }
16
+ };
17
+ const flatMessages = flattenTranslations(messages);
18
+ expect(flatMessages.fr.key).toEqual('value (fr)');
19
+ });
20
+
21
+ it('flattenTranslations can handle flat dot keys', () => {
22
+ const messages = {
23
+ en: {
24
+ 'header.title': 'Hello world'
25
+ }
26
+ };
27
+ const flatMessages = flattenTranslations(messages);
28
+ expect(flatMessages.en['header.title']).toBe('Hello world');
29
+ });
30
+
31
+ it('flattenTranslations can handle nested keys', () => {
32
+ const messages = {
33
+ en: {
34
+ header: {
35
+ title: 'Hello world'
36
+ }
37
+ }
38
+ };
39
+ const flatMessages = flattenTranslations(messages);
40
+ expect(flatMessages.en['header.title']).toBe('Hello world');
41
+ });
42
+
43
+ it('flattenTranslations can handle nested keys with multiple depth levels', () => {
44
+ const messages = {
45
+ en: {
46
+ header: {
47
+ title: {
48
+ subtitle: 'Hello world'
49
+ }
50
+ }
51
+ }
52
+ };
53
+ const flatMessages = flattenTranslations(messages);
54
+ expect(flatMessages.en['header.title.subtitle']).toBe('Hello world');
55
+ });
56
+ });
@@ -0,0 +1,31 @@
1
+ import type { LocalizationMessages, NestedLocalizationMessages } from './types';
2
+
3
+ function flat(source: Record<string, unknown>): Record<string, string> {
4
+ const target: Record<string, string> = {};
5
+ flatten(source, target);
6
+ return target;
7
+ }
8
+
9
+ function flatten(source: any, target: Record<string, string>, prop = '') {
10
+ if (typeof source === 'string') {
11
+ target[prop] = source;
12
+
13
+ return;
14
+ }
15
+
16
+ if (typeof source === 'object' && source !== null) {
17
+ Object.keys(source).forEach((key) => {
18
+ flatten(source[key], target, prop ? `${prop}.${key}` : key);
19
+ });
20
+
21
+ return;
22
+ }
23
+ }
24
+
25
+ export function flattenTranslations(messages: LocalizationMessages | NestedLocalizationMessages): LocalizationMessages {
26
+ return Object.fromEntries(
27
+ Object.entries(messages).map(([language, translations]) => {
28
+ return [language, flat(translations)];
29
+ }),
30
+ );
31
+ }
@@ -8,6 +8,9 @@ const messages = {
8
8
  en: {
9
9
  hi: 'hello',
10
10
  greeting: 'Hi {{name}}, welcome back',
11
+ header: {
12
+ title: 'Hello world'
13
+ }
11
14
  },
12
15
  de: {
13
16
  hi: 'hallo',
@@ -76,4 +79,11 @@ describe('Localize Module', () => {
76
79
  const result = localizer.localizeGlobal('greeting', { name: undefined });
77
80
  expect(result).toBe('Hi , welcome back');
78
81
  });
82
+
83
+ it('localizeGlobal translates from global translations using passed nested translations', () => {
84
+ const localizer = new Localizer(messages, 'en');
85
+ const result = localizer.localizeGlobal('header.title');
86
+
87
+ expect(result).toBe('Hello world');
88
+ });
79
89
  });
package/src/localize.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { LocalizationMessages, Localizable } from './types';
1
+ import { LocalizationMessages, Localizable, NestedLocalizationMessages } from './types';
2
+ import { flattenTranslations } from './flatten-translations';
2
3
 
3
4
  function defaultFallback(key: string, language: string): string {
4
5
  if (process.env.NODE_ENV === 'production') {
@@ -20,15 +21,19 @@ function formatMessage<T extends object>(message: string, variables: T): string
20
21
  }
21
22
 
22
23
  export class Localizer implements Localizable {
24
+ public messages: LocalizationMessages;
25
+
23
26
  /**
24
27
  * Creates a new instance of a localizer.
25
28
  */
26
29
  constructor(
27
- public messages: LocalizationMessages,
30
+ messages: LocalizationMessages | NestedLocalizationMessages,
28
31
  public language: string,
29
32
  public languages: Array<string>,
30
33
  private fallback = defaultFallback,
31
- ) {}
34
+ ) {
35
+ this.messages = flattenTranslations(messages);
36
+ }
32
37
 
33
38
  /**
34
39
  * Localizes the given key via the global translations.
package/src/types.ts CHANGED
@@ -100,6 +100,13 @@ export interface Translations {
100
100
  [tag: string]: string;
101
101
  }
102
102
 
103
+ export interface NestedTranslations {
104
+ /**
105
+ * The available wordings (tag to translation or nested translations).
106
+ */
107
+ [tag: string]: string | NestedTranslations;
108
+ }
109
+
103
110
  export interface LanguageLoader {
104
111
  (language: string, current: LanguageData): Promise<LanguageData>;
105
112
  }
@@ -119,6 +126,15 @@ export interface LocalizationMessages {
119
126
  [lang: string]: Translations;
120
127
  }
121
128
 
129
+ export interface NestedLocalizationMessages {
130
+ /**
131
+ * The available languages (lang to wordings or nested wordings).
132
+ */
133
+ [lang: string]: NestedTranslations;
134
+ }
135
+
136
+ export type AnyLocalizationMessages = LocalizationMessages | NestedLocalizationMessages;
137
+
122
138
  export interface PiletLocaleApi {
123
139
  /**
124
140
  * Adds a list of translations to the existing translations.
@@ -129,7 +145,7 @@ export interface PiletLocaleApi {
129
145
  * @param messagesList The list of messages that extend the existing translations
130
146
  * @param [isOverriding=true] Indicates whether the new translations overwrite the existing translations
131
147
  */
132
- addTranslations(messagesList: LocalizationMessages[], isOverriding?: boolean): void;
148
+ addTranslations(messagesList: Array<AnyLocalizationMessages>, isOverriding?: boolean): void;
133
149
  /**
134
150
  * Gets the currently selected language directly.
135
151
  */
@@ -151,7 +167,7 @@ export interface PiletLocaleApi {
151
167
  * The translations will be exclusively used for retrieving translations for the pilet.
152
168
  * @param messages The messages to use as translation basis.
153
169
  */
154
- setTranslations(messages: LocalizationMessages): void;
170
+ setTranslations(messages: AnyLocalizationMessages): void;
155
171
  /**
156
172
  * Gets the currently provided translations by the pilet.
157
173
  */