@edx/frontend-platform 4.6.0 → 4.6.2
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/.env.development +30 -0
- package/.env.test +30 -0
- package/.eslintignore +6 -0
- package/.eslintrc.js +28 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +13 -0
- package/.github/workflows/add-depr-ticket-to-depr-board.yml +19 -0
- package/.github/workflows/add-remove-label-on-comment.yml +20 -0
- package/.github/workflows/ci.yml +42 -0
- package/.github/workflows/commitlint.yml +10 -0
- package/.github/workflows/lockfileversion-check.yml +13 -0
- package/.github/workflows/manual-publish.yml +43 -0
- package/.github/workflows/npm-deprecate.yml +22 -0
- package/.github/workflows/release.yml +45 -0
- package/.github/workflows/self-assign-issue.yml +12 -0
- package/.github/workflows/update-browserslist-db.yml +12 -0
- package/.nvmrc +1 -0
- package/.releaserc +32 -0
- package/catalog-info.yaml +21 -0
- package/dist/LICENSE +661 -0
- package/dist/README.md +155 -0
- package/dist/package.json +86 -0
- package/docs/addTagsPlugin.js +10 -0
- package/docs/auth-API.md +114 -0
- package/docs/decisions/0001-record-architecture-decisions.rst +32 -0
- package/docs/decisions/0002-frontend-base-design-goals.rst +222 -0
- package/docs/decisions/0003-consolidation-into-frontend-platform.rst +71 -0
- package/docs/decisions/0004-axios-caching-implementation.rst +88 -0
- package/docs/decisions/0005-token-null-after-successful-refresh.rst +69 -0
- package/docs/decisions/0006-middleware-support-for-http-clients.rst +44 -0
- package/docs/decisions/0007-javascript-file-configuration.rst +143 -0
- package/docs/how_tos/automatic-case-conversion.rst +58 -0
- package/docs/how_tos/caching.rst +93 -0
- package/docs/how_tos/i18n.rst +305 -0
- package/docs/removeExport.js +24 -0
- package/docs/template/edx/README.md +12 -0
- package/docs/template/edx/publish.js +713 -0
- package/docs/template/edx/static/fonts/OpenSans-Bold-webfont.eot +0 -0
- package/docs/template/edx/static/fonts/OpenSans-Bold-webfont.svg +1830 -0
- package/docs/template/edx/static/fonts/OpenSans-Bold-webfont.woff +0 -0
- package/docs/template/edx/static/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
- package/docs/template/edx/static/fonts/OpenSans-BoldItalic-webfont.svg +1830 -0
- package/docs/template/edx/static/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
- package/docs/template/edx/static/fonts/OpenSans-Italic-webfont.eot +0 -0
- package/docs/template/edx/static/fonts/OpenSans-Italic-webfont.svg +1830 -0
- package/docs/template/edx/static/fonts/OpenSans-Italic-webfont.woff +0 -0
- package/docs/template/edx/static/fonts/OpenSans-Light-webfont.eot +0 -0
- package/docs/template/edx/static/fonts/OpenSans-Light-webfont.svg +1831 -0
- package/docs/template/edx/static/fonts/OpenSans-Light-webfont.woff +0 -0
- package/docs/template/edx/static/fonts/OpenSans-LightItalic-webfont.eot +0 -0
- package/docs/template/edx/static/fonts/OpenSans-LightItalic-webfont.svg +1835 -0
- package/docs/template/edx/static/fonts/OpenSans-LightItalic-webfont.woff +0 -0
- package/docs/template/edx/static/fonts/OpenSans-Regular-webfont.eot +0 -0
- package/docs/template/edx/static/fonts/OpenSans-Regular-webfont.svg +1831 -0
- package/docs/template/edx/static/fonts/OpenSans-Regular-webfont.woff +0 -0
- package/docs/template/edx/static/scripts/linenumber.js +25 -0
- package/docs/template/edx/static/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/docs/template/edx/static/scripts/prettify/lang-css.js +2 -0
- package/docs/template/edx/static/scripts/prettify/prettify.js +28 -0
- package/docs/template/edx/static/styles/jsdoc-default.css +356 -0
- package/docs/template/edx/static/styles/prettify-jsdoc.css +111 -0
- package/docs/template/edx/static/styles/prettify-tomorrow.css +132 -0
- package/docs/template/edx/tmpl/augments.tmpl +10 -0
- package/docs/template/edx/tmpl/container.tmpl +196 -0
- package/docs/template/edx/tmpl/details.tmpl +143 -0
- package/docs/template/edx/tmpl/example.tmpl +2 -0
- package/docs/template/edx/tmpl/examples.tmpl +13 -0
- package/docs/template/edx/tmpl/exceptions.tmpl +32 -0
- package/docs/template/edx/tmpl/layout.tmpl +39 -0
- package/docs/template/edx/tmpl/mainpage.tmpl +10 -0
- package/docs/template/edx/tmpl/members.tmpl +38 -0
- package/docs/template/edx/tmpl/method.tmpl +131 -0
- package/docs/template/edx/tmpl/modifies.tmpl +14 -0
- package/docs/template/edx/tmpl/params.tmpl +131 -0
- package/docs/template/edx/tmpl/properties.tmpl +108 -0
- package/docs/template/edx/tmpl/returns.tmpl +19 -0
- package/docs/template/edx/tmpl/source.tmpl +8 -0
- package/docs/template/edx/tmpl/tutorial.tmpl +19 -0
- package/docs/template/edx/tmpl/type.tmpl +7 -0
- package/env.config.js +8 -0
- package/jsdoc.json +36 -0
- package/openedx.yaml +12 -0
- package/package.json +6 -6
- package/service-interface.png +0 -0
- package/src/analytics/MockAnalyticsService.js +71 -0
- package/src/analytics/SegmentAnalyticsService.js +243 -0
- package/src/analytics/index.js +12 -0
- package/src/analytics/interface.js +142 -0
- package/src/auth/AxiosCsrfTokenService.js +60 -0
- package/src/auth/AxiosJwtAuthService.js +364 -0
- package/src/auth/AxiosJwtTokenService.js +134 -0
- package/src/auth/LocalForageCache.js +78 -0
- package/src/auth/MockAuthService.js +285 -0
- package/src/auth/index.js +19 -0
- package/src/auth/interceptors/createCsrfTokenProviderInterceptor.js +37 -0
- package/src/auth/interceptors/createJwtTokenProviderInterceptor.js +38 -0
- package/src/auth/interceptors/createProcessAxiosRequestErrorInterceptor.js +20 -0
- package/src/auth/interceptors/createRetryInterceptor.js +72 -0
- package/src/auth/interface.js +309 -0
- package/src/auth/utils.js +105 -0
- package/src/config.js +327 -0
- package/src/constants.js +66 -0
- package/src/i18n/countries.js +57 -0
- package/src/i18n/index.js +123 -0
- package/src/i18n/injectIntlWithShim.jsx +45 -0
- package/src/i18n/languages.js +60 -0
- package/src/i18n/lib.js +282 -0
- package/src/i18n/scripts/README.md +29 -0
- package/src/i18n/scripts/intl-imports.js +259 -0
- package/src/i18n/scripts/transifex-utils.js +75 -0
- package/src/index.js +42 -0
- package/src/initialize.js +357 -0
- package/src/logging/MockLoggingService.js +31 -0
- package/src/logging/NewRelicLoggingService.js +181 -0
- package/src/logging/index.js +9 -0
- package/src/logging/interface.js +110 -0
- package/src/pubSub.js +47 -0
- package/src/react/AppContext.jsx +24 -0
- package/src/react/AppProvider.jsx +93 -0
- package/src/react/AuthenticatedPageRoute.jsx +60 -0
- package/src/react/ErrorBoundary.jsx +44 -0
- package/src/react/ErrorPage.jsx +76 -0
- package/src/react/LoginRedirect.jsx +16 -0
- package/src/react/OptionalReduxProvider.jsx +28 -0
- package/src/react/PageRoute.jsx +31 -0
- package/src/react/hooks.js +50 -0
- package/src/react/index.js +16 -0
- package/src/scripts/GoogleAnalyticsLoader.js +53 -0
- package/src/scripts/index.js +2 -0
- package/src/testing/index.js +9 -0
- package/src/testing/initializeMockApp.js +77 -0
- package/src/testing/mockMessages.js +21 -0
- package/src/utils.js +167 -0
- /package/{analytics → dist/analytics}/MockAnalyticsService.js +0 -0
- /package/{analytics → dist/analytics}/MockAnalyticsService.js.map +0 -0
- /package/{analytics → dist/analytics}/SegmentAnalyticsService.js +0 -0
- /package/{analytics → dist/analytics}/SegmentAnalyticsService.js.map +0 -0
- /package/{analytics → dist/analytics}/index.js +0 -0
- /package/{analytics → dist/analytics}/index.js.map +0 -0
- /package/{analytics → dist/analytics}/interface.js +0 -0
- /package/{analytics → dist/analytics}/interface.js.map +0 -0
- /package/{auth → dist/auth}/AxiosCsrfTokenService.js +0 -0
- /package/{auth → dist/auth}/AxiosCsrfTokenService.js.map +0 -0
- /package/{auth → dist/auth}/AxiosJwtAuthService.js +0 -0
- /package/{auth → dist/auth}/AxiosJwtAuthService.js.map +0 -0
- /package/{auth → dist/auth}/AxiosJwtTokenService.js +0 -0
- /package/{auth → dist/auth}/AxiosJwtTokenService.js.map +0 -0
- /package/{auth → dist/auth}/LocalForageCache.js +0 -0
- /package/{auth → dist/auth}/LocalForageCache.js.map +0 -0
- /package/{auth → dist/auth}/MockAuthService.js +0 -0
- /package/{auth → dist/auth}/MockAuthService.js.map +0 -0
- /package/{auth → dist/auth}/index.js +0 -0
- /package/{auth → dist/auth}/index.js.map +0 -0
- /package/{auth → dist/auth}/interceptors/createCsrfTokenProviderInterceptor.js +0 -0
- /package/{auth → dist/auth}/interceptors/createCsrfTokenProviderInterceptor.js.map +0 -0
- /package/{auth → dist/auth}/interceptors/createJwtTokenProviderInterceptor.js +0 -0
- /package/{auth → dist/auth}/interceptors/createJwtTokenProviderInterceptor.js.map +0 -0
- /package/{auth → dist/auth}/interceptors/createProcessAxiosRequestErrorInterceptor.js +0 -0
- /package/{auth → dist/auth}/interceptors/createProcessAxiosRequestErrorInterceptor.js.map +0 -0
- /package/{auth → dist/auth}/interceptors/createRetryInterceptor.js +0 -0
- /package/{auth → dist/auth}/interceptors/createRetryInterceptor.js.map +0 -0
- /package/{auth → dist/auth}/interface.js +0 -0
- /package/{auth → dist/auth}/interface.js.map +0 -0
- /package/{auth → dist/auth}/utils.js +0 -0
- /package/{auth → dist/auth}/utils.js.map +0 -0
- /package/{config.js → dist/config.js} +0 -0
- /package/{config.js.map → dist/config.js.map} +0 -0
- /package/{constants.js → dist/constants.js} +0 -0
- /package/{constants.js.map → dist/constants.js.map} +0 -0
- /package/{i18n → dist/i18n}/countries.js +0 -0
- /package/{i18n → dist/i18n}/countries.js.map +0 -0
- /package/{i18n → dist/i18n}/index.js +0 -0
- /package/{i18n → dist/i18n}/index.js.map +0 -0
- /package/{i18n → dist/i18n}/injectIntlWithShim.js +0 -0
- /package/{i18n → dist/i18n}/injectIntlWithShim.js.map +0 -0
- /package/{i18n → dist/i18n}/languages.js +0 -0
- /package/{i18n → dist/i18n}/languages.js.map +0 -0
- /package/{i18n → dist/i18n}/lib.js +0 -0
- /package/{i18n → dist/i18n}/lib.js.map +0 -0
- /package/{i18n → dist/i18n}/scripts/README.md +0 -0
- /package/{i18n → dist/i18n}/scripts/intl-imports.js +0 -0
- /package/{i18n → dist/i18n}/scripts/intl-imports.js.map +0 -0
- /package/{i18n → dist/i18n}/scripts/transifex-utils.js +0 -0
- /package/{i18n → dist/i18n}/scripts/transifex-utils.js.map +0 -0
- /package/{index.js → dist/index.js} +0 -0
- /package/{index.js.map → dist/index.js.map} +0 -0
- /package/{initialize.js → dist/initialize.js} +0 -0
- /package/{initialize.js.map → dist/initialize.js.map} +0 -0
- /package/{logging → dist/logging}/MockLoggingService.js +0 -0
- /package/{logging → dist/logging}/MockLoggingService.js.map +0 -0
- /package/{logging → dist/logging}/NewRelicLoggingService.js +0 -0
- /package/{logging → dist/logging}/NewRelicLoggingService.js.map +0 -0
- /package/{logging → dist/logging}/index.js +0 -0
- /package/{logging → dist/logging}/index.js.map +0 -0
- /package/{logging → dist/logging}/interface.js +0 -0
- /package/{logging → dist/logging}/interface.js.map +0 -0
- /package/{pubSub.js → dist/pubSub.js} +0 -0
- /package/{pubSub.js.map → dist/pubSub.js.map} +0 -0
- /package/{react → dist/react}/AppContext.js +0 -0
- /package/{react → dist/react}/AppContext.js.map +0 -0
- /package/{react → dist/react}/AppProvider.js +0 -0
- /package/{react → dist/react}/AppProvider.js.map +0 -0
- /package/{react → dist/react}/AuthenticatedPageRoute.js +0 -0
- /package/{react → dist/react}/AuthenticatedPageRoute.js.map +0 -0
- /package/{react → dist/react}/ErrorBoundary.js +0 -0
- /package/{react → dist/react}/ErrorBoundary.js.map +0 -0
- /package/{react → dist/react}/ErrorPage.js +0 -0
- /package/{react → dist/react}/ErrorPage.js.map +0 -0
- /package/{react → dist/react}/LoginRedirect.js +0 -0
- /package/{react → dist/react}/LoginRedirect.js.map +0 -0
- /package/{react → dist/react}/OptionalReduxProvider.js +0 -0
- /package/{react → dist/react}/OptionalReduxProvider.js.map +0 -0
- /package/{react → dist/react}/PageRoute.js +0 -0
- /package/{react → dist/react}/PageRoute.js.map +0 -0
- /package/{react → dist/react}/hooks.js +0 -0
- /package/{react → dist/react}/hooks.js.map +0 -0
- /package/{react → dist/react}/index.js +0 -0
- /package/{react → dist/react}/index.js.map +0 -0
- /package/{scripts → dist/scripts}/GoogleAnalyticsLoader.js +0 -0
- /package/{scripts → dist/scripts}/GoogleAnalyticsLoader.js.map +0 -0
- /package/{scripts → dist/scripts}/index.js +0 -0
- /package/{scripts → dist/scripts}/index.js.map +0 -0
- /package/{testing → dist/testing}/index.js +0 -0
- /package/{testing → dist/testing}/index.js.map +0 -0
- /package/{testing → dist/testing}/initializeMockApp.js +0 -0
- /package/{testing → dist/testing}/initializeMockApp.js.map +0 -0
- /package/{testing → dist/testing}/mockMessages.js +0 -0
- /package/{testing → dist/testing}/mockMessages.js.map +0 -0
- /package/{utils.js → dist/utils.js} +0 -0
- /package/{utils.js.map → dist/utils.js.map} +0 -0
package/src/config.js
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #### Import members from **@edx/frontend-platform**
|
|
3
|
+
*
|
|
4
|
+
* The configuration module provides utilities for working with an application's configuration
|
|
5
|
+
* document (ConfigDocument). Configuration variables can be supplied to the
|
|
6
|
+
* application in four different ways. They are applied in the following order:
|
|
7
|
+
*
|
|
8
|
+
* - Build-time Configuration
|
|
9
|
+
* - Environment Variables
|
|
10
|
+
* - JavaScript File
|
|
11
|
+
* - Runtime Configuration
|
|
12
|
+
*
|
|
13
|
+
* Last one in wins. Variables with the same name defined via the later methods will override any
|
|
14
|
+
* defined using an earlier method. i.e., if a variable is defined in Runtime Configuration, that
|
|
15
|
+
* will override the same variable defined in either Build-time Configuration method (environment
|
|
16
|
+
* variables or JS file). Configuration defined in a JS file will override environment variables.
|
|
17
|
+
*
|
|
18
|
+
* ##### Build-time Configuration
|
|
19
|
+
*
|
|
20
|
+
* Build-time configuration methods add config variables into the app when it is built by webpack.
|
|
21
|
+
* This saves the app an API call and means it has all the information it needs to initialize right
|
|
22
|
+
* away. There are two methods of supplying build-time configuration: environment variables and a
|
|
23
|
+
* JavaScript file.
|
|
24
|
+
*
|
|
25
|
+
* ###### Environment Variables
|
|
26
|
+
*
|
|
27
|
+
* A set list of required config variables can be supplied as
|
|
28
|
+
* command-line environment variables during the build process.
|
|
29
|
+
*
|
|
30
|
+
* As a simple example, these are supplied on the command-line before invoking `npm run build`:
|
|
31
|
+
*
|
|
32
|
+
* ```
|
|
33
|
+
* LMS_BASE_URL=http://localhost:18000 npm run build
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* Note that additional variables _cannot_ be supplied via this method without using the `config`
|
|
37
|
+
* initialization handler. The app won't pick them up and they'll appear `undefined`.
|
|
38
|
+
*
|
|
39
|
+
* This configuration method is being deprecated in favor of JavaScript File Configuration.
|
|
40
|
+
*
|
|
41
|
+
* ###### JavaScript File Configuration
|
|
42
|
+
*
|
|
43
|
+
* Configuration variables can be supplied in an optional file named env.config.js. This file must
|
|
44
|
+
* export either an Object containing configuration variables or a function. The function must
|
|
45
|
+
* return an Object containing configuration variables or, alternately, a promise which resolves to
|
|
46
|
+
* an Object.
|
|
47
|
+
*
|
|
48
|
+
* Using a function or async function allows the configuration to be resolved at runtime (because
|
|
49
|
+
* the function will be executed at runtime). This is not common, and the capability is included
|
|
50
|
+
* for the sake of flexibility.
|
|
51
|
+
*
|
|
52
|
+
* JavaScript File Configuration is well-suited to extensibility use cases or component overrides,
|
|
53
|
+
* in that the configuration file can depend on any installed JavaScript module. It is also the
|
|
54
|
+
* preferred way of doing build-time configuration if runtime configuration isn't used by your
|
|
55
|
+
* deployment of the platform.
|
|
56
|
+
*
|
|
57
|
+
* Exporting a config object:
|
|
58
|
+
* ```
|
|
59
|
+
* const config = {
|
|
60
|
+
* LMS_BASE_URL: 'http://localhost:18000'
|
|
61
|
+
* };
|
|
62
|
+
*
|
|
63
|
+
* export default config;
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* Exporting a function that returns an object:
|
|
67
|
+
* ```
|
|
68
|
+
* function getConfig() {
|
|
69
|
+
* return {
|
|
70
|
+
* LMS_BASE_URL: 'http://localhost:18000'
|
|
71
|
+
* };
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* Exporting a function that returns a promise that resolves to an object:
|
|
76
|
+
* ```
|
|
77
|
+
* function getAsyncConfig() {
|
|
78
|
+
* return new Promise((resolve, reject) => {
|
|
79
|
+
* resolve({
|
|
80
|
+
* LMS_BASE_URL: 'http://localhost:18000'
|
|
81
|
+
* });
|
|
82
|
+
* });
|
|
83
|
+
* }
|
|
84
|
+
*
|
|
85
|
+
* export default getAsyncConfig;
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* ##### Runtime Configuration
|
|
89
|
+
*
|
|
90
|
+
* Configuration variables can also be supplied using the "runtime configuration" method, taking
|
|
91
|
+
* advantage of the Micro-frontend Config API in edx-platform. More information on this API can be
|
|
92
|
+
* found in the ADR which introduced it:
|
|
93
|
+
*
|
|
94
|
+
* https://github.com/openedx/edx-platform/blob/master/lms/djangoapps/mfe_config_api/docs/decisions/0001-mfe-config-api.rst
|
|
95
|
+
*
|
|
96
|
+
* The runtime configuration method can be enabled by supplying a MFE_CONFIG_API_URL via one of the other
|
|
97
|
+
* two configuration methods above.
|
|
98
|
+
*
|
|
99
|
+
* Runtime configuration is particularly useful if you need to supply different configurations to
|
|
100
|
+
* a single deployment of a micro-frontend, for instance. It is also a perfectly valid alternative
|
|
101
|
+
* to build-time configuration, though it introduces an additional API call to edx-platform on MFE
|
|
102
|
+
* initialization.
|
|
103
|
+
*
|
|
104
|
+
* ##### Initialization Config Handler
|
|
105
|
+
*
|
|
106
|
+
* The configuration document can be extended by
|
|
107
|
+
* applications at run-time using a `config` initialization handler. Please see the Initialization
|
|
108
|
+
* documentation for more information on handlers and initialization phases.
|
|
109
|
+
*
|
|
110
|
+
* ```
|
|
111
|
+
* initialize({
|
|
112
|
+
* handlers: {
|
|
113
|
+
* config: () => {
|
|
114
|
+
* mergeConfig({
|
|
115
|
+
* CUSTOM_VARIABLE: 'custom value',
|
|
116
|
+
* LMS_BASE_URL: 'http://localhost:18001' // You can override variables, but this is uncommon.
|
|
117
|
+
* }, 'App config override handler');
|
|
118
|
+
* },
|
|
119
|
+
* },
|
|
120
|
+
* });
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* @module Config
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
import { APP_CONFIG_INITIALIZED, CONFIG_CHANGED } from './constants';
|
|
127
|
+
|
|
128
|
+
import { publish, subscribe } from './pubSub';
|
|
129
|
+
import { ensureDefinedConfig } from './utils';
|
|
130
|
+
|
|
131
|
+
function extractRegex(envVar) {
|
|
132
|
+
// Convert the environment variable string to a regex, while guarding
|
|
133
|
+
// against a non-string and an empty/whitespace-only string.
|
|
134
|
+
if (typeof envVar === 'string' && envVar.trim() !== '') {
|
|
135
|
+
return new RegExp(envVar);
|
|
136
|
+
}
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const ENVIRONMENT = process.env.NODE_ENV;
|
|
141
|
+
let config = {
|
|
142
|
+
ACCESS_TOKEN_COOKIE_NAME: process.env.ACCESS_TOKEN_COOKIE_NAME,
|
|
143
|
+
ACCOUNT_PROFILE_URL: process.env.ACCOUNT_PROFILE_URL,
|
|
144
|
+
ACCOUNT_SETTINGS_URL: process.env.ACCOUNT_SETTINGS_URL,
|
|
145
|
+
BASE_URL: process.env.BASE_URL,
|
|
146
|
+
PUBLIC_PATH: process.env.PUBLIC_PATH || '/',
|
|
147
|
+
CREDENTIALS_BASE_URL: process.env.CREDENTIALS_BASE_URL,
|
|
148
|
+
CSRF_TOKEN_API_PATH: process.env.CSRF_TOKEN_API_PATH,
|
|
149
|
+
DISCOVERY_API_BASE_URL: process.env.DISCOVERY_API_BASE_URL,
|
|
150
|
+
PUBLISHER_BASE_URL: process.env.PUBLISHER_BASE_URL,
|
|
151
|
+
ECOMMERCE_BASE_URL: process.env.ECOMMERCE_BASE_URL,
|
|
152
|
+
ENVIRONMENT,
|
|
153
|
+
IGNORED_ERROR_REGEX: extractRegex(process.env.IGNORED_ERROR_REGEX),
|
|
154
|
+
LANGUAGE_PREFERENCE_COOKIE_NAME: process.env.LANGUAGE_PREFERENCE_COOKIE_NAME,
|
|
155
|
+
LEARNING_BASE_URL: process.env.LEARNING_BASE_URL,
|
|
156
|
+
LMS_BASE_URL: process.env.LMS_BASE_URL,
|
|
157
|
+
LOGIN_URL: process.env.LOGIN_URL,
|
|
158
|
+
LOGOUT_URL: process.env.LOGOUT_URL,
|
|
159
|
+
STUDIO_BASE_URL: process.env.STUDIO_BASE_URL,
|
|
160
|
+
MARKETING_SITE_BASE_URL: process.env.MARKETING_SITE_BASE_URL,
|
|
161
|
+
ORDER_HISTORY_URL: process.env.ORDER_HISTORY_URL,
|
|
162
|
+
REFRESH_ACCESS_TOKEN_ENDPOINT: process.env.REFRESH_ACCESS_TOKEN_ENDPOINT,
|
|
163
|
+
SECURE_COOKIES: ENVIRONMENT !== 'development',
|
|
164
|
+
SEGMENT_KEY: process.env.SEGMENT_KEY,
|
|
165
|
+
SITE_NAME: process.env.SITE_NAME,
|
|
166
|
+
USER_INFO_COOKIE_NAME: process.env.USER_INFO_COOKIE_NAME,
|
|
167
|
+
LOGO_URL: process.env.LOGO_URL,
|
|
168
|
+
LOGO_TRADEMARK_URL: process.env.LOGO_TRADEMARK_URL,
|
|
169
|
+
LOGO_WHITE_URL: process.env.LOGO_WHITE_URL,
|
|
170
|
+
FAVICON_URL: process.env.FAVICON_URL,
|
|
171
|
+
MFE_CONFIG_API_URL: process.env.MFE_CONFIG_API_URL,
|
|
172
|
+
APP_ID: process.env.APP_ID,
|
|
173
|
+
SUPPORT_URL: process.env.SUPPORT_URL,
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Getter for the application configuration document. This is synchronous and merely returns a
|
|
178
|
+
* reference to an existing object, and is thus safe to call as often as desired.
|
|
179
|
+
*
|
|
180
|
+
* Example:
|
|
181
|
+
*
|
|
182
|
+
* ```
|
|
183
|
+
* import { getConfig } from '@edx/frontend-platform';
|
|
184
|
+
*
|
|
185
|
+
* const {
|
|
186
|
+
* LMS_BASE_URL,
|
|
187
|
+
* } = getConfig();
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* @returns {ConfigDocument}
|
|
191
|
+
*/
|
|
192
|
+
export function getConfig() {
|
|
193
|
+
return config;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Replaces the existing ConfigDocument. This is not commonly used, but can be helpful for tests.
|
|
198
|
+
*
|
|
199
|
+
* The supplied config document will be tested with `ensureDefinedConfig` to ensure it does not
|
|
200
|
+
* have any `undefined` keys.
|
|
201
|
+
*
|
|
202
|
+
* Example:
|
|
203
|
+
*
|
|
204
|
+
* ```
|
|
205
|
+
* import { setConfig } from '@edx/frontend-platform';
|
|
206
|
+
*
|
|
207
|
+
* setConfig({
|
|
208
|
+
* LMS_BASE_URL, // This is overriding the ENTIRE document - this is not merged in!
|
|
209
|
+
* });
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* @param {ConfigDocument} newConfig
|
|
213
|
+
*/
|
|
214
|
+
export function setConfig(newConfig) {
|
|
215
|
+
ensureDefinedConfig(config, 'config');
|
|
216
|
+
config = newConfig;
|
|
217
|
+
publish(CONFIG_CHANGED);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Merges additional configuration values into the ConfigDocument returned by `getConfig`. Will
|
|
222
|
+
* override any values that exist with the same keys.
|
|
223
|
+
*
|
|
224
|
+
* ```
|
|
225
|
+
* mergeConfig({
|
|
226
|
+
* NEW_KEY: 'new value',
|
|
227
|
+
* OTHER_NEW_KEY: 'other new value',
|
|
228
|
+
* });
|
|
229
|
+
*
|
|
230
|
+
* If any of the key values are `undefined`, an error will be logged to 'warn'.
|
|
231
|
+
*
|
|
232
|
+
* @param {Object} newConfig
|
|
233
|
+
*/
|
|
234
|
+
export function mergeConfig(newConfig) {
|
|
235
|
+
ensureDefinedConfig(newConfig, 'ProcessEnvConfigService');
|
|
236
|
+
config = Object.assign(config, newConfig);
|
|
237
|
+
publish(CONFIG_CHANGED);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* A method allowing application code to indicate that particular ConfigDocument keys are required
|
|
242
|
+
* for them to function. This is useful for diagnosing development/deployment issues, primarily,
|
|
243
|
+
* by surfacing misconfigurations early. For instance, if the build process fails to supply an
|
|
244
|
+
* environment variable on the command-line, it's possible that one of the `process.env` variables
|
|
245
|
+
* will be undefined. Should be used in conjunction with `mergeConfig` for custom `ConfigDocument`
|
|
246
|
+
* properties. Requester is for informational/error reporting purposes only.
|
|
247
|
+
*
|
|
248
|
+
* ```
|
|
249
|
+
* ensureConfig(['LMS_BASE_URL', 'LOGIN_URL'], 'MySpecialComponent');
|
|
250
|
+
*
|
|
251
|
+
* // Will log a warning with:
|
|
252
|
+
* // "App configuration error: LOGIN_URL is required by MySpecialComponent."
|
|
253
|
+
* // if LOGIN_URL is undefined, for example.
|
|
254
|
+
* ```
|
|
255
|
+
*
|
|
256
|
+
* *NOTE*: `ensureConfig` waits until `APP_CONFIG_INITIALIZED` is published to verify the existence
|
|
257
|
+
* of the specified properties. This means that this function is compatible with custom `config`
|
|
258
|
+
* phase handlers responsible for loading additional configuration data in the initialization
|
|
259
|
+
* sequence.
|
|
260
|
+
*
|
|
261
|
+
* @param {Array} keys
|
|
262
|
+
* @param {string} [requester='unspecified application code']
|
|
263
|
+
*/
|
|
264
|
+
export function ensureConfig(keys, requester = 'unspecified application code') {
|
|
265
|
+
subscribe(APP_CONFIG_INITIALIZED, () => {
|
|
266
|
+
keys.forEach((key) => {
|
|
267
|
+
if (config[key] === undefined) {
|
|
268
|
+
// eslint-disable-next-line no-console
|
|
269
|
+
console.warn(`App configuration error: ${key} is required by ${requester}.`);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* An object describing the current application configuration.
|
|
277
|
+
*
|
|
278
|
+
* In its most basic form, the initialization process loads this document via `process.env`
|
|
279
|
+
* variables. There are other ways to add configuration variables to the ConfigDocument as
|
|
280
|
+
* documented above (JavaScript File Configuration, Runtime Configuration, and the Initialization
|
|
281
|
+
* Config Handler)
|
|
282
|
+
*
|
|
283
|
+
* ```
|
|
284
|
+
* {
|
|
285
|
+
* BASE_URL: process.env.BASE_URL,
|
|
286
|
+
* // ... other vars
|
|
287
|
+
* }
|
|
288
|
+
* ```
|
|
289
|
+
*
|
|
290
|
+
* When using Webpack (i.e., normal usage), the build process is responsible for supplying these
|
|
291
|
+
* variables via command-line environment variables. That means they must be supplied at build
|
|
292
|
+
* time.
|
|
293
|
+
*
|
|
294
|
+
* @name ConfigDocument
|
|
295
|
+
* @memberof module:Config
|
|
296
|
+
* @property {string} ACCESS_TOKEN_COOKIE_NAME
|
|
297
|
+
* @property {string} ACCOUNT_PROFILE_URL
|
|
298
|
+
* @property {string} ACCOUNT_SETTINGS_URL
|
|
299
|
+
* @property {string} BASE_URL The URL of the current application.
|
|
300
|
+
* @property {string} CREDENTIALS_BASE_URL
|
|
301
|
+
* @property {string} CSRF_TOKEN_API_PATH
|
|
302
|
+
* @property {string} DISCOVERY_API_BASE_URL
|
|
303
|
+
* @property {string} PUBLISHER_BASE_URL
|
|
304
|
+
* @property {string} ECOMMERCE_BASE_URL
|
|
305
|
+
* @property {string} ENVIRONMENT This is one of: development, production, or test.
|
|
306
|
+
* @property {string} IGNORED_ERROR_REGEX
|
|
307
|
+
* @property {string} LANGUAGE_PREFERENCE_COOKIE_NAME
|
|
308
|
+
* @property {string} LEARNING_BASE_URL
|
|
309
|
+
* @property {string} LMS_BASE_URL
|
|
310
|
+
* @property {string} LOGIN_URL
|
|
311
|
+
* @property {string} LOGOUT_URL
|
|
312
|
+
* @property {string} STUDIO_BASE_URL
|
|
313
|
+
* @property {string} MARKETING_SITE_BASE_URL
|
|
314
|
+
* @property {string} ORDER_HISTORY_URL
|
|
315
|
+
* @property {string} REFRESH_ACCESS_TOKEN_ENDPOINT
|
|
316
|
+
* @property {boolean} SECURE_COOKIES
|
|
317
|
+
* @property {string} SEGMENT_KEY
|
|
318
|
+
* @property {string} SITE_NAME
|
|
319
|
+
* @property {string} USER_INFO_COOKIE_NAME
|
|
320
|
+
* @property {string} LOGO_URL
|
|
321
|
+
* @property {string} LOGO_TRADEMARK_URL
|
|
322
|
+
* @property {string} LOGO_WHITE_URL
|
|
323
|
+
* @property {string} FAVICON_URL
|
|
324
|
+
* @property {string} MFE_CONFIG_API_URL
|
|
325
|
+
* @property {string} APP_ID
|
|
326
|
+
* @property {string} SUPPORT_URL
|
|
327
|
+
*/
|
package/src/constants.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** @constant */
|
|
2
|
+
export const APP_TOPIC = 'APP';
|
|
3
|
+
|
|
4
|
+
export const APP_PUBSUB_INITIALIZED = `${APP_TOPIC}.PUBSUB_INITIALIZED`;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Event published when the application initialization sequence has finished loading any dynamic
|
|
8
|
+
* configuration setup in a custom config handler.
|
|
9
|
+
*
|
|
10
|
+
* @event
|
|
11
|
+
*/
|
|
12
|
+
export const APP_CONFIG_INITIALIZED = `${APP_TOPIC}.CONFIG_INITIALIZED`;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Event published when the application initialization sequence has finished determining the user's
|
|
16
|
+
* authentication state, creating an authenticated API client, and executing auth handlers.
|
|
17
|
+
*
|
|
18
|
+
* @event
|
|
19
|
+
*/
|
|
20
|
+
export const APP_AUTH_INITIALIZED = `${APP_TOPIC}.AUTH_INITIALIZED`;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Event published when the application initialization sequence has finished initializing
|
|
24
|
+
* internationalization and executing any i18n handlers.
|
|
25
|
+
*
|
|
26
|
+
* @event
|
|
27
|
+
*/
|
|
28
|
+
export const APP_I18N_INITIALIZED = `${APP_TOPIC}.I18N_INITIALIZED`;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Event published when the application initialization sequence has finished initializing the
|
|
32
|
+
* logging service and executing any logging handlers.
|
|
33
|
+
*
|
|
34
|
+
* @event
|
|
35
|
+
*/
|
|
36
|
+
export const APP_LOGGING_INITIALIZED = `${APP_TOPIC}.LOGGING_INITIALIZED`;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Event published when the application initialization sequence has finished initializing the
|
|
40
|
+
* analytics service and executing any analytics handlers.
|
|
41
|
+
*
|
|
42
|
+
* @event
|
|
43
|
+
*/
|
|
44
|
+
export const APP_ANALYTICS_INITIALIZED = `${APP_TOPIC}.ANALYTICS_INITIALIZED`;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Event published when the application initialization sequence has finished. Applications should
|
|
48
|
+
* subscribe to this event and start rendering the UI when it has fired.
|
|
49
|
+
*
|
|
50
|
+
* @event
|
|
51
|
+
*/
|
|
52
|
+
export const APP_READY = `${APP_TOPIC}.READY`;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Event published when the application initialization sequence has aborted. This is frequently
|
|
56
|
+
* used to show an error page when an initialization error has occurred.
|
|
57
|
+
*
|
|
58
|
+
* @see {@link module:React~ErrorPage}
|
|
59
|
+
* @event
|
|
60
|
+
*/
|
|
61
|
+
export const APP_INIT_ERROR = `${APP_TOPIC}.INIT_ERROR`;
|
|
62
|
+
|
|
63
|
+
/** @constant */
|
|
64
|
+
export const CONFIG_TOPIC = 'CONFIG';
|
|
65
|
+
|
|
66
|
+
export const CONFIG_CHANGED = `${CONFIG_TOPIC}.CHANGED`;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/* eslint-disable import/extensions */
|
|
2
|
+
import COUNTRIES, { langs as countryLangs } from 'i18n-iso-countries';
|
|
3
|
+
|
|
4
|
+
import { getPrimaryLanguageSubtag } from './lib';
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* COUNTRY LISTS
|
|
8
|
+
*
|
|
9
|
+
* Lists of country names localized in supported languages.
|
|
10
|
+
*
|
|
11
|
+
* TODO: When we start dynamically loading translations only for the current locale, change this.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
COUNTRIES.registerLocale(require('i18n-iso-countries/langs/ar.json'));
|
|
15
|
+
COUNTRIES.registerLocale(require('i18n-iso-countries/langs/en.json'));
|
|
16
|
+
COUNTRIES.registerLocale(require('i18n-iso-countries/langs/es.json'));
|
|
17
|
+
COUNTRIES.registerLocale(require('i18n-iso-countries/langs/fr.json'));
|
|
18
|
+
COUNTRIES.registerLocale(require('i18n-iso-countries/langs/zh.json'));
|
|
19
|
+
COUNTRIES.registerLocale(require('i18n-iso-countries/langs/ca.json'));
|
|
20
|
+
COUNTRIES.registerLocale(require('i18n-iso-countries/langs/he.json'));
|
|
21
|
+
COUNTRIES.registerLocale(require('i18n-iso-countries/langs/id.json'));
|
|
22
|
+
COUNTRIES.registerLocale(require('i18n-iso-countries/langs/ko.json'));
|
|
23
|
+
COUNTRIES.registerLocale(require('i18n-iso-countries/langs/pl.json'));
|
|
24
|
+
COUNTRIES.registerLocale(require('i18n-iso-countries/langs/pt.json'));
|
|
25
|
+
COUNTRIES.registerLocale(require('i18n-iso-countries/langs/ru.json'));
|
|
26
|
+
// COUNTRIES.registerLocale(require('i18n-iso-countries/langs/th.json')); // Doesn't exist in lib.
|
|
27
|
+
COUNTRIES.registerLocale(require('i18n-iso-countries/langs/uk.json'));
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Provides a lookup table of country IDs to country names for the current locale.
|
|
31
|
+
*
|
|
32
|
+
* @memberof module:I18n
|
|
33
|
+
*/
|
|
34
|
+
export function getCountryMessages(locale) {
|
|
35
|
+
const primaryLanguageSubtag = getPrimaryLanguageSubtag(locale);
|
|
36
|
+
const languageCode = countryLangs().includes(primaryLanguageSubtag) ? primaryLanguageSubtag : 'en';
|
|
37
|
+
|
|
38
|
+
return COUNTRIES.getNames(languageCode);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Provides a list of countries represented as objects of the following shape:
|
|
43
|
+
*
|
|
44
|
+
* {
|
|
45
|
+
* key, // The ID of the country
|
|
46
|
+
* name // The localized name of the country
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* TODO: ARCH-878: The list should be sorted alphabetically in the current locale.
|
|
50
|
+
* This is useful for populating dropdowns.
|
|
51
|
+
*
|
|
52
|
+
* @memberof module:I18n
|
|
53
|
+
*/
|
|
54
|
+
export function getCountryList(locale) {
|
|
55
|
+
const countryMessages = getCountryMessages(locale);
|
|
56
|
+
return Object.entries(countryMessages).map(([code, name]) => ({ code, name }));
|
|
57
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #### Import members from **@edx/frontend-platform/i18n**
|
|
3
|
+
* The i18n module relies on react-intl and re-exports all of that package's exports.
|
|
4
|
+
*
|
|
5
|
+
* For each locale we want to support, react-intl needs 1) the locale-data, which includes
|
|
6
|
+
* information about how to format numbers, handle plurals, etc., and 2) the translations, as an
|
|
7
|
+
* object holding message id / translated string pairs. A locale string and the messages object are
|
|
8
|
+
* passed into the IntlProvider element that wraps your element hierarchy.
|
|
9
|
+
*
|
|
10
|
+
* Note that react-intl has no way of checking if the translations you give it actually have
|
|
11
|
+
* anything to do with the locale you pass it; it will happily use whatever messages object you pass
|
|
12
|
+
* in. However, if the locale data for the locale you passed into the IntlProvider was not
|
|
13
|
+
* correctly installed with addLocaleData, all of your translations will fall back to the default
|
|
14
|
+
* (in our case English), *even if you gave IntlProvider the correct messages object for that
|
|
15
|
+
* locale*.
|
|
16
|
+
*
|
|
17
|
+
* Messages are provided to this module via the configure() function below.
|
|
18
|
+
*
|
|
19
|
+
*
|
|
20
|
+
* @module Internationalization
|
|
21
|
+
* @see {@link https://github.com/openedx/frontend-platform/blob/master/docs/how_tos/i18n.rst}
|
|
22
|
+
* @see {@link https://formatjs.io/docs/react-intl/components/ Intl} for components exported from this module.
|
|
23
|
+
*
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @name createIntl
|
|
28
|
+
* @kind function
|
|
29
|
+
* @see {@link https://formatjs.io/docs/react-intl/api#createIntl Intl}
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @name FormattedDate
|
|
34
|
+
* @kind class
|
|
35
|
+
* @see {@link https://formatjs.io/docs/react-intl/components/#formatteddate Intl}
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @name FormattedTime
|
|
40
|
+
* @kind class
|
|
41
|
+
* @see {@link https://formatjs.io/docs/react-intl/components/#formattedtime Intl}
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @name FormattedRelativeTime
|
|
46
|
+
* @kind class
|
|
47
|
+
* @see {@link https://formatjs.io/docs/react-intl/components/#formattedrelativetime Intl}
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @name FormattedNumber
|
|
52
|
+
* @kind class
|
|
53
|
+
* @see {@link https://formatjs.io/docs/react-intl/components/#formattednumber Intl}
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @name FormattedPlural
|
|
58
|
+
* @kind class
|
|
59
|
+
* @see {@link https://formatjs.io/docs/react-intl/components/#formattedplural Intl}
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @name FormattedMessage
|
|
64
|
+
* @kind class
|
|
65
|
+
* @see {@link https://formatjs.io/docs/react-intl/components/#formattedmessage Intl}
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @name IntlProvider
|
|
70
|
+
* @kind class
|
|
71
|
+
* @see {@link https://formatjs.io/docs/react-intl/components/#intlprovider Intl}
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @name defineMessages
|
|
76
|
+
* @kind function
|
|
77
|
+
* @see {@link https://formatjs.io/docs/react-intl/api#definemessagesdefinemessage Intl}
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @name useIntl
|
|
82
|
+
* @kind function
|
|
83
|
+
* @see {@link https://formatjs.io/docs/react-intl/api#useIntl Intl}
|
|
84
|
+
*/
|
|
85
|
+
|
|
86
|
+
export {
|
|
87
|
+
createIntl,
|
|
88
|
+
FormattedDate,
|
|
89
|
+
FormattedTime,
|
|
90
|
+
FormattedRelativeTime,
|
|
91
|
+
FormattedNumber,
|
|
92
|
+
FormattedPlural,
|
|
93
|
+
FormattedMessage,
|
|
94
|
+
defineMessages,
|
|
95
|
+
IntlProvider,
|
|
96
|
+
useIntl,
|
|
97
|
+
} from 'react-intl';
|
|
98
|
+
|
|
99
|
+
export {
|
|
100
|
+
intlShape,
|
|
101
|
+
configure,
|
|
102
|
+
getPrimaryLanguageSubtag,
|
|
103
|
+
getLocale,
|
|
104
|
+
getMessages,
|
|
105
|
+
isRtl,
|
|
106
|
+
handleRtl,
|
|
107
|
+
LOCALE_CHANGED,
|
|
108
|
+
LOCALE_TOPIC,
|
|
109
|
+
} from './lib';
|
|
110
|
+
|
|
111
|
+
export {
|
|
112
|
+
default as injectIntl,
|
|
113
|
+
} from './injectIntlWithShim';
|
|
114
|
+
|
|
115
|
+
export {
|
|
116
|
+
getCountryList,
|
|
117
|
+
getCountryMessages,
|
|
118
|
+
} from './countries';
|
|
119
|
+
|
|
120
|
+
export {
|
|
121
|
+
getLanguageList,
|
|
122
|
+
getLanguageMessages,
|
|
123
|
+
} from './languages';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { injectIntl } from 'react-intl';
|
|
3
|
+
import { getLoggingService, intlShape } from './lib';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This function wraps react-intl's injectIntl function in order to add error logging to the intl
|
|
7
|
+
* property's formatMessage function.
|
|
8
|
+
*
|
|
9
|
+
* @memberof I18n
|
|
10
|
+
*/
|
|
11
|
+
const injectIntlWithShim = (WrappedComponent) => {
|
|
12
|
+
class ShimmedIntlComponent extends React.Component {
|
|
13
|
+
constructor(props) {
|
|
14
|
+
super(props);
|
|
15
|
+
this.shimmedIntl = Object.create(this.props.intl, {
|
|
16
|
+
formatMessage: {
|
|
17
|
+
value: (definition, ...args) => {
|
|
18
|
+
if (definition === undefined || definition.id === undefined) {
|
|
19
|
+
const error = new Error('i18n error: An undefined message was supplied to intl.formatMessage.');
|
|
20
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
21
|
+
console.error(error); // eslint-disable-line no-console
|
|
22
|
+
return '!!! Missing message supplied to intl.formatMessage !!!';
|
|
23
|
+
}
|
|
24
|
+
getLoggingService().logError(error);
|
|
25
|
+
return ''; // Fail silently in production
|
|
26
|
+
}
|
|
27
|
+
return this.props.intl.formatMessage(definition, ...args);
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
render() {
|
|
34
|
+
return <WrappedComponent {...this.props} intl={this.shimmedIntl} />;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
ShimmedIntlComponent.propTypes = {
|
|
39
|
+
intl: intlShape.isRequired,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return injectIntl(ShimmedIntlComponent);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default injectIntlWithShim;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* eslint-disable import/extensions */
|
|
2
|
+
import LANGUAGES, { langs as languageLangs } from '@cospired/i18n-iso-languages';
|
|
3
|
+
|
|
4
|
+
import { getPrimaryLanguageSubtag } from './lib';
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* LANGUAGE LISTS
|
|
8
|
+
*
|
|
9
|
+
* Lists of language names localized in supported languages.
|
|
10
|
+
*
|
|
11
|
+
* TODO: When we start dynamically loading translations only for the current locale, change this.
|
|
12
|
+
* TODO: Also note that a bunch of languages are missing here. They're present but commented out
|
|
13
|
+
* for reference. That's because they're not implemented in this library. If you read this and it's
|
|
14
|
+
* been a while, go check and see if that's changed!
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/ar.json'));
|
|
18
|
+
LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/en.json'));
|
|
19
|
+
LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/es.json'));
|
|
20
|
+
LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/fr.json'));
|
|
21
|
+
// LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/zh.json'));
|
|
22
|
+
// LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/ca.json'));
|
|
23
|
+
// LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/he.json'));
|
|
24
|
+
// LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/id.json'));
|
|
25
|
+
// LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/ko.json'));
|
|
26
|
+
LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/pl.json'));
|
|
27
|
+
LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/pt.json'));
|
|
28
|
+
// LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/ru.json'));
|
|
29
|
+
// LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/th.json'));
|
|
30
|
+
// LANGUAGES.registerLocale(require('@cospired/i18n-iso-languages/langs/uk.json'));
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Provides a lookup table of language IDs to language names for the current locale.
|
|
34
|
+
*
|
|
35
|
+
* @memberof I18n
|
|
36
|
+
*/
|
|
37
|
+
export const getLanguageMessages = (locale) => {
|
|
38
|
+
const primaryLanguageSubtag = getPrimaryLanguageSubtag(locale);
|
|
39
|
+
const languageCode = languageLangs().includes(primaryLanguageSubtag) ? primaryLanguageSubtag : 'en';
|
|
40
|
+
|
|
41
|
+
return LANGUAGES.getNames(languageCode);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Provides a list of languages represented as objects of the following shape:
|
|
46
|
+
*
|
|
47
|
+
* {
|
|
48
|
+
* key, // The ID of the language
|
|
49
|
+
* name // The localized name of the language
|
|
50
|
+
* }
|
|
51
|
+
*
|
|
52
|
+
* TODO: ARCH-878: The list should be sorted alphabetically in the current locale.
|
|
53
|
+
* This is useful for populating dropdowns.
|
|
54
|
+
*
|
|
55
|
+
* @memberof I18n
|
|
56
|
+
*/
|
|
57
|
+
export const getLanguageList = (locale) => {
|
|
58
|
+
const languageMessages = getLanguageMessages(locale);
|
|
59
|
+
return Object.entries(languageMessages).map(([code, name]) => ({ code, name }));
|
|
60
|
+
};
|