@openedx/frontend-base 1.0.0-alpha.21 → 1.0.0-alpha.22

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.
Files changed (52) hide show
  1. package/dist/runtime/i18n/index.d.ts +1 -1
  2. package/dist/runtime/i18n/index.js +1 -1
  3. package/dist/runtime/i18n/index.js.map +1 -1
  4. package/dist/runtime/i18n/lib.d.ts +0 -6
  5. package/dist/runtime/i18n/lib.js +0 -13
  6. package/dist/runtime/i18n/lib.js.map +1 -1
  7. package/dist/shell/dev/devHome/app.js +0 -2
  8. package/dist/shell/dev/devHome/app.js.map +1 -1
  9. package/dist/shell/site.js +1 -3
  10. package/dist/shell/site.js.map +1 -1
  11. package/dist/tools/cli/commands/translations.d.ts +2 -0
  12. package/dist/tools/cli/commands/translations.js +20 -0
  13. package/dist/tools/cli/openedx.js +6 -0
  14. package/dist/tools/cli/utils/printUsage.js +8 -0
  15. package/dist/tools/cli/utils/translations/index.d.ts +2 -0
  16. package/dist/tools/cli/utils/translations/index.js +7 -0
  17. package/dist/tools/cli/utils/translations/messagesObject.d.ts +26 -0
  18. package/dist/tools/cli/utils/translations/messagesObject.js +66 -0
  19. package/dist/tools/cli/utils/translations/prepare.d.ts +5 -0
  20. package/dist/tools/cli/utils/translations/prepare.js +98 -0
  21. package/dist/tools/cli/utils/translations/pull.d.ts +6 -0
  22. package/dist/tools/cli/utils/translations/pull.js +102 -0
  23. package/dist/tools/types.d.ts +2 -0
  24. package/dist/tools/types.js +2 -0
  25. package/dist/tools/webpack/common-config/index.d.ts +1 -0
  26. package/dist/tools/webpack/common-config/index.js +3 -1
  27. package/dist/tools/webpack/common-config/site/getI18nMessagesFallbackPlugin/emptyI18n.d.ts +2 -0
  28. package/dist/tools/webpack/common-config/site/getI18nMessagesFallbackPlugin/emptyI18n.js +3 -0
  29. package/dist/tools/webpack/common-config/site/getI18nMessagesFallbackPlugin/index.d.ts +2 -0
  30. package/dist/tools/webpack/common-config/site/getI18nMessagesFallbackPlugin/index.js +26 -0
  31. package/dist/tools/webpack/utils/getResolvedSiteI18nPath.d.ts +1 -0
  32. package/dist/tools/webpack/utils/getResolvedSiteI18nPath.js +25 -0
  33. package/dist/tools/webpack/webpack.config.build.js +4 -0
  34. package/dist/tools/webpack/webpack.config.dev.js +4 -0
  35. package/dist/tools/webpack/webpack.config.dev.shell.js +3 -0
  36. package/dist/types.d.ts +1 -1
  37. package/dist/types.js.map +1 -1
  38. package/package.json +13 -7
  39. package/dist/shell/dev/devHome/i18n/index.d.ts +0 -27
  40. package/dist/shell/dev/devHome/i18n/index.js +0 -28
  41. package/dist/shell/dev/devHome/i18n/index.js.map +0 -1
  42. package/dist/shell/i18n/index.d.ts +0 -25
  43. package/dist/shell/i18n/index.js +0 -26
  44. package/dist/shell/i18n/index.js.map +0 -1
  45. package/dist/tools/cli/intl-imports.d.ts +0 -7
  46. package/dist/tools/cli/intl-imports.js +0 -233
  47. package/dist/tools/cli/intl-imports.test.d.ts +0 -1
  48. package/dist/tools/cli/intl-imports.test.js +0 -146
  49. package/dist/tools/cli/transifex-utils.d.ts +0 -2
  50. package/dist/tools/cli/transifex-utils.js +0 -68
  51. package/dist/tools/webpack/plugins/html-webpack-new-relic-plugin/test/HtmlWebpackNewRelicPlugin.test.d.ts +0 -1
  52. package/dist/tools/webpack/plugins/html-webpack-new-relic-plugin/test/HtmlWebpackNewRelicPlugin.test.js +0 -66
@@ -1,3 +1,3 @@
1
1
  export { default as injectIntl } from "./injectIntlWithShim";
2
2
  export { createIntl, defineMessages, FormattedDate, FormattedMessage, FormattedNumber, FormattedPlural, FormattedRelativeTime, FormattedTime, IntlProvider, useIntl } from "react-intl";
3
- export { addAppMessages, configureI18n, getLocale, getLocalizedLanguageName, getMessages, getPrimaryLanguageSubtag, getSupportedLanguageList, handleRtl, intlShape, isRtl, LOCALE_CHANGED, LOCALE_TOPIC, mergeMessages, updateLocale } from "./lib";
3
+ export { configureI18n, getLocale, getLocalizedLanguageName, getMessages, getPrimaryLanguageSubtag, getSupportedLanguageList, handleRtl, intlShape, isRtl, LOCALE_CHANGED, LOCALE_TOPIC, mergeMessages, updateLocale } from "./lib";
@@ -73,6 +73,6 @@
73
73
  * @see {@link https://formatjs.io/docs/react-intl/api#useIntl Intl}
74
74
  */
75
75
  export { createIntl, defineMessages, FormattedDate, FormattedMessage, FormattedNumber, FormattedPlural, FormattedRelativeTime, FormattedTime, IntlProvider, useIntl } from 'react-intl';
76
- export { addAppMessages, configureI18n, getLocale, getLocalizedLanguageName, getMessages, getPrimaryLanguageSubtag, getSupportedLanguageList, handleRtl, intlShape, isRtl, LOCALE_CHANGED, LOCALE_TOPIC, mergeMessages, updateLocale } from './lib';
76
+ export { configureI18n, getLocale, getLocalizedLanguageName, getMessages, getPrimaryLanguageSubtag, getSupportedLanguageList, handleRtl, intlShape, isRtl, LOCALE_CHANGED, LOCALE_TOPIC, mergeMessages, updateLocale } from './lib';
77
77
  export { default as injectIntl } from './injectIntlWithShim';
78
78
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../runtime/i18n/index.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH,OAAO,EACL,UAAU,EACV,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,YAAY,EACZ,OAAO,EACR,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,cAAc,EACd,aAAa,EACb,SAAS,EACT,wBAAwB,EACxB,WAAW,EACX,wBAAwB,EACxB,wBAAwB,EACxB,SAAS,EACT,SAAS,EACT,KAAK,EACL,cAAc,EACd,YAAY,EACZ,aAAa,EACb,YAAY,EACb,MAAM,OAAO,CAAC;AAEf,OAAO,EACL,OAAO,IAAI,UAAU,EACtB,MAAM,sBAAsB,CAAC","sourcesContent":["/**\n * #### Import members from **@openedx/frontend-base**\n * The i18n module relies on react-intl and re-exports all of that package's exports.\n *\n * For each locale we want to support, react-intl needs 1) the locale-data, which includes\n * information about how to format numbers, handle plurals, etc., and 2) the translations, as an\n * object holding message id / translated string pairs. A locale string and the messages object are\n * passed into the IntlProvider element that wraps your element hierarchy.\n *\n * Note that react-intl has no way of checking if the translations you give it actually have\n * anything to do with the locale you pass it; it will happily use whatever messages object you pass\n * in. However, if the locale data for the locale you passed into the IntlProvider was not\n * correctly installed with addLocaleData, all of your translations will fall back to the default\n * (in our case English), *even if you gave IntlProvider the correct messages object for that\n * locale*.\n *\n * Messages are provided to this module via the configureI18n() function below.\n *\n *\n * @module Internationalization\n * @see {@link https://github.com/openedx/frontend-base/blob/master/docs/how_tos/i18n.rst}\n * @see {@link https://formatjs.io/docs/react-intl/components/ Intl} for components exported from this module.\n *\n */\n\n/**\n * @name createIntl\n * @kind function\n * @see {@link https://formatjs.io/docs/react-intl/api#createIntl Intl}\n */\n\n/**\n * @name FormattedDate\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formatteddate Intl}\n */\n\n/**\n * @name FormattedTime\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedtime Intl}\n */\n\n/**\n * @name FormattedRelativeTime\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedrelativetime Intl}\n */\n\n/**\n * @name FormattedNumber\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattednumber Intl}\n */\n\n/**\n * @name FormattedPlural\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedplural Intl}\n */\n\n/**\n * @name FormattedMessage\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedmessage Intl}\n */\n\n/**\n * @name IntlProvider\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#intlprovider Intl}\n */\n\n/**\n * @name defineMessages\n * @kind function\n * @see {@link https://formatjs.io/docs/react-intl/api#definemessagesdefinemessage Intl}\n */\n\n/**\n * @name useIntl\n * @kind function\n * @see {@link https://formatjs.io/docs/react-intl/api#useIntl Intl}\n */\n\nexport {\n createIntl,\n defineMessages,\n FormattedDate,\n FormattedMessage,\n FormattedNumber,\n FormattedPlural,\n FormattedRelativeTime,\n FormattedTime,\n IntlProvider,\n useIntl\n} from 'react-intl';\n\nexport {\n addAppMessages,\n configureI18n,\n getLocale,\n getLocalizedLanguageName,\n getMessages,\n getPrimaryLanguageSubtag,\n getSupportedLanguageList,\n handleRtl,\n intlShape,\n isRtl,\n LOCALE_CHANGED,\n LOCALE_TOPIC,\n mergeMessages,\n updateLocale\n} from './lib';\n\nexport {\n default as injectIntl\n} from './injectIntlWithShim';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../runtime/i18n/index.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH,OAAO,EACL,UAAU,EACV,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,YAAY,EACZ,OAAO,EACR,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,aAAa,EACb,SAAS,EACT,wBAAwB,EACxB,WAAW,EACX,wBAAwB,EACxB,wBAAwB,EACxB,SAAS,EACT,SAAS,EACT,KAAK,EACL,cAAc,EACd,YAAY,EACZ,aAAa,EACb,YAAY,EACb,MAAM,OAAO,CAAC;AAEf,OAAO,EACL,OAAO,IAAI,UAAU,EACtB,MAAM,sBAAsB,CAAC","sourcesContent":["/**\n * #### Import members from **@openedx/frontend-base**\n * The i18n module relies on react-intl and re-exports all of that package's exports.\n *\n * For each locale we want to support, react-intl needs 1) the locale-data, which includes\n * information about how to format numbers, handle plurals, etc., and 2) the translations, as an\n * object holding message id / translated string pairs. A locale string and the messages object are\n * passed into the IntlProvider element that wraps your element hierarchy.\n *\n * Note that react-intl has no way of checking if the translations you give it actually have\n * anything to do with the locale you pass it; it will happily use whatever messages object you pass\n * in. However, if the locale data for the locale you passed into the IntlProvider was not\n * correctly installed with addLocaleData, all of your translations will fall back to the default\n * (in our case English), *even if you gave IntlProvider the correct messages object for that\n * locale*.\n *\n * Messages are provided to this module via the configureI18n() function below.\n *\n *\n * @module Internationalization\n * @see {@link https://github.com/openedx/frontend-base/blob/master/docs/how_tos/i18n.rst}\n * @see {@link https://formatjs.io/docs/react-intl/components/ Intl} for components exported from this module.\n *\n */\n\n/**\n * @name createIntl\n * @kind function\n * @see {@link https://formatjs.io/docs/react-intl/api#createIntl Intl}\n */\n\n/**\n * @name FormattedDate\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formatteddate Intl}\n */\n\n/**\n * @name FormattedTime\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedtime Intl}\n */\n\n/**\n * @name FormattedRelativeTime\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedrelativetime Intl}\n */\n\n/**\n * @name FormattedNumber\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattednumber Intl}\n */\n\n/**\n * @name FormattedPlural\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedplural Intl}\n */\n\n/**\n * @name FormattedMessage\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedmessage Intl}\n */\n\n/**\n * @name IntlProvider\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#intlprovider Intl}\n */\n\n/**\n * @name defineMessages\n * @kind function\n * @see {@link https://formatjs.io/docs/react-intl/api#definemessagesdefinemessage Intl}\n */\n\n/**\n * @name useIntl\n * @kind function\n * @see {@link https://formatjs.io/docs/react-intl/api#useIntl Intl}\n */\n\nexport {\n createIntl,\n defineMessages,\n FormattedDate,\n FormattedMessage,\n FormattedNumber,\n FormattedPlural,\n FormattedRelativeTime,\n FormattedTime,\n IntlProvider,\n useIntl\n} from 'react-intl';\n\nexport {\n configureI18n,\n getLocale,\n getLocalizedLanguageName,\n getMessages,\n getPrimaryLanguageSubtag,\n getSupportedLanguageList,\n handleRtl,\n intlShape,\n isRtl,\n LOCALE_CHANGED,\n LOCALE_TOPIC,\n mergeMessages,\n updateLocale\n} from './lib';\n\nexport {\n default as injectIntl\n} from './injectIntlWithShim';\n"]}
@@ -96,12 +96,6 @@ export declare function handleRtl(): void;
96
96
  * @memberof module:Internationalization
97
97
  */
98
98
  export declare function mergeMessages(newMessages?: {}): Record<string, Record<string, string> | Record<string, MessageFormatElement[]> | undefined>;
99
- /**
100
- * Adds all the messages found in the loaded apps.
101
- *
102
- * @memberof module:Internationalization
103
- */
104
- export declare function addAppMessages(): void;
105
99
  interface ConfigureI18nOptions {
106
100
  messages: LocalizedMessages[] | LocalizedMessages;
107
101
  }
@@ -206,19 +206,6 @@ export function mergeMessages(newMessages = {}) {
206
206
  messages = merge(messages, msgs);
207
207
  return messages;
208
208
  }
209
- /**
210
- * Adds all the messages found in the loaded apps.
211
- *
212
- * @memberof module:Internationalization
213
- */
214
- export function addAppMessages() {
215
- const { apps } = getSiteConfig();
216
- if (apps) {
217
- apps.forEach((app) => {
218
- mergeMessages(app.messages);
219
- });
220
- }
221
- }
222
209
  /**
223
210
  * Configures the i18n library with messages for your application.
224
211
  *
@@ -1 +1 @@
1
- {"version":3,"file":"lib.js","sourceRoot":"","sources":["../../../runtime/i18n/lib.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,cAAc,CAAC;AACjC,OAAO,SAAS,MAAM,YAAY,CAAC;AAEnC,OAAO,OAAO,MAAM,kBAAkB,CAAC;AAGvC,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,+GAA+G;AAC/G,8FAA8F;AAC9F,mDAAmD;AACnD,MAAM,UAAU,GAAG;IACjB,IAAI,EAAE,yBAAyB;IAC/B,OAAO,EAAE,gCAAgC;IACzC,OAAO,EAAE,mBAAmB;IAC5B,OAAO,EAAE,oBAAoB;IAC7B,OAAO,EAAE,mBAAmB;IAC5B,OAAO,EAAE,iBAAiB;IAC1B,OAAO,EAAE,gBAAgB;IACzB,OAAO,EAAE,kBAAkB;IAC3B,OAAO,EAAE,kBAAkB;IAC3B,OAAO,EAAE,mBAAmB;IAC5B,OAAO,EAAE,iBAAiB;IAC1B,OAAO,EAAE,mBAAmB;IAC5B,OAAO,EAAE,gBAAgB;IACzB,OAAO,EAAE,iBAAiB;IAC1B,OAAO,EAAE,wBAAwB;IACjC,OAAO,EAAE,iBAAiB;IAC1B,OAAO,EAAE,iBAAiB;IAC1B,OAAO,EAAE,mBAAmB;IAC5B,OAAO,EAAE,iBAAiB;IAC1B,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,6BAA6B;IACtC,OAAO,EAAE,iBAAiB;IAC1B,IAAI,EAAE,cAAc;IACpB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,cAAc;IACpB,IAAI,EAAE,uBAAuB;IAC7B,OAAO,EAAE,8BAA8B;IACvC,IAAI,EAAE,iBAAiB;IACvB,IAAI,EAAE,iBAAiB;IACvB,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,eAAe;IACxB,OAAO,EAAE,kBAAkB;IAC3B,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,0BAA0B;CACpC,CAAC;AAEF,IAAI,QAAqG,CAAC;AAE1G;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC;AAE1C;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,QAAQ,CAAC;AAErC;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,YAAY,UAAU,CAAC;AAExD;;;;GAIG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAI;IAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAM;IACxC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,6FAA6F,CAAC,CAAC;IACjH,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,CAAC,KAAK,SAAS,EAAE,CAAC;QACnC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,QAAQ,CAAC,wBAAwB,CAAC,MAAM,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;QAC7D,OAAO,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,SAAS,CAAC,MAAe;IACvC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,mFAAmF,CAAC,CAAC;IACvG,CAAC;IAED,kCAAkC;IAClC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IACD,4BAA4B;IAE5B,MAAM,EAAE,4BAA4B,EAAE,GAAG,aAAa,EAAE,CAAC;IACzD,IAAI,4BAA4B,EAAE,CAAC;QACjC,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QACrE,IAAI,kBAAkB,EAAE,CAAC;YACvB,OAAO,mBAAmB,CAAC,kBAAkB,CAAC,WAAW,EAAE,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,kGAAkG;IAClG,yCAAyC;IACzC,8EAA8E;IAC9E,OAAO,mBAAmB,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAAM;IAC7C,MAAM,aAAa,GAAG,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IAEzF,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACzF,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,+DAA+D;IACnF,OAAO,CAAC,IAAI,EAAE,CAAC;IAEf,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC9B,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,wBAAwB,CAAC,MAAM,CAAC;KACvC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,SAAS,EAAE,CAAC;IACZ,OAAO,CAAC,cAAc,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,MAAM,GAAG,SAAS,EAAE;IAC9C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,qFAAqF,CAAC,CAAC;IACzG,CAAC;IAED,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CAAC,MAAM;IAC1B,OAAO,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS;IACvB,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC;QACvB,UAAU,CAAC,QAAQ,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACjF,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,QAAQ,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACjF,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,WAAW,GAAG,EAAE;IAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IAClF,QAAQ,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAEjC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,EAAE,IAAI,EAAE,GAAG,aAAa,EAAE,CAAC;IACjC,IAAI,IAAI,EAAE,CAAC;QACT,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YACnB,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAMD;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAAC,OAA6B;IACzD,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IAE/F,SAAS,EAAE,CAAC;AACd,CAAC","sourcesContent":["import merge from 'lodash.merge';\nimport PropTypes from 'prop-types';\nimport { MessageFormatElement } from 'react-intl';\nimport Cookies from 'universal-cookie';\n\nimport { LocalizedMessages } from '../../types';\nimport { getSiteConfig } from '../config';\nimport { publish } from '../subscriptions';\n\nconst cookies = new Cookies();\n\n// This list is based on https://help.smartling.com/hc/en-us/articles/1260802028830-Right-to-left-RTL-Languages\n// There are very few resources available online outlining the locale codes for RTL languages;\n// If this list is inaccurate, we should change it.\nconst rtlLocales = [\n 'ar', // Arabic (International)\n 'ar-ae', // Arabic (United Arab Emirates)\n 'ar-bh', // Arabic (Bahrain)\n 'ar-dj', // Arabic (Djibouti)\n 'ar-dz', // Arabic (Algeria)\n 'ar-eg', // Arabic (Egypt)\n 'ar-iq', // Arabic (Iraq)\n 'ar-jo', // Arabic (Jordan)\n 'ar-kw', // Arabic (Kuwait)\n 'ar-lb', // Arabic (Lebanon)\n 'ar-ly', // Arabic (Libya)\n 'ar-ma', // Arabic (Morocco)\n 'ar-om', // Arabic (Oman)\n 'ar-qa', // Arabic (Qatar)\n 'ar-sa', // Arabic (Saudi Arabia)\n 'ar-sd', // Arabic (Sudan)\n 'ar-sy', // Arabic (Syria)\n 'ar-tn', // Arabic (Tunisia)\n 'ar-ye', // Arabic (Yemen)\n 'fa', // Persian\n 'fa-af', // Dari/Persian (Afghanistan)\n 'fa-ir', // Persian (Iran)\n 'he', // Hebrew (he)\n 'he-il', // Hebrew\n 'iw', // Hebrew (iw)\n 'kd', // Kurdish (Sorani) RTL\n 'pk-pk', // Panjabi-Shahmuki (Pakistan)\n 'ps', // Pushto; Pashto\n 'ug', // Uighur; Uyghur\n 'ur', // Urdu\n 'ur-in', // Urdu (India)\n 'ur-pk', // Urdu (Pakistan)\n 'yi', // Yiddish\n 'yi-us', // Yiddish (United States)\n];\n\nlet messages: Record<string, Record<string, string> | Record<string, MessageFormatElement[]> | undefined>;\n\n/**\n * @memberof module:Internationalization\n *\n * Prior versions of react-intl (our primary implementation of the i18n service) included a\n * PropTypes-based 'shape' for its `intl` object. This has since been removed. For legacy\n * compatibility, we include an `intlShape` export that is set to PropTypes.object. Usage of this\n * export is deprecated.\n *\n * @deprecated\n */\nexport const intlShape = PropTypes.object;\n\n/**\n * @memberof module:Internationalization\n */\nexport const LOCALE_TOPIC = 'LOCALE';\n\n/**\n * @memberof module:Internationalization\n */\nexport const LOCALE_CHANGED = `${LOCALE_TOPIC}.CHANGED`;\n\n/**\n *\n * @memberof module:Internationalization\n * @returns {Cookies}\n */\nexport function getCookies() {\n return cookies;\n}\n\n/**\n * Some of our dependencies function on primary language subtags, rather than full locales.\n * This function strips a locale down to that first subtag. Depending on the code, this\n * may be 2 or more characters.\n *\n * @param {string} code\n * @memberof module:Internationalization\n */\nexport function getPrimaryLanguageSubtag(code) {\n return code.split('-')[0];\n}\n\n/**\n * Finds the closest supported locale to the one provided. This is done in three steps:\n *\n * 1. Returning the locale itself if its exact language code is supported.\n * 2. Returning the primary language subtag of the language code if it is supported (ar for ar-eg,\n * for instance).\n * 3. Returning 'en' if neither of the above produce a supported locale.\n *\n * @param {string} locale\n * @returns {string}\n * @memberof module:Internationalization\n */\nexport function findSupportedLocale(locale) {\n if (messages === undefined) {\n throw new Error('findSupportedLocale called before configuring i18n. Call configureI18n with messages first.');\n }\n\n if (messages[locale] !== undefined) {\n return locale;\n }\n\n if (messages[getPrimaryLanguageSubtag(locale)] !== undefined) {\n return getPrimaryLanguageSubtag(locale);\n }\n\n return 'en';\n}\n\n/**\n * Get the locale from the cookie or, failing that, the browser setting.\n * Gracefully fall back to a more general primary language subtag or to English (en)\n * if we don't support that language.\n *\n * @param {string|undefined} locale If a locale is provided, returns the closest supported locale. Optional.\n * @throws An error if i18n has not yet been configured.\n * @returns {string}\n * @memberof module:Internationalization\n */\nexport function getLocale(locale?: string) {\n if (messages === null) {\n throw new Error('getLocale called before configuring i18n. Call configureI18n with messages first.');\n }\n\n // 1. Explicit application request\n if (locale !== undefined) {\n return findSupportedLocale(locale);\n }\n // 2. User setting in cookie\n\n const { languagePreferenceCookieName } = getSiteConfig();\n if (languagePreferenceCookieName) {\n const languagePreference = cookies.get(languagePreferenceCookieName);\n if (languagePreference) {\n return findSupportedLocale(languagePreference.toLowerCase());\n }\n }\n\n // 3. Browser language (default)\n // Note that some browers prefer upper case for the region part of the locale, while others don't.\n // Thus the toLowerCase, for consistency.\n // https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/language\n return findSupportedLocale(globalThis.navigator.language.toLowerCase());\n}\n\nexport function getLocalizedLanguageName(locale) {\n const localizedName = (new Intl.DisplayNames([locale], { type: 'language' })).of(locale);\n\n if (localizedName === undefined) {\n throw new Error(`Unsupported locale: ${locale}`);\n }\n\n return `${localizedName.charAt(0).toLocaleUpperCase(locale)}${localizedName.slice(1)}`;\n}\n\nexport function getSupportedLanguageList() {\n const locales = Object.keys(messages);\n locales.push('en'); // 'en' is not in the messages object because it's the default.\n locales.sort();\n\n return locales.map((locale) => ({\n code: locale,\n name: getLocalizedLanguageName(locale),\n }));\n}\n\nexport function updateLocale() {\n handleRtl();\n publish(LOCALE_CHANGED);\n}\n\n/**\n * Returns messages for the provided locale, or the user's preferred locale if no argument is\n * provided.\n *\n * @param {string} [locale=getLocale()]\n * @memberof module:Internationalization\n */\nexport function getMessages(locale = getLocale()) {\n if (messages === undefined) {\n throw new Error('getMessages called before configuring i18n. Call configureI18n with messages first.');\n }\n\n return messages[locale];\n}\n\n/**\n * Determines if the provided locale is a right-to-left language.\n *\n * @param {string} locale\n * @memberof module:Internationalization\n */\nexport function isRtl(locale) {\n return rtlLocales.includes(locale);\n}\n\n/**\n * Handles applying the RTL stylesheet and \"dir=rtl\" attribute to the html tag if the current locale\n * is a RTL language.\n *\n * @memberof module:Internationalization\n */\nexport function handleRtl() {\n if (isRtl(getLocale())) {\n globalThis.document.getElementsByTagName('html')[0].setAttribute('dir', 'rtl');\n } else {\n globalThis.document.getElementsByTagName('html')[0].setAttribute('dir', 'ltr');\n }\n}\n\n/**\n *\n *\n * @param {Object} newMessages\n * @returns {Object}\n * @memberof module:Internationalization\n */\nexport function mergeMessages(newMessages = {}) {\n const msgs = Array.isArray(newMessages) ? merge({}, ...newMessages) : newMessages;\n messages = merge(messages, msgs);\n\n return messages;\n}\n\n/**\n * Adds all the messages found in the loaded apps.\n *\n * @memberof module:Internationalization\n */\nexport function addAppMessages() {\n const { apps } = getSiteConfig();\n if (apps) {\n apps.forEach((app) => {\n mergeMessages(app.messages);\n });\n }\n}\n\ninterface ConfigureI18nOptions {\n messages: LocalizedMessages[] | LocalizedMessages,\n}\n\n/**\n * Configures the i18n library with messages for your application.\n *\n * Logs a warning if it detects a locale it doesn't expect (as defined by the supportedLocales list\n * above), or if an expected locale is not provided.\n *\n * @param {Object} options\n * @param {Object} options.messages\n * @memberof module:Internationalization\n */\nexport function configureI18n(options: ConfigureI18nOptions) {\n messages = Array.isArray(options.messages) ? merge({}, ...options.messages) : options.messages;\n\n handleRtl();\n}\n"]}
1
+ {"version":3,"file":"lib.js","sourceRoot":"","sources":["../../../runtime/i18n/lib.ts"],"names":[],"mappings":"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","sourcesContent":["import merge from 'lodash.merge';\nimport PropTypes from 'prop-types';\nimport { MessageFormatElement } from 'react-intl';\nimport Cookies from 'universal-cookie';\n\nimport { LocalizedMessages } from '../../types';\nimport { getSiteConfig } from '../config';\nimport { publish } from '../subscriptions';\n\nconst cookies = new Cookies();\n\n// This list is based on https://help.smartling.com/hc/en-us/articles/1260802028830-Right-to-left-RTL-Languages\n// There are very few resources available online outlining the locale codes for RTL languages;\n// If this list is inaccurate, we should change it.\nconst rtlLocales = [\n 'ar', // Arabic (International)\n 'ar-ae', // Arabic (United Arab Emirates)\n 'ar-bh', // Arabic (Bahrain)\n 'ar-dj', // Arabic (Djibouti)\n 'ar-dz', // Arabic (Algeria)\n 'ar-eg', // Arabic (Egypt)\n 'ar-iq', // Arabic (Iraq)\n 'ar-jo', // Arabic (Jordan)\n 'ar-kw', // Arabic (Kuwait)\n 'ar-lb', // Arabic (Lebanon)\n 'ar-ly', // Arabic (Libya)\n 'ar-ma', // Arabic (Morocco)\n 'ar-om', // Arabic (Oman)\n 'ar-qa', // Arabic (Qatar)\n 'ar-sa', // Arabic (Saudi Arabia)\n 'ar-sd', // Arabic (Sudan)\n 'ar-sy', // Arabic (Syria)\n 'ar-tn', // Arabic (Tunisia)\n 'ar-ye', // Arabic (Yemen)\n 'fa', // Persian\n 'fa-af', // Dari/Persian (Afghanistan)\n 'fa-ir', // Persian (Iran)\n 'he', // Hebrew (he)\n 'he-il', // Hebrew\n 'iw', // Hebrew (iw)\n 'kd', // Kurdish (Sorani) RTL\n 'pk-pk', // Panjabi-Shahmuki (Pakistan)\n 'ps', // Pushto; Pashto\n 'ug', // Uighur; Uyghur\n 'ur', // Urdu\n 'ur-in', // Urdu (India)\n 'ur-pk', // Urdu (Pakistan)\n 'yi', // Yiddish\n 'yi-us', // Yiddish (United States)\n];\n\nlet messages: Record<string, Record<string, string> | Record<string, MessageFormatElement[]> | undefined>;\n\n/**\n * @memberof module:Internationalization\n *\n * Prior versions of react-intl (our primary implementation of the i18n service) included a\n * PropTypes-based 'shape' for its `intl` object. This has since been removed. For legacy\n * compatibility, we include an `intlShape` export that is set to PropTypes.object. Usage of this\n * export is deprecated.\n *\n * @deprecated\n */\nexport const intlShape = PropTypes.object;\n\n/**\n * @memberof module:Internationalization\n */\nexport const LOCALE_TOPIC = 'LOCALE';\n\n/**\n * @memberof module:Internationalization\n */\nexport const LOCALE_CHANGED = `${LOCALE_TOPIC}.CHANGED`;\n\n/**\n *\n * @memberof module:Internationalization\n * @returns {Cookies}\n */\nexport function getCookies() {\n return cookies;\n}\n\n/**\n * Some of our dependencies function on primary language subtags, rather than full locales.\n * This function strips a locale down to that first subtag. Depending on the code, this\n * may be 2 or more characters.\n *\n * @param {string} code\n * @memberof module:Internationalization\n */\nexport function getPrimaryLanguageSubtag(code) {\n return code.split('-')[0];\n}\n\n/**\n * Finds the closest supported locale to the one provided. This is done in three steps:\n *\n * 1. Returning the locale itself if its exact language code is supported.\n * 2. Returning the primary language subtag of the language code if it is supported (ar for ar-eg,\n * for instance).\n * 3. Returning 'en' if neither of the above produce a supported locale.\n *\n * @param {string} locale\n * @returns {string}\n * @memberof module:Internationalization\n */\nexport function findSupportedLocale(locale) {\n if (messages === undefined) {\n throw new Error('findSupportedLocale called before configuring i18n. Call configureI18n with messages first.');\n }\n\n if (messages[locale] !== undefined) {\n return locale;\n }\n\n if (messages[getPrimaryLanguageSubtag(locale)] !== undefined) {\n return getPrimaryLanguageSubtag(locale);\n }\n\n return 'en';\n}\n\n/**\n * Get the locale from the cookie or, failing that, the browser setting.\n * Gracefully fall back to a more general primary language subtag or to English (en)\n * if we don't support that language.\n *\n * @param {string|undefined} locale If a locale is provided, returns the closest supported locale. Optional.\n * @throws An error if i18n has not yet been configured.\n * @returns {string}\n * @memberof module:Internationalization\n */\nexport function getLocale(locale?: string) {\n if (messages === null) {\n throw new Error('getLocale called before configuring i18n. Call configureI18n with messages first.');\n }\n\n // 1. Explicit application request\n if (locale !== undefined) {\n return findSupportedLocale(locale);\n }\n // 2. User setting in cookie\n\n const { languagePreferenceCookieName } = getSiteConfig();\n if (languagePreferenceCookieName) {\n const languagePreference = cookies.get(languagePreferenceCookieName);\n if (languagePreference) {\n return findSupportedLocale(languagePreference.toLowerCase());\n }\n }\n\n // 3. Browser language (default)\n // Note that some browers prefer upper case for the region part of the locale, while others don't.\n // Thus the toLowerCase, for consistency.\n // https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/language\n return findSupportedLocale(globalThis.navigator.language.toLowerCase());\n}\n\nexport function getLocalizedLanguageName(locale) {\n const localizedName = (new Intl.DisplayNames([locale], { type: 'language' })).of(locale);\n\n if (localizedName === undefined) {\n throw new Error(`Unsupported locale: ${locale}`);\n }\n\n return `${localizedName.charAt(0).toLocaleUpperCase(locale)}${localizedName.slice(1)}`;\n}\n\nexport function getSupportedLanguageList() {\n const locales = Object.keys(messages);\n locales.push('en'); // 'en' is not in the messages object because it's the default.\n locales.sort();\n\n return locales.map((locale) => ({\n code: locale,\n name: getLocalizedLanguageName(locale),\n }));\n}\n\nexport function updateLocale() {\n handleRtl();\n publish(LOCALE_CHANGED);\n}\n\n/**\n * Returns messages for the provided locale, or the user's preferred locale if no argument is\n * provided.\n *\n * @param {string} [locale=getLocale()]\n * @memberof module:Internationalization\n */\nexport function getMessages(locale = getLocale()) {\n if (messages === undefined) {\n throw new Error('getMessages called before configuring i18n. Call configureI18n with messages first.');\n }\n\n return messages[locale];\n}\n\n/**\n * Determines if the provided locale is a right-to-left language.\n *\n * @param {string} locale\n * @memberof module:Internationalization\n */\nexport function isRtl(locale) {\n return rtlLocales.includes(locale);\n}\n\n/**\n * Handles applying the RTL stylesheet and \"dir=rtl\" attribute to the html tag if the current locale\n * is a RTL language.\n *\n * @memberof module:Internationalization\n */\nexport function handleRtl() {\n if (isRtl(getLocale())) {\n globalThis.document.getElementsByTagName('html')[0].setAttribute('dir', 'rtl');\n } else {\n globalThis.document.getElementsByTagName('html')[0].setAttribute('dir', 'ltr');\n }\n}\n\n/**\n *\n *\n * @param {Object} newMessages\n * @returns {Object}\n * @memberof module:Internationalization\n */\nexport function mergeMessages(newMessages = {}) {\n const msgs = Array.isArray(newMessages) ? merge({}, ...newMessages) : newMessages;\n messages = merge(messages, msgs);\n\n return messages;\n}\n\ninterface ConfigureI18nOptions {\n messages: LocalizedMessages[] | LocalizedMessages,\n}\n\n/**\n * Configures the i18n library with messages for your application.\n *\n * Logs a warning if it detects a locale it doesn't expect (as defined by the supportedLocales list\n * above), or if an expected locale is not provided.\n *\n * @param {Object} options\n * @param {Object} options.messages\n * @memberof module:Internationalization\n */\nexport function configureI18n(options: ConfigureI18nOptions) {\n messages = Array.isArray(options.messages) ? merge({}, ...options.messages) : options.messages;\n\n handleRtl();\n}\n"]}
@@ -1,5 +1,4 @@
1
1
  import HomePage from './HomePage';
2
- import messages from './i18n';
3
2
  const app = {
4
3
  appId: 'org.openedx.frontend.app.dev.home',
5
4
  routes: [{
@@ -10,7 +9,6 @@ const app = {
10
9
  role: 'org.openedx.frontend.role.devHome'
11
10
  }
12
11
  }],
13
- messages,
14
12
  };
15
13
  export default app;
16
14
  //# sourceMappingURL=app.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../shell/dev/devHome/app.ts"],"names":[],"mappings":"AACA,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,QAAQ,MAAM,QAAQ,CAAC;AAE9B,MAAM,GAAG,GAAQ;IACf,KAAK,EAAE,mCAAmC;IAC1C,MAAM,EAAE,CAAC;YACP,IAAI,EAAE,GAAG;YACT,EAAE,EAAE,qCAAqC;YACzC,SAAS,EAAE,QAAQ;YACnB,MAAM,EAAE;gBACN,IAAI,EAAE,mCAAmC;aAC1C;SACF,CAAC;IACF,QAAQ;CACT,CAAC;AAEF,eAAe,GAAG,CAAC","sourcesContent":["import { App } from '../../../types';\nimport HomePage from './HomePage';\nimport messages from './i18n';\n\nconst app: App = {\n appId: 'org.openedx.frontend.app.dev.home',\n routes: [{\n path: '/',\n id: 'org.openedx.frontend.route.dev.home',\n Component: HomePage,\n handle: {\n role: 'org.openedx.frontend.role.devHome'\n }\n }],\n messages,\n};\n\nexport default app;\n"]}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../shell/dev/devHome/app.ts"],"names":[],"mappings":"AACA,OAAO,QAAQ,MAAM,YAAY,CAAC;AAElC,MAAM,GAAG,GAAQ;IACf,KAAK,EAAE,mCAAmC;IAC1C,MAAM,EAAE,CAAC;YACP,IAAI,EAAE,GAAG;YACT,EAAE,EAAE,qCAAqC;YACzC,SAAS,EAAE,QAAQ;YACnB,MAAM,EAAE;gBACN,IAAI,EAAE,mCAAmC;aAC1C;SACF,CAAC;CACH,CAAC;AAEF,eAAe,GAAG,CAAC","sourcesContent":["import { App } from '../../../types';\nimport HomePage from './HomePage';\n\nconst app: App = {\n appId: 'org.openedx.frontend.app.dev.home',\n routes: [{\n path: '/',\n id: 'org.openedx.frontend.route.dev.home',\n Component: HomePage,\n handle: {\n role: 'org.openedx.frontend.role.devHome'\n }\n }],\n};\n\nexport default app;\n"]}
@@ -14,14 +14,12 @@ import { RouterProvider } from 'react-router-dom';
14
14
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
15
15
  import { SITE_INIT_ERROR, SITE_READY, initialize, subscribe } from '../runtime';
16
16
  import { addAppConfigs } from '../runtime/config';
17
- import { addAppMessages } from '../runtime/i18n';
18
- import messages from './i18n';
17
+ import messages from 'site.i18n';
19
18
  import createRouter from './router/createRouter';
20
19
  subscribe(SITE_READY, () => __awaiter(void 0, void 0, void 0, function* () {
21
20
  const queryClient = new QueryClient();
22
21
  const router = createRouter();
23
22
  addAppConfigs();
24
- addAppMessages();
25
23
  const root = createRoot(document.getElementById('root'));
26
24
  root.render(_jsx(StrictMode, { children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx(RouterProvider, { router: router }) }) }));
27
25
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"site.js","sourceRoot":"","sources":["../../shell/site.tsx"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEzE,OAAO,EACL,eAAe,EACf,UAAU,EACV,UAAU,EACV,SAAS,EACV,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,QAAQ,MAAM,QAAQ,CAAC;AAC9B,OAAO,YAAY,MAAM,uBAAuB,CAAC;AAEjD,SAAS,CAAC,UAAU,EAAE,GAAS,EAAE;IAC/B,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAE9B,aAAa,EAAE,CAAC;IAChB,cAAc,EAAE,CAAC;IAEjB,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAgB,CAAC,CAAC;IACxE,IAAI,CAAC,MAAM,CACT,KAAC,UAAU,cACT,KAAC,mBAAmB,IAAC,MAAM,EAAE,WAAW,YACtC,KAAC,cAAc,IAAC,MAAM,EAAE,MAAM,GAAI,GACd,GACX,CACd,CAAC;AACJ,CAAC,CAAA,CAAC,CAAC;AAEH,SAAS,CAAC,eAAe,EAAE,CAAC,KAAK,EAAE,EAAE;IACnC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAgB,CAAC,CAAC;IACxE,IAAI,CAAC,MAAM,CAAC,wBAAM,KAAK,CAAC,OAAO,GAAO,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEH,UAAU,CAAC;IACT,QAAQ;CACT,CAAC,CAAC","sourcesContent":["import { StrictMode } from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { RouterProvider } from 'react-router-dom';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\n\nimport {\n SITE_INIT_ERROR,\n SITE_READY,\n initialize,\n subscribe\n} from '../runtime';\nimport { addAppConfigs } from '../runtime/config';\nimport { addAppMessages } from '../runtime/i18n';\nimport messages from './i18n';\nimport createRouter from './router/createRouter';\n\nsubscribe(SITE_READY, async () => {\n const queryClient = new QueryClient();\n const router = createRouter();\n\n addAppConfigs();\n addAppMessages();\n\n const root = createRoot(document.getElementById('root') as HTMLElement);\n root.render(\n <StrictMode>\n <QueryClientProvider client={queryClient}>\n <RouterProvider router={router} />\n </QueryClientProvider>\n </StrictMode>\n );\n});\n\nsubscribe(SITE_INIT_ERROR, (error) => {\n const root = createRoot(document.getElementById('root') as HTMLElement);\n root.render(<div>{error.message}</div>);\n});\n\ninitialize({\n messages,\n});\n"]}
1
+ {"version":3,"file":"site.js","sourceRoot":"","sources":["../../shell/site.tsx"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEzE,OAAO,EACL,eAAe,EACf,UAAU,EACV,UAAU,EACV,SAAS,EACV,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,YAAY,MAAM,uBAAuB,CAAC;AAEjD,SAAS,CAAC,UAAU,EAAE,GAAS,EAAE;IAC/B,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAE9B,aAAa,EAAE,CAAC;IAEhB,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAgB,CAAC,CAAC;IACxE,IAAI,CAAC,MAAM,CACT,KAAC,UAAU,cACT,KAAC,mBAAmB,IAAC,MAAM,EAAE,WAAW,YACtC,KAAC,cAAc,IAAC,MAAM,EAAE,MAAM,GAAI,GACd,GACX,CACd,CAAC;AACJ,CAAC,CAAA,CAAC,CAAC;AAEH,SAAS,CAAC,eAAe,EAAE,CAAC,KAAK,EAAE,EAAE;IACnC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAgB,CAAC,CAAC;IACxE,IAAI,CAAC,MAAM,CAAC,wBAAM,KAAK,CAAC,OAAO,GAAO,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEH,UAAU,CAAC;IACT,QAAQ;CACT,CAAC,CAAC","sourcesContent":["import { StrictMode } from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { RouterProvider } from 'react-router-dom';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\n\nimport {\n SITE_INIT_ERROR,\n SITE_READY,\n initialize,\n subscribe\n} from '../runtime';\nimport { addAppConfigs } from '../runtime/config';\nimport messages from 'site.i18n';\nimport createRouter from './router/createRouter';\n\nsubscribe(SITE_READY, async () => {\n const queryClient = new QueryClient();\n const router = createRouter();\n\n addAppConfigs();\n\n const root = createRoot(document.getElementById('root') as HTMLElement);\n root.render(\n <StrictMode>\n <QueryClientProvider client={queryClient}>\n <RouterProvider router={router} />\n </QueryClientProvider>\n </StrictMode>\n );\n});\n\nsubscribe(SITE_INIT_ERROR, (error) => {\n const root = createRoot(document.getElementById('root') as HTMLElement);\n root.render(<div>{error.message}</div>);\n});\n\ninitialize({\n messages,\n});\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function runPrepare(): void;
2
+ export declare function runPull(): void;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runPrepare = runPrepare;
7
+ exports.runPull = runPull;
8
+ const child_process_1 = __importDefault(require("child_process"));
9
+ const translations_1 = require("../utils/translations");
10
+ function runPrepare() {
11
+ (0, translations_1.prepare)({ siteRoot: process.cwd() });
12
+ }
13
+ function runPull() {
14
+ (0, translations_1.pull)({
15
+ siteRoot: process.cwd(),
16
+ execFileSync: (file, args) => child_process_1.default.execFileSync(file, args, { stdio: 'inherit' }),
17
+ shouldPrepare: !process.argv.includes('--no-prepare'),
18
+ atlasOptions: process.argv.find(a => a.startsWith('--atlas-options='))?.slice('--atlas-options='.length),
19
+ });
20
+ }
@@ -95,6 +95,12 @@ switch (commandName) {
95
95
  case types_1.CommandTypes.SERVE:
96
96
  require('./commands/serve');
97
97
  break;
98
+ case types_1.CommandTypes.TRANSLATIONS_PULL:
99
+ require('./commands/translations').runPull();
100
+ break;
101
+ case types_1.CommandTypes.TRANSLATIONS_PREPARE:
102
+ require('./commands/translations').runPrepare();
103
+ break;
98
104
  case types_1.CommandTypes.HELP:
99
105
  (0, printUsage_1.default)();
100
106
  break;
@@ -35,5 +35,13 @@ function printUsage() {
35
35
  console.group();
36
36
  console.log(`Serves the dist folder with an express server. Used to locally test production assets.\n`);
37
37
  console.groupEnd();
38
+ console.log(`${chalk_1.default.bold('translations:pull')}\n`);
39
+ console.group();
40
+ console.log(`Pulls translations for all installed apps using atlas, then runs translations:prepare. Reads atlasTranslations config from package.json. Pass ${chalk_1.default.bold('--no-prepare')} to skip the prepare step.\n`);
41
+ console.groupEnd();
42
+ console.log(`${chalk_1.default.bold('translations:prepare')}\n`);
43
+ console.group();
44
+ console.log(`Generates TypeScript modules from pulled translation JSON files in src/i18n/messages/ and src/i18n/site-messages/.\n`);
45
+ console.groupEnd();
38
46
  console.groupEnd();
39
47
  }
@@ -0,0 +1,2 @@
1
+ export { prepare } from './prepare';
2
+ export { pull } from './pull';
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pull = exports.prepare = void 0;
4
+ var prepare_1 = require("./prepare");
5
+ Object.defineProperty(exports, "prepare", { enumerable: true, get: function () { return prepare_1.prepare; } });
6
+ var pull_1 = require("./pull");
7
+ Object.defineProperty(exports, "pull", { enumerable: true, get: function () { return pull_1.pull; } });
@@ -0,0 +1,26 @@
1
+ export interface LocaleImport {
2
+ localeName: string;
3
+ filename: string;
4
+ }
5
+ export interface LocaleEntry {
6
+ key: string;
7
+ varName: string;
8
+ }
9
+ export interface MessagesObject {
10
+ imports: LocaleImport[];
11
+ entries: LocaleEntry[];
12
+ }
13
+ /**
14
+ * Reads all locale JSON files in a directory and returns the data needed to
15
+ * render a messages object ({ 'ar': ar, 'es-419': es_419 }).
16
+ * Returns null if no non-empty JSON files are found.
17
+ */
18
+ export declare function generateMessagesObject(dirPath: string): MessagesObject | null;
19
+ export declare function renderImportLine({ localeName, filename }: LocaleImport): string;
20
+ export declare function renderImportsBlock(messagesObject: MessagesObject): string;
21
+ export declare function renderExportLine({ key, varName }: LocaleEntry): string;
22
+ export declare function renderExportBlock(messagesObject: MessagesObject): string;
23
+ /**
24
+ * Renders a MessagesObject and writes it to an index.ts file in the given directory.
25
+ */
26
+ export declare function writeMessagesObjectToFile(dirPath: string, messagesObject: MessagesObject): void;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateMessagesObject = generateMessagesObject;
7
+ exports.renderImportLine = renderImportLine;
8
+ exports.renderImportsBlock = renderImportsBlock;
9
+ exports.renderExportLine = renderExportLine;
10
+ exports.renderExportBlock = renderExportBlock;
11
+ exports.writeMessagesObjectToFile = writeMessagesObjectToFile;
12
+ const fs_1 = __importDefault(require("fs"));
13
+ const path_1 = __importDefault(require("path"));
14
+ /**
15
+ * Reads all locale JSON files in a directory and returns the data needed to
16
+ * render a messages object ({ 'ar': ar, 'es-419': es_419 }).
17
+ * Returns null if no non-empty JSON files are found.
18
+ */
19
+ function generateMessagesObject(dirPath) {
20
+ const dirEntries = fs_1.default.readdirSync(dirPath, { withFileTypes: true });
21
+ const jsonFiles = dirEntries
22
+ .filter(e => e.isFile() && e.name.endsWith('.json'))
23
+ .map(e => e.name);
24
+ const imports = [];
25
+ const entries = [];
26
+ for (const filename of jsonFiles) {
27
+ const localeName = filename.replace(/\.json$/, '');
28
+ const key = localeName.toLowerCase().replace(/_/g, '-');
29
+ const filePath = path_1.default.join(dirPath, filename);
30
+ try {
31
+ const parsed = JSON.parse(fs_1.default.readFileSync(filePath, { encoding: 'utf8' }));
32
+ if (!Object.keys(parsed).length) {
33
+ continue; // skip empty files
34
+ }
35
+ }
36
+ catch {
37
+ continue;
38
+ }
39
+ imports.push({ localeName, filename });
40
+ entries.push({ key, varName: localeName });
41
+ }
42
+ if (!imports.length) {
43
+ return null;
44
+ }
45
+ return { imports, entries };
46
+ }
47
+ function renderImportLine({ localeName, filename }) {
48
+ return `import ${localeName} from './${filename}';`;
49
+ }
50
+ function renderImportsBlock(messagesObject) {
51
+ return messagesObject.imports.map(renderImportLine).join('\n');
52
+ }
53
+ function renderExportLine({ key, varName }) {
54
+ return ` '${key}': ${varName},`;
55
+ }
56
+ function renderExportBlock(messagesObject) {
57
+ const lines = messagesObject.entries.map(renderExportLine).join('\n');
58
+ return `export default {\n${lines}\n};\n`;
59
+ }
60
+ /**
61
+ * Renders a MessagesObject and writes it to an index.ts file in the given directory.
62
+ */
63
+ function writeMessagesObjectToFile(dirPath, messagesObject) {
64
+ const content = `${renderImportsBlock(messagesObject)}\n\n${renderExportBlock(messagesObject)}`;
65
+ fs_1.default.writeFileSync(path_1.default.join(dirPath, 'index.ts'), content);
66
+ }
@@ -0,0 +1,5 @@
1
+ export declare function prepareAllPackageMessages(messagesDir: string): [string[], string[]];
2
+ export declare function prepareSiteMessages(siteMessagesDir: string): [string[], string[]];
3
+ export declare function prepare({ siteRoot }: {
4
+ siteRoot: string;
5
+ }): void;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.prepareAllPackageMessages = prepareAllPackageMessages;
7
+ exports.prepareSiteMessages = prepareSiteMessages;
8
+ exports.prepare = prepare;
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const lodash_camelcase_1 = __importDefault(require("lodash.camelcase"));
11
+ const path_1 = __importDefault(require("path"));
12
+ const messagesObject_1 = require("./messagesObject");
13
+ function packageVarName(packagePath) {
14
+ const name = packagePath.split('/').pop();
15
+ return `${(0, lodash_camelcase_1.default)(name)}Messages`;
16
+ }
17
+ function getPackageMessages(messagesDir, packagePath) {
18
+ return (0, messagesObject_1.generateMessagesObject)(path_1.default.join(messagesDir, packagePath));
19
+ }
20
+ function getPackagePaths(messagesDir) {
21
+ const directoryEntries = fs_1.default.readdirSync(messagesDir, { withFileTypes: true })
22
+ .filter(e => e.isDirectory());
23
+ const packagePaths = [];
24
+ for (const entry of directoryEntries) {
25
+ const directory = fs_1.default.readdirSync(path_1.default.join(messagesDir, entry.name), { withFileTypes: true });
26
+ if (!directory.some(e => e.isDirectory())) {
27
+ // no subdirectories, this is a package dir
28
+ packagePaths.push(entry.name);
29
+ continue;
30
+ }
31
+ // this is a scope dir, subdirs are packages
32
+ const packageDirs = directory.filter(e => e.isDirectory());
33
+ for (const pkg of packageDirs) {
34
+ packagePaths.push(`${entry.name}/${pkg.name}`);
35
+ }
36
+ }
37
+ return packagePaths;
38
+ }
39
+ function getAllPackageMessages(messagesDir) {
40
+ if (!fs_1.default.existsSync(messagesDir)) {
41
+ // directory doesn't exist
42
+ return new Map();
43
+ }
44
+ const directory = fs_1.default.readdirSync(messagesDir, { withFileTypes: true });
45
+ if (!directory.some(e => e.isDirectory())) {
46
+ // directory exists but has no subdirectories
47
+ return new Map();
48
+ }
49
+ const packagePaths = getPackagePaths(messagesDir);
50
+ const result = new Map();
51
+ for (const packagePath of packagePaths) {
52
+ const messagesObject = getPackageMessages(messagesDir, packagePath);
53
+ if (messagesObject) {
54
+ result.set(packagePath, messagesObject);
55
+ }
56
+ }
57
+ return result;
58
+ }
59
+ function prepareAllPackageMessages(messagesDir) {
60
+ const packageMessages = getAllPackageMessages(messagesDir);
61
+ const importLines = [];
62
+ const exportItems = [];
63
+ for (const [packagePath, messagesObject] of packageMessages) {
64
+ (0, messagesObject_1.writeMessagesObjectToFile)(path_1.default.join(messagesDir, packagePath), messagesObject);
65
+ const varName = packageVarName(packagePath);
66
+ importLines.push(`import ${varName} from './messages/${packagePath}';`);
67
+ exportItems.push(` ${varName},`);
68
+ }
69
+ return [importLines, exportItems];
70
+ }
71
+ function prepareSiteMessages(siteMessagesDir) {
72
+ const siteMessages = fs_1.default.existsSync(siteMessagesDir)
73
+ ? (0, messagesObject_1.generateMessagesObject)(siteMessagesDir)
74
+ : null;
75
+ if (!siteMessages) {
76
+ return [[], []];
77
+ }
78
+ (0, messagesObject_1.writeMessagesObjectToFile)(siteMessagesDir, siteMessages);
79
+ return [
80
+ [`import siteMessages from './site-messages';`],
81
+ [` siteMessages,`],
82
+ ];
83
+ }
84
+ function prepare({ siteRoot }) {
85
+ const i18nDir = path_1.default.join(siteRoot, 'src', 'i18n');
86
+ const messagesDir = path_1.default.join(i18nDir, 'messages');
87
+ const siteMessagesDir = path_1.default.join(i18nDir, 'site-messages');
88
+ const [packageImportLines, packageExportItems] = prepareAllPackageMessages(messagesDir);
89
+ const [siteImportLines, siteExportItems] = prepareSiteMessages(siteMessagesDir);
90
+ const importLines = [...packageImportLines, ...siteImportLines];
91
+ const exportItems = [...packageExportItems, ...siteExportItems];
92
+ const hasMessages = importLines.length > 0 && exportItems.length > 0;
93
+ const messagesContent = hasMessages
94
+ ? `${importLines.join('\n')}\n\nexport default [\n${exportItems.join('\n')}\n];\n`
95
+ : 'export default [];\n';
96
+ fs_1.default.mkdirSync(i18nDir, { recursive: true });
97
+ fs_1.default.writeFileSync(path_1.default.join(i18nDir, 'messages.ts'), messagesContent);
98
+ }
@@ -0,0 +1,6 @@
1
+ export declare function pull({ siteRoot, execFileSync, shouldPrepare, atlasOptions, }: {
2
+ siteRoot: string;
3
+ execFileSync: (file: string, args: string[]) => void;
4
+ shouldPrepare: boolean;
5
+ atlasOptions?: string;
6
+ }): void;
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.pull = pull;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const prepare_1 = require("./prepare");
10
+ function validateSiteTranslationsConfig(siteRoot) {
11
+ const pkgJsonPath = path_1.default.join(siteRoot, 'package.json');
12
+ let config;
13
+ try {
14
+ config = JSON.parse(fs_1.default.readFileSync(pkgJsonPath, { encoding: 'utf8' }));
15
+ }
16
+ catch {
17
+ throw new Error(`translations:pull: Could not read ${pkgJsonPath}`);
18
+ }
19
+ if (!config.atlasTranslations) {
20
+ throw new Error(`translations:pull: No atlasTranslations field in ${pkgJsonPath}. `
21
+ + 'Add an atlasTranslations config to enable translation pulling.');
22
+ }
23
+ if (config.atlasTranslations.path && !config.name) {
24
+ throw new Error(`translations:pull: atlasTranslations.path is set in ${pkgJsonPath} but there is no name field. `
25
+ + 'A name field is required to identify this package as a translation source.');
26
+ }
27
+ }
28
+ function readTranslationsConfig(pkgJsonPath, nodeModulesBase) {
29
+ const packageName = path_1.default.relative(nodeModulesBase, path_1.default.dirname(pkgJsonPath));
30
+ if (!fs_1.default.existsSync(pkgJsonPath)) {
31
+ console.warn(`translations:pull: Package ${packageName} not found in node_modules, skipping.`);
32
+ return null;
33
+ }
34
+ let config;
35
+ try {
36
+ config = JSON.parse(fs_1.default.readFileSync(pkgJsonPath, { encoding: 'utf8' }));
37
+ }
38
+ catch {
39
+ console.warn(`translations:pull: Error reading package.json for ${packageName}, skipping.`);
40
+ return null;
41
+ }
42
+ const resolvedPackageName = config.name ?? packageName;
43
+ if (!config.atlasTranslations) {
44
+ console.warn(`translations:pull: No atlasTranslations config in ${resolvedPackageName}, skipping.`);
45
+ return null;
46
+ }
47
+ return { packageName: resolvedPackageName, config };
48
+ }
49
+ function resolveTranslationMappings(pkgJsonPath, nodeModulesBase) {
50
+ const visited = new Set();
51
+ function resolve(pkgJsonPath, ancestors) {
52
+ const read = readTranslationsConfig(pkgJsonPath, nodeModulesBase);
53
+ if (!read)
54
+ return [];
55
+ const { packageName, config } = read;
56
+ if (ancestors.includes(packageName)) {
57
+ console.warn(`translations:pull: Circular dependency detected: ${[...ancestors, packageName].join(' → ')}, skipping.`);
58
+ return [];
59
+ }
60
+ if (visited.has(packageName)) {
61
+ return [];
62
+ }
63
+ visited.add(packageName);
64
+ const results = [];
65
+ const mapping = config.atlasTranslations?.path
66
+ ? { from: config.atlasTranslations.path, to: packageName }
67
+ : null;
68
+ if (mapping) {
69
+ results.push(mapping);
70
+ }
71
+ const dependencies = config.atlasTranslations?.dependencies ?? [];
72
+ for (const dep of dependencies) {
73
+ results.push(...resolve(path_1.default.join(nodeModulesBase, dep, 'package.json'), [...ancestors, packageName]));
74
+ }
75
+ return results;
76
+ }
77
+ return resolve(pkgJsonPath, []);
78
+ }
79
+ function clearMessages(messagesDir) {
80
+ if (fs_1.default.existsSync(messagesDir)) {
81
+ fs_1.default.rmSync(messagesDir, { recursive: true });
82
+ }
83
+ fs_1.default.mkdirSync(messagesDir, { recursive: true });
84
+ }
85
+ function pull({ siteRoot, execFileSync, shouldPrepare, atlasOptions = '', }) {
86
+ validateSiteTranslationsConfig(siteRoot);
87
+ // only interact with messages dir, not site-messages
88
+ const messagesDir = path_1.default.join(siteRoot, 'src', 'i18n', 'messages');
89
+ const nodeModulesBase = path_1.default.join(siteRoot, 'node_modules');
90
+ clearMessages(messagesDir);
91
+ const mappings = resolveTranslationMappings(path_1.default.join(siteRoot, 'package.json'), nodeModulesBase);
92
+ if (!mappings.length) {
93
+ if (shouldPrepare)
94
+ (0, prepare_1.prepare)({ siteRoot });
95
+ return;
96
+ }
97
+ const atlasOptionsArgs = atlasOptions.trim().split(/\s+/).filter(Boolean);
98
+ const atlasMappingArgs = mappings.map(m => `${m.from}:src/i18n/messages/${m.to}`);
99
+ execFileSync('atlas', ['pull', ...atlasOptionsArgs, ...atlasMappingArgs]);
100
+ if (shouldPrepare)
101
+ (0, prepare_1.prepare)({ siteRoot });
102
+ }
@@ -14,5 +14,7 @@ export declare enum CommandTypes {
14
14
  DEV = "dev",
15
15
  FORMAT_JS = "formatjs",
16
16
  SERVE = "serve",
17
+ TRANSLATIONS_PULL = "translations:pull",
18
+ TRANSLATIONS_PREPARE = "translations:prepare",
17
19
  HELP = "help"
18
20
  }
@@ -19,5 +19,7 @@ var CommandTypes;
19
19
  CommandTypes["DEV"] = "dev";
20
20
  CommandTypes["FORMAT_JS"] = "formatjs";
21
21
  CommandTypes["SERVE"] = "serve";
22
+ CommandTypes["TRANSLATIONS_PULL"] = "translations:pull";
23
+ CommandTypes["TRANSLATIONS_PREPARE"] = "translations:prepare";
22
24
  CommandTypes["HELP"] = "help";
23
25
  })(CommandTypes || (exports.CommandTypes = CommandTypes = {}));
@@ -4,3 +4,4 @@ export { default as getImageMinimizer } from './all/getImageMinimizer';
4
4
  export { default as getStylesheetRule } from './all/getStylesheetRule';
5
5
  export { default as getDevServer } from './dev/getDevServer';
6
6
  export { default as getHtmlWebpackPlugin } from './site/getHtmlWebpackPlugin';
7
+ export { default as getI18nMessagesFallbackPlugin } from './site/getI18nMessagesFallbackPlugin';
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getHtmlWebpackPlugin = exports.getDevServer = exports.getStylesheetRule = exports.getImageMinimizer = exports.getFileLoaderRules = exports.getCodeRules = void 0;
6
+ exports.getI18nMessagesFallbackPlugin = exports.getHtmlWebpackPlugin = exports.getDevServer = exports.getStylesheetRule = exports.getImageMinimizer = exports.getFileLoaderRules = exports.getCodeRules = void 0;
7
7
  var getCodeRules_1 = require("./all/getCodeRules");
8
8
  Object.defineProperty(exports, "getCodeRules", { enumerable: true, get: function () { return __importDefault(getCodeRules_1).default; } });
9
9
  var getFileLoaderRules_1 = require("./all/getFileLoaderRules");
@@ -16,3 +16,5 @@ var getDevServer_1 = require("./dev/getDevServer");
16
16
  Object.defineProperty(exports, "getDevServer", { enumerable: true, get: function () { return __importDefault(getDevServer_1).default; } });
17
17
  var getHtmlWebpackPlugin_1 = require("./site/getHtmlWebpackPlugin");
18
18
  Object.defineProperty(exports, "getHtmlWebpackPlugin", { enumerable: true, get: function () { return __importDefault(getHtmlWebpackPlugin_1).default; } });
19
+ var getI18nMessagesFallbackPlugin_1 = require("./site/getI18nMessagesFallbackPlugin");
20
+ Object.defineProperty(exports, "getI18nMessagesFallbackPlugin", { enumerable: true, get: function () { return __importDefault(getI18nMessagesFallbackPlugin_1).default; } });
@@ -0,0 +1,2 @@
1
+ declare const _default: never[];
2
+ export default _default;
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = [];
@@ -0,0 +1,2 @@
1
+ import webpack from 'webpack';
2
+ export default function getI18nMessagesFallbackPlugin(): webpack.NormalModuleReplacementPlugin;