Compare commits
292 Commits
recruitmes
...
open-relea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
779275f52c | ||
|
|
0b449ae285 | ||
|
|
728154a577 | ||
|
|
1cca916784 | ||
|
|
c5ef676e65 | ||
|
|
ed4fbaaca5 | ||
|
|
b676a058b1 | ||
|
|
ce6cc34bde | ||
|
|
c5deeb7f99 | ||
|
|
dabf556e2f | ||
|
|
fd4404ec28 | ||
|
|
8dbf20b3d2 | ||
|
|
4ae9ead191 | ||
|
|
8549bf2fcf | ||
|
|
762da62a29 | ||
|
|
7d536e6cdb | ||
|
|
166d7953c9 | ||
|
|
8ea457f949 | ||
|
|
35dfc720c8 | ||
|
|
3ca2739fce | ||
|
|
5df3d8f6e2 | ||
|
|
980a4c4003 | ||
|
|
c3f5374c6e | ||
|
|
fcccc19fc5 | ||
|
|
c2609a3316 | ||
|
|
34f3240c03 | ||
|
|
dba4792a7d | ||
|
|
ad13f7e5c6 | ||
|
|
20476b9445 | ||
|
|
21ad3d78a4 | ||
|
|
8b8e41fa1b | ||
|
|
f997cd0b47 | ||
|
|
9241be296f | ||
|
|
47c2d5c15e | ||
|
|
ed89d8546c | ||
|
|
19de32cb5d | ||
|
|
08a859c002 | ||
|
|
ff1db82c56 | ||
|
|
c122afefb9 | ||
|
|
689542947e | ||
|
|
f64aeff6b5 | ||
|
|
4dd12f6230 | ||
|
|
4571d35102 | ||
|
|
ed7aca7bc5 | ||
|
|
f96dc974f3 | ||
|
|
81f3dbf584 | ||
|
|
4f91b30ee1 | ||
|
|
51272c0fc4 | ||
|
|
27d4a26ae8 | ||
|
|
2fdf630ed3 | ||
|
|
dc056a6cc0 | ||
|
|
54015223a2 | ||
|
|
345777cb72 | ||
|
|
347493fe6b | ||
|
|
766438dcf3 | ||
|
|
f2989e836a | ||
|
|
34118bfc90 | ||
|
|
91a74e309a | ||
|
|
0c32b98e85 | ||
|
|
e059fab172 | ||
|
|
08a8bc0e4f | ||
|
|
3dc0cd97ca | ||
|
|
697adecc1d | ||
|
|
1063945825 | ||
|
|
8aaf4c676f | ||
|
|
10e6abad18 | ||
|
|
a69aa06123 | ||
|
|
81a5857d07 | ||
|
|
cc5cc30279 | ||
|
|
0d492cc9d9 | ||
|
|
5440de3684 | ||
|
|
42768f1f09 | ||
|
|
0d168d79b2 | ||
|
|
c90b8b702b | ||
|
|
db64ff2098 | ||
|
|
1d96fa6146 | ||
|
|
ce72bfdb68 | ||
|
|
7ac8f6a40a | ||
|
|
1cb0cfa113 | ||
|
|
e2899e66d1 | ||
|
|
7229d87fd1 | ||
|
|
fcbabe95ea | ||
|
|
4a0b23b7a1 | ||
|
|
f9190549ff | ||
|
|
79774b1d47 | ||
|
|
fce5b23763 | ||
|
|
0af61b1387 | ||
|
|
e48ab11d5b | ||
|
|
9f92c412b4 | ||
|
|
2b30e0998c | ||
|
|
b8443d517e | ||
|
|
e7dd047eb5 | ||
|
|
3541c66637 | ||
|
|
028e0b0dfc | ||
|
|
1ce7962fa5 | ||
|
|
70a20726a9 | ||
|
|
f83c24c020 | ||
|
|
d4bfdf699b | ||
|
|
1ee501f8b9 | ||
|
|
13d67eb2a3 | ||
|
|
a9558cb296 | ||
|
|
7706d44667 | ||
|
|
3486aead7f | ||
|
|
2947784f00 | ||
|
|
7acb102b43 | ||
|
|
4bd1f3de7d | ||
|
|
5f2570c440 | ||
|
|
f066880c7c | ||
|
|
1eded91f24 | ||
|
|
029f201a46 | ||
|
|
6f5a6f6500 | ||
|
|
9c555c06be | ||
|
|
9198b122ec | ||
|
|
5a3ee877d6 | ||
|
|
3c049ab65a | ||
|
|
ad8be560b4 | ||
|
|
5dea66540d | ||
|
|
400648f09f | ||
|
|
f781f311a2 | ||
|
|
9469adc386 | ||
|
|
691a248477 | ||
|
|
4bf0021982 | ||
|
|
b04257a62d | ||
|
|
bce8aa712d | ||
|
|
25bc11ea8d | ||
|
|
bcece267bc | ||
|
|
1575034ed3 | ||
|
|
922f1e2ac4 | ||
|
|
b03fe545ba | ||
|
|
47fce8aa7d | ||
|
|
5fd6754025 | ||
|
|
428372d198 | ||
|
|
4f83726387 | ||
|
|
40cb949d4e | ||
|
|
daa54be1c8 | ||
|
|
b126635981 | ||
|
|
94e1207d37 | ||
|
|
9ec6e1cf05 | ||
|
|
eddce35a37 | ||
|
|
38cbd4d0d8 | ||
|
|
b962b3f4ca | ||
|
|
ad9b40d9e9 | ||
|
|
7990fe7483 | ||
|
|
def1415f14 | ||
|
|
3f57f39187 | ||
|
|
0e8c8f5412 | ||
|
|
2099e62bb4 | ||
|
|
7f7931fec5 | ||
|
|
1d039de652 | ||
|
|
21d24d517f | ||
|
|
3581007e59 | ||
|
|
df5e11d806 | ||
|
|
75f460bd17 | ||
|
|
66261c4cea | ||
|
|
ea6854374b | ||
|
|
e0385ce20d | ||
|
|
3f53b3057b | ||
|
|
517a390b2f | ||
|
|
6dc04be641 | ||
|
|
d852f217cb | ||
|
|
178fb43a5a | ||
|
|
76d3a13169 | ||
|
|
ce9c6e24a3 | ||
|
|
6dd9d2a1dc | ||
|
|
b493a09c63 | ||
|
|
5df7130310 | ||
|
|
69ede3f005 | ||
|
|
ea5ae8f2af | ||
|
|
d352773a4e | ||
|
|
3fa3954383 | ||
|
|
182fb34a03 | ||
|
|
6e99e1e72c | ||
|
|
7e82785c7b | ||
|
|
74aa00f9cc | ||
|
|
561be05bac | ||
|
|
b97e6292dd | ||
|
|
aa6f36a293 | ||
|
|
0b21ca3f51 | ||
|
|
a04872d7bf | ||
|
|
526da727ec | ||
|
|
747dac26d7 | ||
|
|
a956ccaa93 | ||
|
|
b37a059af7 | ||
|
|
3117c9abd4 | ||
|
|
211c6afc60 | ||
|
|
261e4cfe86 | ||
|
|
dd7ed6d9ee | ||
|
|
9f38be3318 | ||
|
|
7415a0c0e6 | ||
|
|
ac9a390d98 | ||
|
|
61c839bb09 | ||
|
|
cd3cda3c4f | ||
|
|
242629fbdd | ||
|
|
214c383071 | ||
|
|
b8f0615434 | ||
|
|
387e9aedf1 | ||
|
|
d1b5ba74e8 | ||
|
|
1c599d8d04 | ||
|
|
5303b7b95c | ||
|
|
f64d9dd940 | ||
|
|
3a68403773 | ||
|
|
95c869a6ef | ||
|
|
35ee6b5a7b | ||
|
|
55e44e5881 | ||
|
|
738af2aaac | ||
|
|
0f333b4a03 | ||
|
|
06bb7182fb | ||
|
|
4b8677f34d | ||
|
|
f0df248ac2 | ||
|
|
9151cf46aa | ||
|
|
d7f6b1ae0c | ||
|
|
d7c1e119fb | ||
|
|
35d6c9d7bc | ||
|
|
9f9fe2ed1a | ||
|
|
96ec8c3943 | ||
|
|
23bac18450 | ||
|
|
094573be1f | ||
|
|
b2f2760774 | ||
|
|
933e8f85fd | ||
|
|
d9b9c4d290 | ||
|
|
892f3d33ca | ||
|
|
c1b402ebd6 | ||
|
|
a081544440 | ||
|
|
6fee02110a | ||
|
|
aef3f6a179 | ||
|
|
d7391dfd66 | ||
|
|
4f7fbf82bf | ||
|
|
0d01a9fea3 | ||
|
|
88a6e1b260 | ||
|
|
b142e159b6 | ||
|
|
2a079e484f | ||
|
|
1210fe01ae | ||
|
|
7400da7ba6 | ||
|
|
a86f5c43ad | ||
|
|
531b82745f | ||
|
|
ebdaeb80f1 | ||
|
|
488b364215 | ||
|
|
619c75a4b7 | ||
|
|
be783fed99 | ||
|
|
59d5a400f4 | ||
|
|
e0e0c1011e | ||
|
|
2070877a84 | ||
|
|
8c8cd2bcd5 | ||
|
|
a5e7a3a592 | ||
|
|
007dfa82a8 | ||
|
|
8223f0c988 | ||
|
|
335f9fcaf8 | ||
|
|
31a2a8f402 | ||
|
|
54fb55fe8f | ||
|
|
c34360f2fb | ||
|
|
82d339c91b | ||
|
|
4d9b508e19 | ||
|
|
60e51a8f25 | ||
|
|
350a6b10ae | ||
|
|
4ba9e1194b | ||
|
|
6cb470522b | ||
|
|
a3953b672f | ||
|
|
e91a8a4dfa | ||
|
|
17048f5caf | ||
|
|
955cf26860 | ||
|
|
ee094a1330 | ||
|
|
75269a3372 | ||
|
|
2ac0f83e87 | ||
|
|
b0df7a0593 | ||
|
|
14e89575d1 | ||
|
|
4e7003ca5e | ||
|
|
6bc11b01f5 | ||
|
|
b5ada5d2d5 | ||
|
|
21ff9b81f9 | ||
|
|
cdf0c29d01 | ||
|
|
57cc5a4692 | ||
|
|
7cb58d4f26 | ||
|
|
b1e9f631dc | ||
|
|
0a25ec2037 | ||
|
|
3164afa46a | ||
|
|
bff75b811d | ||
|
|
d7b729cc98 | ||
|
|
8917b88a5a | ||
|
|
53e40480f2 | ||
|
|
9c20e91563 | ||
|
|
582af7a8b0 | ||
|
|
62ed8a631e | ||
|
|
bca605c632 | ||
|
|
c9cf7c5190 | ||
|
|
e29e35c093 | ||
|
|
85276767eb | ||
|
|
1de911122a | ||
|
|
68cc93da1c | ||
|
|
419915d752 | ||
|
|
63572d43f6 | ||
|
|
498325e6e7 | ||
|
|
5c8d682a83 |
8
.env
8
.env
@@ -16,7 +16,6 @@ SITE_NAME=null
|
||||
USER_INFO_COOKIE_NAME=null
|
||||
AUTHN_MINIMAL_HEADER=true
|
||||
LOGIN_ISSUE_SUPPORT_LINK=''
|
||||
REGISTRATION_OPTIONAL_FIELDS=''
|
||||
USER_SURVEY_COOKIE_NAME=null
|
||||
COOKIE_DOMAIN=null
|
||||
WELCOME_PAGE_SUPPORT_LINK=null
|
||||
@@ -24,3 +23,10 @@ INFO_EMAIL=''
|
||||
DISABLE_ENTERPRISE_LOGIN=''
|
||||
REGISTER_CONVERSION_COOKIE_NAME=null
|
||||
ENABLE_PROGRESSIVE_PROFILING=''
|
||||
MARKETING_EMAILS_OPT_IN=''
|
||||
ENABLE_COPPA_COMPLIANCE=''
|
||||
ZENDESK_KEY=''
|
||||
ZENDESK_LOGO_URL=''
|
||||
APP_ID=''
|
||||
MFE_CONFIG_API_URL=''
|
||||
ENABLE_COOKIE_POLICY_BANNER=''
|
||||
|
||||
@@ -17,16 +17,22 @@ MARKETING_SITE_BASE_URL='http://localhost:18000'
|
||||
ORDER_HISTORY_URL='http://localhost:1996/orders'
|
||||
REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh'
|
||||
SEGMENT_KEY=''
|
||||
SITE_NAME='edX'
|
||||
SITE_NAME='Your Platform Name Here'
|
||||
USER_INFO_COOKIE_NAME='edx-user-info'
|
||||
AUTHN_MINIMAL_HEADER=true
|
||||
LOGIN_ISSUE_SUPPORT_LINK='/login-issue-support-url'
|
||||
TOS_AND_HONOR_CODE='http://localhost:18000/honor'
|
||||
TOS_LINK='http://localhost:18000/tos'
|
||||
PRIVACY_POLICY='http://localhost:18000/privacy'
|
||||
REGISTRATION_OPTIONAL_FIELDS=''
|
||||
USER_SURVEY_COOKIE_NAME='openedx-user-survey-type'
|
||||
COOKIE_DOMAIN='localhost'
|
||||
WELCOME_PAGE_SUPPORT_LINK='http://localhost:1999/welcome'
|
||||
INFO_EMAIL='info@edx.org'
|
||||
DISABLE_ENTERPRISE_LOGIN=''
|
||||
REGISTER_CONVERSION_COOKIE_NAME='openedx-user-register-conversion'
|
||||
ENABLE_COPPA_COMPLIANCE=''
|
||||
MARKETING_EMAILS_OPT_IN=''
|
||||
ZENDESK_KEY=''
|
||||
ZENDESK_LOGO_URL=''
|
||||
APP_ID=''
|
||||
MFE_CONFIG_API_URL=''
|
||||
|
||||
@@ -15,10 +15,16 @@ MARKETING_SITE_BASE_URL='http://localhost:18000'
|
||||
ORDER_HISTORY_URL='http://localhost:1996/orders'
|
||||
REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh'
|
||||
SEGMENT_KEY=''
|
||||
SITE_NAME='edX'
|
||||
SITE_NAME='Your Platform Name Here'
|
||||
USER_INFO_COOKIE_NAME='edx-user-info'
|
||||
LOGIN_ISSUE_SUPPORT_LINK='https://login-issue-support-url.com'
|
||||
USER_SURVEY_COOKIE_NAME='openedx-user-survey-type'
|
||||
WELCOME_PAGE_SUPPORT_LINK='http://localhost:1999/welcome'
|
||||
DISABLE_ENTERPRISE_LOGIN=''
|
||||
REGISTER_CONVERSION_COOKIE_NAME='openedx-user-register-conversion'
|
||||
MARKETING_EMAILS_OPT_IN=''
|
||||
ENABLE_COPPA_COMPLIANCE=''
|
||||
ZENDESK_KEY=''
|
||||
ZENDESK_LOGO_URL=''
|
||||
APP_ID=''
|
||||
MFE_CONFIG_API_URL=''
|
||||
|
||||
26
.eslintrc.js
26
.eslintrc.js
@@ -20,5 +20,31 @@ module.exports = createConfig('eslint', {
|
||||
assert: 'htmlFor',
|
||||
depth: 25
|
||||
}],
|
||||
'sort-imports': ['error', {ignoreCase: true, ignoreDeclarationSort: true}],
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
groups: [
|
||||
'builtin',
|
||||
'external',
|
||||
'internal',
|
||||
['sibling', 'parent'],
|
||||
'index',
|
||||
],
|
||||
pathGroups: [
|
||||
{
|
||||
pattern: '@(react|react-dom|react-redux)',
|
||||
group: 'external',
|
||||
position: 'before',
|
||||
},
|
||||
],
|
||||
pathGroupsExcludedImportTypes: ['react'],
|
||||
'newlines-between': 'always',
|
||||
alphabetize: {
|
||||
order: 'asc',
|
||||
caseInsensitive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
24
.github/pull_request_template.md
vendored
Normal file
24
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
### Description
|
||||
|
||||
Include a description of your changes here, along with a link to any relevant Jira tickets and/or Github issues.
|
||||
|
||||
#### How Has This Been Tested?
|
||||
|
||||
Please describe in detail how you tested your changes.
|
||||
|
||||
#### Screenshots/sandbox (optional):
|
||||
Include a link to the sandbox for design changes or screenshot for before and after. **Remove this section if its not applicable.**
|
||||
|
||||
|Before|After|
|
||||
|-------|-----|
|
||||
| | |
|
||||
|
||||
#### Merge Checklist
|
||||
|
||||
* [ ] If your update includes visual changes, have they been reviewed by a designer? Send them a link to the Sandbox, if applicable.
|
||||
* [ ] Is there adequate test coverage for your changes?
|
||||
|
||||
#### Post-merge Checklist
|
||||
|
||||
* [ ] Deploy the changes to prod after verifying on stage or ask **@openedx/vanguards** to do it.
|
||||
* [ ] 🎉 🙌 Celebrate! Thanks for your contribution.
|
||||
19
.github/workflows/add-depr-ticket-to-depr-board.yml
vendored
Normal file
19
.github/workflows/add-depr-ticket-to-depr-board.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# Run the workflow that adds new tickets that are either:
|
||||
# - labelled "DEPR"
|
||||
# - title starts with "[DEPR]"
|
||||
# - body starts with "Proposal Date" (this is the first template field)
|
||||
# to the org-wide DEPR project board
|
||||
|
||||
name: Add newly created DEPR issues to the DEPR project board
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
routeissue:
|
||||
uses: openedx/.github/.github/workflows/add-depr-ticket-to-depr-board.yml@master
|
||||
secrets:
|
||||
GITHUB_APP_ID: ${{ secrets.GRAPHQL_AUTH_APP_ID }}
|
||||
GITHUB_APP_PRIVATE_KEY: ${{ secrets.GRAPHQL_AUTH_APP_PEM }}
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_ISSUE_BOT_TOKEN }}
|
||||
45
.github/workflows/ci.yml
vendored
Normal file
45
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
name: node_CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- '**'
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
node: [16]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Nodejs
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Verify No Uncommitted Package-Lock Changes
|
||||
run: make validate-no-uncommitted-package-lock-changes
|
||||
|
||||
- name: Run i18n_extract
|
||||
run: npm run i18n_extract
|
||||
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
|
||||
- name: Test
|
||||
run: npm run test
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Run Code Coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
10
.github/workflows/commitlint.yml
vendored
Normal file
10
.github/workflows/commitlint.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Run commitlint on the commit messages in a pull request.
|
||||
|
||||
name: Lint Commit Messages
|
||||
|
||||
on:
|
||||
- pull_request
|
||||
|
||||
jobs:
|
||||
commitlint:
|
||||
uses: openedx/.github/.github/workflows/commitlint.yml@master
|
||||
13
.github/workflows/lockfileversion-check.yml
vendored
Normal file
13
.github/workflows/lockfileversion-check.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#check package-lock file version
|
||||
|
||||
name: Lockfile Version check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
version-check:
|
||||
uses: openedx/.github/.github/workflows/lockfileversion-check.yml@master
|
||||
@@ -1,7 +1,6 @@
|
||||
.eslintignore
|
||||
.eslintrc.json
|
||||
.gitignore
|
||||
.travis.yml
|
||||
docker-compose.yml
|
||||
Dockerfile
|
||||
Makefile
|
||||
|
||||
13
.travis.yml
13
.travis.yml
@@ -1,13 +0,0 @@
|
||||
language: node_js
|
||||
node_js: 12
|
||||
install:
|
||||
- npm ci
|
||||
script:
|
||||
- make validate-no-uncommitted-package-lock-changes
|
||||
- npm run i18n_extract
|
||||
- npm run lint
|
||||
- npm run test
|
||||
- npm run build
|
||||
- npm run is-es5
|
||||
after_success:
|
||||
- codecov
|
||||
@@ -1,8 +1,9 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[edx-platform.frontend-app-authn]
|
||||
[o:open-edx:p:edx-platform:r:frontend-app-authn]
|
||||
file_filter = src/i18n/messages/<lang>.json
|
||||
source_file = src/i18n/transifex_input.json
|
||||
source_lang = en
|
||||
type = KEYVALUEJSON
|
||||
type = KEYVALUEJSON
|
||||
|
||||
|
||||
16
Makefile
Executable file → Normal file
16
Makefile
Executable file → Normal file
@@ -1,11 +1,9 @@
|
||||
transifex_resource = frontend-app-authn
|
||||
transifex_langs = "ar,fr,es_419,zh_CN"
|
||||
export TRANSIFEX_RESOURCE = frontend-app-authn
|
||||
transifex_langs = "ar,fr,es_419,zh_CN,it_IT,pt_PT,de_DE,uk,ru,hi"
|
||||
|
||||
transifex_utils = ./node_modules/.bin/transifex-utils.js
|
||||
i18n = ./src/i18n
|
||||
transifex_input = $(i18n)/transifex_input.json
|
||||
tx_url1 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transifex_resource)/translation/en/strings/
|
||||
tx_url2 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transifex_resource)/source/
|
||||
|
||||
# This directory must match .babelrc .
|
||||
transifex_temp = ./temp/babel-plugin-react-intl
|
||||
@@ -38,17 +36,17 @@ push_translations:
|
||||
# Pushing strings to Transifex...
|
||||
tx push -s
|
||||
# Fetching hashes from Transifex...
|
||||
./node_modules/reactifex/bash_scripts/get_hashed_strings.sh $(tx_url1)
|
||||
./node_modules/@edx/reactifex/bash_scripts/get_hashed_strings_v3.sh
|
||||
# Writing out comments to file...
|
||||
$(transifex_utils) $(transifex_temp) --comments
|
||||
$(transifex_utils) $(transifex_temp) --comments --v3-scripts-path
|
||||
# Pushing comments to Transifex...
|
||||
./node_modules/reactifex/bash_scripts/put_comments.sh $(tx_url2)
|
||||
./node_modules/@edx/reactifex/bash_scripts/put_comments_v3.sh
|
||||
|
||||
# Pulls translations from Transifex.
|
||||
pull_translations:
|
||||
tx pull -f --mode reviewed --language=$(transifex_langs)
|
||||
tx pull -t -f --mode reviewed --languages=$(transifex_langs)
|
||||
|
||||
# This target is used by Travis.
|
||||
# This target is used by CI.
|
||||
validate-no-uncommitted-package-lock-changes:
|
||||
# Checking for package-lock.json changes...
|
||||
git diff --exit-code package-lock.json
|
||||
|
||||
141
README.rst
141
README.rst
@@ -1,48 +1,143 @@
|
||||
|Build Status| |Codecov| |license|
|
||||
|Build Status| |ci-badge| |Codecov| |semantic-release|
|
||||
|
||||
frontend-app-authn
|
||||
=================================
|
||||
====================
|
||||
|
||||
Please tag **@openedx/vanguards** on any PRs or issues. Thanks!
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This is a micro-frontend application responsible for the login, registration and password reset functionality.
|
||||
|
||||
Development
|
||||
-----------
|
||||
**What is the domain of this MFE?**
|
||||
|
||||
Start Devstack
|
||||
^^^^^^^^^^^^^^
|
||||
- Register page
|
||||
|
||||
To use this application `devstack <https://github.com/edx/devstack>`__ must be running.
|
||||
- Login page
|
||||
|
||||
- Start devstack
|
||||
- Forgot password page
|
||||
|
||||
Start the development server
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- Reset password page
|
||||
|
||||
In this project, install requirements and start the development server by running:
|
||||
- Progressive profiling page
|
||||
|
||||
.. code:: bash
|
||||
|
||||
npm install
|
||||
npm start # The server will run on port 1999
|
||||
Installation
|
||||
------------
|
||||
|
||||
Once the dev server is up visit http://localhost:1999/login.
|
||||
This MFE is bundled with `Devstack <https://github.com/openedx/devstack>`_, see the `Getting Started <https://github.com/openedx/devstack#getting-started>`_ section for setup instructions.
|
||||
|
||||
Configuration and Deployment
|
||||
----------------------------
|
||||
1. Install Devstack using the `Getting Started <https://github.com/openedx/devstack#getting-started>`_ instructions.
|
||||
|
||||
This MFE is configured via node environment variables supplied at build time. See the .env file for the list of required environment variables. Example build syntax with a single environment variable:
|
||||
2. Start up LMS, if it's not already started.
|
||||
|
||||
.. code:: bash
|
||||
4. Within this project (frontend-app-authn), install requirements and start the development server:
|
||||
|
||||
NODE_ENV=development ACCESS_TOKEN_COOKIE_NAME='edx-jwt-cookie-header-payload' npm run build
|
||||
.. code-block::
|
||||
|
||||
npm install
|
||||
npm start # The server will run on port 1999
|
||||
|
||||
5. Once the dev server is up, visit http://localhost:1999 to access the MFE
|
||||
|
||||
.. image:: ./docs/images/frontend-app-authn-localhost-preview.png
|
||||
|
||||
**Note:** Follow `Enable social auth locally <docs/how_tos/enable_social_auth.rst>`_ for enabling Social Sign-on Buttons (SSO) locally
|
||||
|
||||
Environment Variables/Setup Notes
|
||||
---------------------------------
|
||||
|
||||
This MFE is configured via environment variables supplied at build time. All micro-frontends have a shared set of required environment variables, as documented in the Open edX Developer Guide under `Required Environment Variables <https://edx.readthedocs.io/projects/edx-developer-docs/en/latest/developers_guide/micro_frontends_in_open_edx.html#required-environment-variables>`__.
|
||||
|
||||
The authentication micro-frontend also requires the following additional variable:
|
||||
|
||||
.. list-table:: Environment Variables
|
||||
:widths: 30 50 20
|
||||
:header-rows: 1
|
||||
|
||||
* - Name
|
||||
- Description / Usage
|
||||
- Example
|
||||
|
||||
* - ``LOGIN_ISSUE_SUPPORT_LINK``
|
||||
- The fully-qualified URL to the login issue support page in the target environment.
|
||||
- ``https://support.example.com``
|
||||
|
||||
* - ``ACTIVATION_EMAIL_SUPPORT_LINK``
|
||||
- The fully-qualified URL to the activation email support page in the target environment.
|
||||
- ``https://support.example.com``
|
||||
|
||||
* - ``PASSWORD_RESET_SUPPORT_LINK``
|
||||
- The fully-qualified URL to the password reset support page in the target environment.
|
||||
- ``https://support.example.com``
|
||||
|
||||
* - ``WELCOME_PAGE_SUPPORT_LINK``
|
||||
- The fully-qualified URL to the welcome support page in the target environment.
|
||||
- ``https://support.example.com``
|
||||
|
||||
* - ``TOS_AND_HONOR_CODE``
|
||||
- The fully-qualified URL to the Honor code page in the target environment.
|
||||
- ``https://example.com/honor``
|
||||
|
||||
* - ``TOS_LINK``
|
||||
- The fully-qualified URL to the Terms of service page in the target environment.
|
||||
- ``https://example.com/tos``
|
||||
|
||||
* - ``PRIVACY_POLICY``
|
||||
- The fully-qualified URL to the Privacy policy page in the target environment.
|
||||
- ``https://example.com/privacy``
|
||||
|
||||
* - ``INFO_EMAIL``
|
||||
- The valid email address for information query regarding the target environment.
|
||||
- ``info@example.com``
|
||||
|
||||
* - ``ENABLE_DYNAMIC_REGISTRATION_FIELDS``
|
||||
- Enables support for configurable registration fields on the MFE. This flag must be enabled to show any required registration field besides the default fields (name, email, username, password).
|
||||
- ``true`` | ``''`` (empty strings are falsy)
|
||||
|
||||
* - ``ENABLE_PROGRESSIVE_PROFILING``
|
||||
- Enables support for progressive profiling. If enabled, users are redirected to a second page where data for optional registration fields can be collected.
|
||||
- ``true`` | ``''`` (empty strings are falsy)
|
||||
|
||||
* - ``DISABLE_ENTERPRISE_LOGIN``
|
||||
- Disables the enterprise login from Authn MFE.
|
||||
- ``true`` | ``''`` (empty strings are falsy)
|
||||
|
||||
edX-specific Environment Variables
|
||||
**********************************
|
||||
|
||||
Furthermore, there are several edX-specific environment variables that enable integrations with closed-source services private to the edX organization, and might be unsupported in Open edX.
|
||||
|
||||
.. list-table:: edX-specific Environment Variables
|
||||
:widths: 30 50 20
|
||||
:header-rows: 1
|
||||
|
||||
* - Name
|
||||
- Description / Usage
|
||||
- Example
|
||||
|
||||
* - ``MARKETING_EMAILS_OPT_IN``
|
||||
- Enables support for opting in marketing emails that helps us getting user consent for sending marketing emails.
|
||||
- ``true`` | ``''`` (empty strings are falsy)
|
||||
|
||||
For more information see the document: `Micro-frontend applications in Open
|
||||
edX <https://github.com/edx/edx-developer-docs/blob/5191e800bf16cf42f25c58c58f983bdaf7f9305d/docs/micro-frontends-in-open-edx.rst>`__.
|
||||
edX <https://edx.readthedocs.io/projects/edx-developer-docs/en/latest/developers_guide/micro_frontends_in_open_edx.html#required-environment-variables>`__.
|
||||
|
||||
Known Issues
|
||||
------------
|
||||
|
||||
None
|
||||
|
||||
|
||||
==============================
|
||||
|
||||
.. |Build Status| image:: https://api.travis-ci.com/edx/frontend-app-authn.svg?branch=master
|
||||
:target: https://travis-ci.com/edx/frontend-app-authn
|
||||
.. |Codecov| image:: https://img.shields.io/codecov/c/github/edx/frontend-app-authn
|
||||
:target: https://codecov.io/gh/edx/frontend-app-authn
|
||||
.. |license| image:: https://img.shields.io/npm/l/@edx/frontend-app-authn.svg
|
||||
:target: @edx/frontend-app-authn
|
||||
.. |ci-badge| image:: https://github.com/openedx/edx-developer-docs/actions/workflows/ci.yml/badge.svg
|
||||
:target: https://github.com/openedx/edx-developer-docs/actions/workflows/ci.yml
|
||||
:alt: Continuous Integration
|
||||
.. |semantic-release| image:: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
|
||||
:target: https://github.com/semantic-release/semantic-release
|
||||
14
docs/how_tos/enable_social_auth.rst
Normal file
14
docs/how_tos/enable_social_auth.rst
Normal file
@@ -0,0 +1,14 @@
|
||||
Enable Social Auth Locally
|
||||
--------------------------
|
||||
|
||||
Please follow the steps below to enable social auth (SSO) locally.
|
||||
|
||||
1. Follow `Enabling Third Party Authentication <https://edx.readthedocs.io/projects/edx-installing-configuring-and-running/en/latest/configuration/tpa/index.html>`_ for backend configuration.
|
||||
|
||||
2. Authn has a component for rendering Social Auth providers at frontend which goes through each provider.
|
||||
|
||||
* If the provider has an ``iconImage``, then it will be rendered as image in SSO button.
|
||||
|
||||
* If ``iconImage`` is not available in provider, but the provider's ``iconClass`` is from the supported icon classes ``['apple', 'facebook', 'google', 'microsoft']`` then it is used as icon image.
|
||||
|
||||
* If ``iconClass`` doesn't match the supported icon classes then the ``faSignInAlt`` from font awesome icons is used as icon image for SSO button.
|
||||
@@ -2,4 +2,4 @@
|
||||
React App i18n HOWTO
|
||||
####################
|
||||
|
||||
This document has moved to the frontend-platform repo: https://github.com/edx/frontend-platform/blob/master/docs/how_tos/i18n.rst
|
||||
This document has moved to the frontend-platform repo: https://github.com/openedx/frontend-platform/blob/master/docs/how_tos/i18n.rst
|
||||
|
||||
BIN
docs/images/frontend-app-authn-localhost-preview.png
Normal file
BIN
docs/images/frontend-app-authn-localhost-preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 311 KiB |
@@ -8,5 +8,7 @@ module.exports = createConfig('jest', {
|
||||
'src/setupTest.js',
|
||||
'src/i18n',
|
||||
'src/index.jsx',
|
||||
'MainApp.jsx',
|
||||
],
|
||||
testEnvironment: 'jsdom',
|
||||
});
|
||||
|
||||
@@ -5,5 +5,4 @@ nick: Authn MFE
|
||||
oeps: {}
|
||||
owner: edx/vanguards
|
||||
openedx-release:
|
||||
maybe: true # Delete this "maybe" line when you have decided about Open edX inclusion.
|
||||
ref: master
|
||||
|
||||
52378
package-lock.json
generated
52378
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
81
package.json
81
package.json
@@ -4,16 +4,14 @@
|
||||
"description": "Frontend application template",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/edx/frontend-app-authn.git"
|
||||
"url": "git+https://github.com/openedx/frontend-app-authn.git"
|
||||
},
|
||||
"browserslist": [
|
||||
"last 2 versions",
|
||||
"ie 11"
|
||||
"extends @edx/browserslist-config"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "fedx-scripts webpack",
|
||||
"i18n_extract": "BABEL_ENV=i18n fedx-scripts babel src --quiet > /dev/null",
|
||||
"is-es5": "es-check es5 ./dist/*.js",
|
||||
"lint": "fedx-scripts eslint --ext .js --ext .jsx .",
|
||||
"snapshot": "fedx-scripts jest --updateSnapshot",
|
||||
"start": "fedx-scripts webpack-dev-server --progress",
|
||||
@@ -26,64 +24,65 @@
|
||||
},
|
||||
"author": "edX",
|
||||
"license": "AGPL-3.0",
|
||||
"homepage": "https://github.com/edx/frontend-app-authn#readme",
|
||||
"homepage": "https://github.com/openedx/frontend-app-authn#readme",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/edx/frontend-app-authn/issues"
|
||||
"url": "https://github.com/openedx/frontend-app-authn/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@edx/brand": "npm:@edx/brand-openedx@1.1.0",
|
||||
"@edx/frontend-component-cookie-policy-banner": "2.1.12",
|
||||
"@edx/frontend-platform": "1.12.0",
|
||||
"@edx/paragon": "16.6.1",
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.32",
|
||||
"@fortawesome/free-brands-svg-icons": "5.15.1",
|
||||
"@fortawesome/free-regular-svg-icons": "5.15.1",
|
||||
"@fortawesome/free-solid-svg-icons": "5.15.1",
|
||||
"@fortawesome/react-fontawesome": "0.1.13",
|
||||
"classnames": "2.2.6",
|
||||
"core-js": "3.9.1",
|
||||
"@edx/frontend-component-cookie-policy-banner": "2.2.0",
|
||||
"@edx/frontend-platform": "4.2.0",
|
||||
"@edx/paragon": "20.20.0",
|
||||
"@fortawesome/fontawesome-svg-core": "6.2.1",
|
||||
"@fortawesome/free-brands-svg-icons": "6.2.1",
|
||||
"@fortawesome/free-regular-svg-icons": "6.2.1",
|
||||
"@fortawesome/free-solid-svg-icons": "6.2.1",
|
||||
"@fortawesome/react-fontawesome": "0.2.0",
|
||||
"@redux-devtools/extension": "3.2.3",
|
||||
"classnames": "2.3.2",
|
||||
"core-js": "3.26.1",
|
||||
"extract-react-intl-messages": "4.1.1",
|
||||
"fastest-levenshtein": "1.0.12",
|
||||
"fastest-levenshtein": "1.0.16",
|
||||
"form-urlencoded": "4.2.1",
|
||||
"formik": "2.2.6",
|
||||
"lodash.camelcase": "4.3.0",
|
||||
"lodash.snakecase": "4.1.1",
|
||||
"prop-types": "15.7.2",
|
||||
"prop-types": "15.8.1",
|
||||
"query-string": "5.1.1",
|
||||
"react": "16.14.0",
|
||||
"react-dom": "16.14.0",
|
||||
"react-helmet": "6.1.0",
|
||||
"react-loading-skeleton": "2.2.0",
|
||||
"react-onclickoutside": "6.11.2",
|
||||
"react-redux": "7.2.3",
|
||||
"react-onclickoutside": "6.12.2",
|
||||
"react-redux": "7.2.9",
|
||||
"react-responsive": "8.2.0",
|
||||
"react-router": "5.2.0",
|
||||
"react-router-dom": "5.2.0",
|
||||
"redux": "4.0.5",
|
||||
"redux-devtools-extension": "2.13.8",
|
||||
"react-router": "5.3.4",
|
||||
"react-router-dom": "5.3.4",
|
||||
"redux": "4.2.0",
|
||||
"redux-logger": "3.0.6",
|
||||
"redux-mock-store": "1.5.4",
|
||||
"redux-saga": "1.1.3",
|
||||
"redux-thunk": "2.3.0",
|
||||
"regenerator-runtime": "0.13.9",
|
||||
"reselect": "4.0.0",
|
||||
"universal-cookie": "^4.0.4"
|
||||
"redux-saga": "1.2.1",
|
||||
"redux-thunk": "2.4.2",
|
||||
"regenerator-runtime": "0.13.11",
|
||||
"reselect": "4.1.7",
|
||||
"sanitize-html": "2.7.3",
|
||||
"semver-regex": "3.1.4",
|
||||
"universal-cookie": "4.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@edx/frontend-build": "5.6.11",
|
||||
"babel-plugin-react-intl": "8.2.25",
|
||||
"codecov": "3.8.1",
|
||||
"@edx/browserslist-config": "^1.1.1",
|
||||
"@edx/frontend-build": "11.0.2",
|
||||
"@edx/reactifex": "1.1.0",
|
||||
"babel-plugin-formatjs": "10.3.31",
|
||||
"enzyme": "3.11.0",
|
||||
"enzyme-adapter-react-16": "1.15.6",
|
||||
"es-check": "5.2.3",
|
||||
"glob": "7.1.6",
|
||||
"history": "5.0.0",
|
||||
"husky": "4.3.8",
|
||||
"jest": "26.6.3",
|
||||
"react-test-renderer": "16.14.0",
|
||||
"reactifex": "1.1.1"
|
||||
"enzyme-adapter-react-16": "1.15.7",
|
||||
"eslint-plugin-import": "2.26.0",
|
||||
"glob": "7.2.3",
|
||||
"history": "5.3.0",
|
||||
"husky": "7.0.4",
|
||||
"jest": "27.5.1",
|
||||
"react-test-renderer": "16.14.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<!doctype html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>Authn | edX</title>
|
||||
<title>Authn | <%= process.env.SITE_NAME %></title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="shortcut icon" href="<%=htmlWebpackPlugin.options.FAVICON_URL%>" type="image/x-icon" />
|
||||
<% if (process.env.OPTIMIZELY_URL) { %>
|
||||
<script
|
||||
src="<%= process.env.OPTIMIZELY_URL %>"
|
||||
@@ -14,6 +13,58 @@
|
||||
src="<%= process.env.MARKETING_SITE_BASE_URL %>/optimizelyjs/<%= process.env.OPTIMIZELY_PROJECT_ID %>.js"
|
||||
></script>
|
||||
<% } %>
|
||||
<% if (process.env.ZENDESK_KEY) { %>
|
||||
<script
|
||||
id="ze-snippet"
|
||||
src="https://static.zdassets.com/ekr/snippet.js?key=<%= process.env.ZENDESK_KEY %>"
|
||||
>
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
window.zESettings = {
|
||||
cookies: true,
|
||||
webWidget: {
|
||||
contactOptions: {
|
||||
enabled: false,
|
||||
},
|
||||
chat: {
|
||||
suppress: false,
|
||||
},
|
||||
contactForm: {
|
||||
ticketForms: [
|
||||
{
|
||||
id: 360003368814,
|
||||
subject: false,
|
||||
fields: [
|
||||
{
|
||||
id: 'description',
|
||||
prefill: {
|
||||
'*': '',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
selectTicketForm: {
|
||||
'*': 'Please choose your request type:',
|
||||
},
|
||||
attachments: true,
|
||||
},
|
||||
helpCenter: {
|
||||
originalArticleButton: true,
|
||||
},
|
||||
answerBot: {
|
||||
suppress: false,
|
||||
contactOnlyAfterQuery: true,
|
||||
title: { '*': 'edX Support' },
|
||||
avatar: {
|
||||
url: '<%= process.env.ZENDESK_LOGO_URL %>',
|
||||
name: { '*': 'edX Support' },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<% } %>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
{
|
||||
"extends": [
|
||||
"config:base"
|
||||
"config:base",
|
||||
":automergeLinters",
|
||||
":automergeTesters",
|
||||
":automergeMinor",
|
||||
":noUnscheduledUpdates",
|
||||
":semanticCommits"
|
||||
],
|
||||
"patch": {
|
||||
"automerge": true
|
||||
},
|
||||
"rebaseStalePrs": true
|
||||
"rebaseStalePrs": true,
|
||||
"schedule": [
|
||||
"every weekday"
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchPackageNames": ["node", "npm"],
|
||||
"enabled": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,25 +1,30 @@
|
||||
import React from 'react';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Redirect, Route, Switch } from 'react-router-dom';
|
||||
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
|
||||
import {
|
||||
UnAuthOnlyRoute, registerIcons, NotFoundPage, Logistration,
|
||||
Logistration, NotFoundPage, registerIcons, UnAuthOnlyRoute,
|
||||
} from './common-components';
|
||||
import {
|
||||
LOGIN_PAGE, PAGE_NOT_FOUND, REGISTER_PAGE, RESET_PAGE, PASSWORD_RESET_CONFIRM, WELCOME_PAGE,
|
||||
} from './data/constants';
|
||||
import configureStore from './data/configureStore';
|
||||
import {
|
||||
LOGIN_PAGE, PAGE_NOT_FOUND, PASSWORD_RESET_CONFIRM, REGISTER_PAGE, RESET_PAGE, WELCOME_PAGE,
|
||||
} from './data/constants';
|
||||
import { updatePathWithQueryParams } from './data/utils';
|
||||
import ForgotPasswordPage from './forgot-password';
|
||||
import ResetPasswordPage from './reset-password';
|
||||
import WelcomePage from './welcome';
|
||||
import { ProgressiveProfiling } from './welcome';
|
||||
import './index.scss';
|
||||
|
||||
registerIcons();
|
||||
|
||||
const MainApp = () => (
|
||||
<AppProvider store={configureStore()}>
|
||||
<Helmet>
|
||||
<link rel="shortcut icon" href={getConfig().FAVICON_URL} type="image/x-icon" />
|
||||
</Helmet>
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<Redirect to={updatePathWithQueryParams(REGISTER_PAGE)} />
|
||||
@@ -28,7 +33,7 @@ const MainApp = () => (
|
||||
<UnAuthOnlyRoute exact path={REGISTER_PAGE} component={Logistration} />
|
||||
<UnAuthOnlyRoute exact path={RESET_PAGE} component={ForgotPasswordPage} />
|
||||
<Route exact path={PASSWORD_RESET_CONFIRM} component={ResetPasswordPage} />
|
||||
<Route exact path={WELCOME_PAGE} component={WelcomePage} />
|
||||
<Route exact path={WELCOME_PAGE} component={ProgressiveProfiling} />
|
||||
<Route path={PAGE_NOT_FOUND} component={NotFoundPage} />
|
||||
<Route path="*">
|
||||
<Redirect to={PAGE_NOT_FOUND} />
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Col, Hyperlink, Image, Row,
|
||||
} from '@edx/paragon';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
const AuthExtraLargeLayout = (props) => {
|
||||
const { intl, username, variant } = props;
|
||||
|
||||
return (
|
||||
<div className="container row p-0 m-0 large-screen-container">
|
||||
<div className="col-md-9 p-0 screen-header-light">
|
||||
<Hyperlink destination={getConfig().MARKETING_SITE_BASE_URL}>
|
||||
<Image alt="edx" className="logo position-absolute" src={getConfig().LOGO_WHITE_URL} />
|
||||
</Hyperlink>
|
||||
<div className="min-vh-100 d-flex align-items-center">
|
||||
<div>
|
||||
<Row>
|
||||
<Col xs={3}>
|
||||
<svg className={classNames(
|
||||
'ml-5 mt-5',
|
||||
{
|
||||
'extra-large-svg-line': variant === 'xl',
|
||||
'extra-extra-large-svg-line': variant === 'xxl',
|
||||
},
|
||||
)}
|
||||
>
|
||||
<line x1="60" y1="0" x2="5" y2="220" />
|
||||
</svg>
|
||||
</Col>
|
||||
<Col xs={9}>
|
||||
<div className={classNames(
|
||||
'data-hj-suppress',
|
||||
{
|
||||
h3: variant === 'xl',
|
||||
h2: variant === 'xxl',
|
||||
},
|
||||
)}
|
||||
>
|
||||
{intl.formatMessage(
|
||||
messages['welcome.to.platform'], { siteName: getConfig().SITE_NAME, username },
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
'text-primary',
|
||||
{
|
||||
'display-1': variant === 'xl',
|
||||
'display-2': variant === 'xxl',
|
||||
},
|
||||
)}
|
||||
>
|
||||
{intl.formatMessage(messages['complete.your.profile.1'])}
|
||||
<span className="text-accent-a">
|
||||
<br />
|
||||
{intl.formatMessage(messages['complete.your.profile.2'])}
|
||||
</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-3 p-0 screen-polygon">
|
||||
<svg
|
||||
width="100%"
|
||||
height="100%"
|
||||
className="m1-n1 large-screen-svg-light"
|
||||
preserveAspectRatio="xMaxYMin meet"
|
||||
>
|
||||
<g transform="skewX(171.6)">
|
||||
<rect x="0" y="0" height="100%" width="100%" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
AuthExtraLargeLayout.defaultProps = {
|
||||
variant: 'xl',
|
||||
};
|
||||
|
||||
AuthExtraLargeLayout.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
username: PropTypes.string.isRequired,
|
||||
variant: PropTypes.oneOf(['xl', 'xxl']),
|
||||
};
|
||||
|
||||
export default injectIntl(AuthExtraLargeLayout);
|
||||
46
src/base-component/AuthLargeLayout.jsx
Normal file
46
src/base-component/AuthLargeLayout.jsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Hyperlink, Image } from '@edx/paragon';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
const AuthLargeLayout = ({ intl, username }) => (
|
||||
<div className="w-50 d-flex">
|
||||
<div className="col-md-10 bg-light-200 p-0">
|
||||
<Hyperlink destination={getConfig().MARKETING_SITE_BASE_URL}>
|
||||
<Image className="logo position-absolute" alt={getConfig().SITE_NAME} src={getConfig().LOGO_URL} />
|
||||
</Hyperlink>
|
||||
<div className="min-vh-100 d-flex align-items-center">
|
||||
<div className="large-screen-left-container mr-n4.5 large-yellow-line mt-5" />
|
||||
<div>
|
||||
<h1 className="welcome-to-platform data-hj-suppress">
|
||||
{intl.formatMessage(messages['welcome.to.platform'], { siteName: getConfig().SITE_NAME, username })}
|
||||
</h1>
|
||||
<h2 className="complete-your-profile">
|
||||
{intl.formatMessage(messages['complete.your.profile.1'])}
|
||||
<div className="text-accent-a">
|
||||
{intl.formatMessage(messages['complete.your.profile.2'])}
|
||||
</div>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-2 bg-white p-0">
|
||||
<svg className="m1-n1 w-100 h-100 large-screen-svg-light" preserveAspectRatio="xMaxYMin meet">
|
||||
<g transform="skewX(171.6)">
|
||||
<rect x="0" y="0" height="100%" width="100%" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
AuthLargeLayout.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
username: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(AuthLargeLayout);
|
||||
@@ -1,65 +1,45 @@
|
||||
import React from 'react';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import {
|
||||
Col, Hyperlink, Image, Row,
|
||||
} from '@edx/paragon';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Hyperlink, Image } from '@edx/paragon';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
const AuthMediumLayout = (props) => {
|
||||
const { intl, username } = props;
|
||||
|
||||
return (
|
||||
<div className="container row p-0 mb-3 medium-container">
|
||||
<div className="col-md-10 p-0 screen-header-light">
|
||||
const AuthMediumLayout = ({ intl, username }) => (
|
||||
<>
|
||||
<div className="w-100 medium-screen-top-stripe" />
|
||||
<div className="w-100 p-0 mb-3 d-flex">
|
||||
<div className="col-md-10 bg-light-200">
|
||||
<Hyperlink destination={getConfig().MARKETING_SITE_BASE_URL}>
|
||||
<Image alt="edx" className="logo" src={getConfig().LOGO_WHITE_URL} />
|
||||
<Image className="logo" alt={getConfig().SITE_NAME} src={getConfig().LOGO_URL} />
|
||||
</Hyperlink>
|
||||
<div className="d-flex align-items-center justify-content-center ml-6">
|
||||
<div className="d-flex align-items-center justify-content-center mb-4 ml-5">
|
||||
<div className="medium-yellow-line mt-5 mr-n2" />
|
||||
<div>
|
||||
<Row>
|
||||
<Col xs={3}>
|
||||
<svg className="medium-svg-line ml-5 mt-5">
|
||||
<line x1="60" y1="0" x2="5" y2="220" />
|
||||
</svg>
|
||||
</Col>
|
||||
<Col xs={9}>
|
||||
<h3 className="data-hj-suppress">
|
||||
{intl.formatMessage(
|
||||
messages['welcome.to.platform'], { siteName: getConfig().SITE_NAME, username },
|
||||
)}
|
||||
</h3>
|
||||
<div className="display-1 text-primary">
|
||||
{intl.formatMessage(messages['complete.your.profile.1'])}
|
||||
<span className="text-accent-a">
|
||||
<br />
|
||||
{intl.formatMessage(messages['complete.your.profile.2'])}
|
||||
</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<h1 className="h3 data-hj-suppress mw-320">
|
||||
{intl.formatMessage(messages['welcome.to.platform'], { siteName: getConfig().SITE_NAME, username })}
|
||||
</h1>
|
||||
<h2 className="display-1">
|
||||
{intl.formatMessage(messages['complete.your.profile.1'])}
|
||||
<div className="text-accent-a">
|
||||
{intl.formatMessage(messages['complete.your.profile.2'])}
|
||||
</div>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-2 p-0 screen-polygon">
|
||||
<svg
|
||||
width="100%"
|
||||
height="100%"
|
||||
className="medium-screen-svg-light"
|
||||
preserveAspectRatio="xMaxYMin meet"
|
||||
>
|
||||
<div className="col-md-2 bg-white p-0">
|
||||
<svg className="w-100 h-100 medium-screen-svg-light" preserveAspectRatio="xMaxYMin meet">
|
||||
<g transform="skewX(168)">
|
||||
<rect x="0" y="0" height="100%" width="100%" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
</>
|
||||
);
|
||||
|
||||
AuthMediumLayout.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
|
||||
@@ -1,68 +1,38 @@
|
||||
import React from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Col, Hyperlink, Image, Row,
|
||||
} from '@edx/paragon';
|
||||
import { Hyperlink, Image } from '@edx/paragon';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
const AuthSmallLayout = (props) => {
|
||||
const { intl, username, variant } = props;
|
||||
|
||||
return (
|
||||
<div className="small-screen-header-light">
|
||||
<Hyperlink destination={getConfig().MARKETING_SITE_BASE_URL}>
|
||||
<Image alt="edx" className="logo" src={getConfig().LOGO_WHITE_URL} />
|
||||
</Hyperlink>
|
||||
<div className={classNames('d-flex mt-3', { 'pl-6': variant === 'sm' })}>
|
||||
<div>
|
||||
<Row>
|
||||
<Col xs={3}>
|
||||
<svg className={classNames(
|
||||
'mt-4\.5', // eslint-disable-line no-useless-escape
|
||||
{
|
||||
'extra-small-svg-line': variant === 'xs',
|
||||
'small-svg-line': variant === 'sm',
|
||||
},
|
||||
)}
|
||||
>
|
||||
<line x1="60" y1="0" x2="5" y2="220" />
|
||||
</svg>
|
||||
</Col>
|
||||
<Col xs={9}>
|
||||
<h5 className="data-hj-suppress">
|
||||
{intl.formatMessage(
|
||||
messages['welcome.to.platform'], { siteName: getConfig().SITE_NAME, username },
|
||||
)}
|
||||
</h5>
|
||||
<h1>
|
||||
{intl.formatMessage(messages['complete.your.profile.1'])}
|
||||
<br />
|
||||
<span className="text-accent-a">
|
||||
{intl.formatMessage(messages['complete.your.profile.2'])}
|
||||
</span>
|
||||
</h1>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
const AuthSmallLayout = ({ intl, username }) => (
|
||||
<div className="min-vw-100 bg-light-200">
|
||||
<div className="col-md-12 small-screen-top-stripe" />
|
||||
<Hyperlink destination={getConfig().MARKETING_SITE_BASE_URL}>
|
||||
<Image className="logo-small" alt={getConfig().SITE_NAME} src={getConfig().LOGO_URL} />
|
||||
</Hyperlink>
|
||||
<div className="d-flex align-items-center mb-3 mt-3 mr-3">
|
||||
<div className="small-yellow-line mt-4.5" />
|
||||
<div>
|
||||
<h1 className="h5 data-hj-suppress">
|
||||
{intl.formatMessage(messages['welcome.to.platform'], { siteName: getConfig().SITE_NAME, username })}
|
||||
</h1>
|
||||
<h2 className="h1">
|
||||
{intl.formatMessage(messages['complete.your.profile.1'])}
|
||||
<div className="text-accent-a">
|
||||
{intl.formatMessage(messages['complete.your.profile.2'])}
|
||||
</div>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
AuthSmallLayout.defaultProps = {
|
||||
variant: 'sm',
|
||||
};
|
||||
</div>
|
||||
);
|
||||
|
||||
AuthSmallLayout.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
username: PropTypes.string.isRequired,
|
||||
variant: PropTypes.oneOf(['sm', 'xs']),
|
||||
};
|
||||
|
||||
export default injectIntl(AuthSmallLayout);
|
||||
|
||||
@@ -1,58 +1,39 @@
|
||||
import React from 'react';
|
||||
|
||||
import CookiePolicyBanner from '@edx/frontend-component-cookie-policy-banner';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
|
||||
import { getLocale } from '@edx/frontend-platform/i18n';
|
||||
import { breakpoints } from '@edx/paragon';
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import MediaQuery from 'react-responsive';
|
||||
|
||||
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
|
||||
import {
|
||||
ExtraSmall, Small, Medium, Large, ExtraLarge, ExtraExtraLarge,
|
||||
} from '@edx/paragon';
|
||||
import CookiePolicyBanner from '@edx/frontend-component-cookie-policy-banner';
|
||||
import { getLocale } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import AuthLargeLayout from './AuthLargeLayout';
|
||||
import AuthMediumLayout from './AuthMediumLayout';
|
||||
import AuthSmallLayout from './AuthSmallLayout';
|
||||
import LargeLayout from './LargeLayout';
|
||||
import MediumLayout from './MediumLayout';
|
||||
import SmallLayout from './SmallLayout';
|
||||
|
||||
import AuthExtraLargeLayout from './AuthExtraLargeLayout';
|
||||
import AuthMediumLayout from './AuthMediumLayout';
|
||||
import AuthSmallLayout from './AuthSmallLayout';
|
||||
|
||||
const BaseComponent = ({ children }) => {
|
||||
const authenticatedUser = getAuthenticatedUser();
|
||||
const BaseComponent = ({ children, showWelcomeBanner }) => {
|
||||
const authenticatedUser = showWelcomeBanner ? getAuthenticatedUser() : null;
|
||||
const username = authenticatedUser ? authenticatedUser.username : null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<CookiePolicyBanner languageCode={getLocale()} />
|
||||
<ExtraLarge>
|
||||
<div className="col-md-12 extra-large-screen-top-stripe" />
|
||||
</ExtraLarge>
|
||||
<ExtraExtraLarge>
|
||||
<div className="col-md-12 extra-large-screen-top-stripe" />
|
||||
</ExtraExtraLarge>
|
||||
|
||||
<div className={classNames('layout', { authenticated: authenticatedUser })}>
|
||||
<ExtraSmall>
|
||||
<div className="col-md-12 small-screen-top-stripe" />
|
||||
{authenticatedUser ? <AuthSmallLayout variant="xs" username={authenticatedUser.username} /> : <SmallLayout />}
|
||||
</ExtraSmall>
|
||||
<Small>
|
||||
<div className="col-md-12 small-screen-top-stripe" />
|
||||
{authenticatedUser ? <AuthSmallLayout username={authenticatedUser.username} /> : <SmallLayout />}
|
||||
</Small>
|
||||
<Medium>
|
||||
<div className="w-100 medium-screen-top-stripe" />
|
||||
{authenticatedUser ? <AuthMediumLayout username={authenticatedUser.username} /> : <MediumLayout />}
|
||||
</Medium>
|
||||
<Large>
|
||||
<div className="w-100 large-screen-top-stripe" />
|
||||
{authenticatedUser ? <AuthMediumLayout username={authenticatedUser.username} /> : <MediumLayout />}
|
||||
</Large>
|
||||
<ExtraLarge>
|
||||
{authenticatedUser ? <AuthExtraLargeLayout username={authenticatedUser.username} /> : <LargeLayout />}
|
||||
</ExtraLarge>
|
||||
<ExtraExtraLarge>
|
||||
{authenticatedUser ? <AuthExtraLargeLayout variant="xxl" username={authenticatedUser.username} /> : <LargeLayout />}
|
||||
</ExtraExtraLarge>
|
||||
{getConfig().ENABLE_COOKIE_POLICY_BANNER ? <CookiePolicyBanner languageCode={getLocale()} /> : null}
|
||||
<div className="col-md-12 extra-large-screen-top-stripe" />
|
||||
<div className="layout">
|
||||
<MediaQuery maxWidth={breakpoints.small.maxWidth - 1}>
|
||||
{authenticatedUser ? <AuthSmallLayout username={username} /> : <SmallLayout />}
|
||||
</MediaQuery>
|
||||
<MediaQuery minWidth={breakpoints.medium.minWidth} maxWidth={breakpoints.large.maxWidth - 1}>
|
||||
{authenticatedUser ? <AuthMediumLayout username={username} /> : <MediumLayout />}
|
||||
</MediaQuery>
|
||||
<MediaQuery minWidth={breakpoints.extraLarge.minWidth} maxWidth={breakpoints.extraExtraLarge.maxWidth}>
|
||||
{authenticatedUser ? <AuthLargeLayout username={username} /> : <LargeLayout />}
|
||||
</MediaQuery>
|
||||
|
||||
<div className={classNames('content', { 'align-items-center mt-0': authenticatedUser })}>
|
||||
{children}
|
||||
@@ -62,8 +43,13 @@ const BaseComponent = ({ children }) => {
|
||||
);
|
||||
};
|
||||
|
||||
BaseComponent.defaultProps = {
|
||||
showWelcomeBanner: false,
|
||||
};
|
||||
|
||||
BaseComponent.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
showWelcomeBanner: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default BaseComponent;
|
||||
|
||||
@@ -1,25 +1,35 @@
|
||||
import React from 'react';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Hyperlink, Image } from '@edx/paragon';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import LargeScreenLeftLayout from './LargeLeftLayout';
|
||||
import messages from './messages';
|
||||
|
||||
const LargeLayout = () => (
|
||||
<div className="container row p-0 m-0 large-screen-container">
|
||||
<div className="col-md-9 p-0 screen-header-primary">
|
||||
const LargeLayout = ({ intl }) => (
|
||||
<div className="w-50 d-flex">
|
||||
<div className="col-md-9 bg-primary-400">
|
||||
<Hyperlink destination={getConfig().MARKETING_SITE_BASE_URL}>
|
||||
<Image alt="edx" className="logo position-absolute" src={getConfig().LOGO_WHITE_URL} />
|
||||
<Image className="logo position-absolute" alt={getConfig().SITE_NAME} src={getConfig().LOGO_WHITE_URL} />
|
||||
</Hyperlink>
|
||||
<LargeScreenLeftLayout />
|
||||
<div className="min-vh-100 d-flex align-items-center">
|
||||
<div className={classNames({ 'large-yellow-line mr-n4.5': getConfig().SITE_NAME === 'edX' })} />
|
||||
<h1
|
||||
className={classNames(
|
||||
'display-2 text-white mw-xs',
|
||||
{ 'ml-6': getConfig().SITE_NAME !== 'edX' },
|
||||
)}
|
||||
>
|
||||
{intl.formatMessage(messages['start.learning'])}
|
||||
<div className="text-accent-a">
|
||||
{intl.formatMessage(messages['with.site.name'], { siteName: getConfig().SITE_NAME })}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-3 p-0 screen-polygon">
|
||||
<svg
|
||||
width="100%"
|
||||
height="100%"
|
||||
className="ml-n1 large-screen-svg-primary"
|
||||
preserveAspectRatio="xMaxYMin meet"
|
||||
>
|
||||
<div className="col-md-3 bg-white p-0">
|
||||
<svg className="ml-n1 w-100 h-100 large-screen-svg-primary" preserveAspectRatio="xMaxYMin meet">
|
||||
<g transform="skewX(171.6)">
|
||||
<rect x="0" y="0" height="100%" width="100%" />
|
||||
</g>
|
||||
@@ -28,4 +38,8 @@ const LargeLayout = () => (
|
||||
</div>
|
||||
);
|
||||
|
||||
export default LargeLayout;
|
||||
LargeLayout.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(LargeLayout);
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
const LargeLeftLayout = (props) => {
|
||||
const { intl } = props;
|
||||
|
||||
return (
|
||||
<div className="min-vh-100 pr-0 mt-lg-n2 d-flex align-items-center">
|
||||
<svg className="large-screen-svg-line ml-5">
|
||||
<line x1="50" y1="0" x2="10" y2="215" />
|
||||
</svg>
|
||||
<h1 className="large-heading">
|
||||
{intl.formatMessage(messages['start.learning'])}
|
||||
<span className="text-accent-a"><br />
|
||||
{intl.formatMessage(messages['with.site.name'], { siteName: getConfig().SITE_NAME })}
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
LargeLeftLayout.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(LargeLeftLayout);
|
||||
@@ -1,42 +1,47 @@
|
||||
import React from 'react';
|
||||
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Hyperlink, Image } from '@edx/paragon';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
const MediumLayout = (props) => {
|
||||
const { intl } = props;
|
||||
|
||||
return (
|
||||
<div className="container row p-0 mb-3 medium-screen-container">
|
||||
<div className="col-md-10 p-0 screen-header-primary">
|
||||
const MediumLayout = ({ intl }) => (
|
||||
<>
|
||||
<div className="w-100 medium-screen-top-stripe" />
|
||||
<div className="w-100 p-0 mb-3 d-flex">
|
||||
<div className="col-md-10 bg-primary-400">
|
||||
<Hyperlink destination={getConfig().MARKETING_SITE_BASE_URL}>
|
||||
<Image alt="edx" className="logo" src={getConfig().LOGO_WHITE_URL} />
|
||||
<Image alt={getConfig().SITE_NAME} className="logo" src={getConfig().LOGO_WHITE_URL} />
|
||||
</Hyperlink>
|
||||
<div className="row mt-4 justify-content-center">
|
||||
<svg className="medium-screen-svg-line pl-5">
|
||||
<line x1="50" y1="0" x2="10" y2="215" />
|
||||
</svg>
|
||||
<h1 className="medium-heading pb-4">
|
||||
{intl.formatMessage(messages['start.learning'])}
|
||||
<span className="text-accent-a"><br />
|
||||
{intl.formatMessage(messages['with.site.name'], { siteName: getConfig().SITE_NAME })}
|
||||
</span>
|
||||
</h1>
|
||||
<div className="d-flex align-items-center justify-content-center mb-4 ">
|
||||
<div className={classNames({ 'mt-1 medium-yellow-line': getConfig().SITE_NAME === 'edX' })} />
|
||||
<div>
|
||||
<h1
|
||||
className={classNames(
|
||||
'display-1 text-white mt-5 mb-5 mr-2',
|
||||
{ 'ml-4.5': getConfig().SITE_NAME !== 'edX' },
|
||||
)}
|
||||
>
|
||||
<span className="mr-2">{intl.formatMessage(messages['start.learning'])}</span>
|
||||
<span className="text-accent-a d-inline-block">
|
||||
{intl.formatMessage(messages['with.site.name'], { siteName: getConfig().SITE_NAME })}
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-2 p-0 screen-polygon">
|
||||
<svg width="100%" height="100%" className="medium-screen-svg-primary" preserveAspectRatio="xMaxYMin meet">
|
||||
<div className="col-md-2 bg-white p-0">
|
||||
<svg className="w-100 h-100 medium-screen-svg-primary" preserveAspectRatio="xMaxYMin meet">
|
||||
<g transform="skewX(168)">
|
||||
<rect x="0" y="0" height="100%" width="100%" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
</>
|
||||
);
|
||||
|
||||
MediumLayout.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
import React from 'react';
|
||||
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Hyperlink, Image } from '@edx/paragon';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
const SmallLayout = (props) => {
|
||||
const { intl } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="small-screen-header-primary">
|
||||
<Hyperlink destination={getConfig().MARKETING_SITE_BASE_URL}>
|
||||
<Image alt="edx" className="logo" src={getConfig().LOGO_WHITE_URL} />
|
||||
</Hyperlink>
|
||||
<div className="d-flex mt-3">
|
||||
<svg className="small-screen-svg-line">
|
||||
<line x1="55" y1="0" x2="40" y2="65" />
|
||||
</svg>
|
||||
<h1 className="small-heading pb-3">
|
||||
{intl.formatMessage(messages['start.learning'])}
|
||||
<br />
|
||||
<span className="text-accent-a">
|
||||
{intl.formatMessage(messages['with.site.name'], { siteName: getConfig().SITE_NAME })}
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
const SmallLayout = ({ intl }) => (
|
||||
<span className="bg-primary-400 w-100">
|
||||
<div className="col-md-12 small-screen-top-stripe" />
|
||||
<div>
|
||||
<Hyperlink destination={getConfig().MARKETING_SITE_BASE_URL}>
|
||||
<Image className="logo-small" alt={getConfig().SITE_NAME} src={getConfig().LOGO_WHITE_URL} />
|
||||
</Hyperlink>
|
||||
<div className="d-flex align-items-center mb-3 mt-3 mr-3">
|
||||
<div className={classNames({ 'small-yellow-line mr-n2.5': getConfig().SITE_NAME === 'edX' })} />
|
||||
<h1
|
||||
className={classNames(
|
||||
'text-white mt-3.5 mb-3.5',
|
||||
{ 'ml-4.5': getConfig().SITE_NAME !== 'edX' },
|
||||
)}
|
||||
>
|
||||
<span className="mr-1">{intl.formatMessage(messages['start.learning'])}</span>
|
||||
<span className="text-accent-a d-inline-block">
|
||||
{intl.formatMessage(messages['with.site.name'], { siteName: getConfig().SITE_NAME })}
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
|
||||
SmallLayout.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
import LargeLayout from '../LargeLayout';
|
||||
import MediumLayout from '../MediumLayout';
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import React from 'react';
|
||||
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import PropTypes from 'prop-types';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { faSignInAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Form, Button,
|
||||
Button, Form,
|
||||
} from '@edx/paragon';
|
||||
import { faSignInAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { LOGIN_PAGE, SUPPORTED_ICON_CLASSES } from '../data/constants';
|
||||
import messages from './messages';
|
||||
@@ -16,6 +15,7 @@ import messages from './messages';
|
||||
const EnterpriseSSO = (props) => {
|
||||
const { intl } = props;
|
||||
const tpaProvider = props.provider;
|
||||
const disablePublicAccountCreation = getConfig().ALLOW_PUBLIC_ACCOUNT_CREATION === false;
|
||||
|
||||
const handleSubmit = (e, url) => {
|
||||
e.preventDefault();
|
||||
@@ -62,12 +62,15 @@ const EnterpriseSSO = (props) => {
|
||||
<div className="mb-4" />
|
||||
<Button
|
||||
type="submit"
|
||||
id="other-ways-to-sign-in"
|
||||
variant="outline-primary"
|
||||
state="Complete"
|
||||
className="w-100"
|
||||
onClick={(e) => handleClick(e)}
|
||||
>
|
||||
{intl.formatMessage(messages['enterprisetpa.login.button.text'])}
|
||||
{disablePublicAccountCreation
|
||||
? intl.formatMessage(messages['enterprisetpa.login.button.text.public.account.creation.disabled'])
|
||||
: intl.formatMessage(messages['enterprisetpa.login.button.text'])}
|
||||
</Button>
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
@@ -24,9 +24,12 @@ const FormGroup = (props) => {
|
||||
<Form.Group controlId={props.name} className={props.className} isInvalid={props.errorMessage !== ''}>
|
||||
<Form.Control
|
||||
as={props.as}
|
||||
readOnly={props.readOnly}
|
||||
type={props.type}
|
||||
aria-invalid={props.errorMessage !== ''}
|
||||
className="form-field"
|
||||
autoComplete={props.autoComplete}
|
||||
spellCheck={props.spellCheck}
|
||||
name={props.name}
|
||||
value={props.value}
|
||||
onFocus={handleFocus}
|
||||
@@ -62,39 +65,43 @@ const FormGroup = (props) => {
|
||||
|
||||
FormGroup.defaultProps = {
|
||||
as: 'input',
|
||||
errorMessage: '',
|
||||
borderClass: '',
|
||||
autoComplete: null,
|
||||
handleBlur: null,
|
||||
handleChange: () => {},
|
||||
handleFocus: null,
|
||||
handleClick: null,
|
||||
helpText: [],
|
||||
options: null,
|
||||
trailingElement: null,
|
||||
type: 'text',
|
||||
borderClass: '',
|
||||
children: null,
|
||||
className: '',
|
||||
errorMessage: '',
|
||||
handleBlur: null,
|
||||
handleChange: () => {},
|
||||
handleClick: null,
|
||||
handleFocus: null,
|
||||
helpText: [],
|
||||
options: null,
|
||||
readOnly: false,
|
||||
spellCheck: null,
|
||||
trailingElement: null,
|
||||
type: 'text',
|
||||
};
|
||||
|
||||
FormGroup.propTypes = {
|
||||
as: PropTypes.string,
|
||||
errorMessage: PropTypes.string,
|
||||
borderClass: PropTypes.string,
|
||||
autoComplete: PropTypes.string,
|
||||
borderClass: PropTypes.string,
|
||||
children: PropTypes.element,
|
||||
className: PropTypes.string,
|
||||
errorMessage: PropTypes.string,
|
||||
floatingLabel: PropTypes.string.isRequired,
|
||||
handleBlur: PropTypes.func,
|
||||
handleChange: PropTypes.func,
|
||||
handleFocus: PropTypes.func,
|
||||
handleClick: PropTypes.func,
|
||||
handleFocus: PropTypes.func,
|
||||
helpText: PropTypes.arrayOf(PropTypes.string),
|
||||
name: PropTypes.string.isRequired,
|
||||
options: PropTypes.func,
|
||||
readOnly: PropTypes.bool,
|
||||
spellCheck: PropTypes.string,
|
||||
trailingElement: PropTypes.element,
|
||||
type: PropTypes.string,
|
||||
value: PropTypes.string.isRequired,
|
||||
children: PropTypes.element,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
export default FormGroup;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import React from 'react';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import PropTypes from 'prop-types';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Button, Hyperlink, Icon } from '@edx/paragon';
|
||||
import { Institution } from '@edx/paragon/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
export const RenderInstitutionButton = props => {
|
||||
@@ -70,7 +72,7 @@ const LogistrationDefaultProps = {
|
||||
};
|
||||
const LogistrationProps = {
|
||||
secondaryProviders: PropTypes.arrayOf(PropTypes.shape({
|
||||
name: PropTypes.string.isRequried,
|
||||
name: PropTypes.string.isRequired,
|
||||
loginUrl: PropTypes.string.isRequired,
|
||||
})),
|
||||
};
|
||||
|
||||
@@ -1,28 +1,38 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
import { getAuthService } from '@edx/frontend-platform/auth';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Icon,
|
||||
Tab,
|
||||
Tabs,
|
||||
} from '@edx/paragon';
|
||||
import { ChevronLeft } from '@edx/paragon/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Redirect } from 'react-router-dom';
|
||||
|
||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Tabs,
|
||||
Tab,
|
||||
Icon,
|
||||
} from '@edx/paragon';
|
||||
import { ChevronLeft } from '@edx/paragon/icons';
|
||||
|
||||
import messages from './messages';
|
||||
import BaseComponent from '../base-component';
|
||||
import { LOGIN_PAGE, REGISTER_PAGE } from '../data/constants';
|
||||
import { updatePathWithQueryParams, getTpaHint } from '../data/utils';
|
||||
import { getTpaHint, updatePathWithQueryParams } from '../data/utils';
|
||||
import { LoginPage } from '../login';
|
||||
import { RegistrationPage } from '../register';
|
||||
import BaseComponent from '../base-component';
|
||||
import messages from './messages';
|
||||
|
||||
const Logistration = (props) => {
|
||||
const { intl, selectedPage } = props;
|
||||
const tpa = getTpaHint();
|
||||
const [institutionLogin, setInstitutionLogin] = useState(false);
|
||||
const [key, setKey] = useState('');
|
||||
const disablePublicAccountCreation = getConfig().ALLOW_PUBLIC_ACCOUNT_CREATION === false;
|
||||
|
||||
useEffect(() => {
|
||||
const authService = getAuthService();
|
||||
if (authService) {
|
||||
authService.getCsrfTokenService().getCsrfToken(getConfig().LMS_BASE_URL);
|
||||
}
|
||||
});
|
||||
|
||||
const handleInstitutionLogin = (e) => {
|
||||
sendTrackEvent('edx.bi.institution_login_form.toggled', { category: 'user-engagement' });
|
||||
@@ -54,30 +64,56 @@ const Logistration = (props) => {
|
||||
return (
|
||||
<BaseComponent>
|
||||
<div>
|
||||
{institutionLogin
|
||||
{disablePublicAccountCreation
|
||||
? (
|
||||
<Tabs defaultActiveKey="" id="controlled-tab" onSelect={handleInstitutionLogin}>
|
||||
<Tab title={tabTitle} eventKey={selectedPage === LOGIN_PAGE ? LOGIN_PAGE : REGISTER_PAGE} />
|
||||
</Tabs>
|
||||
)
|
||||
: (
|
||||
<>
|
||||
{!tpa && (
|
||||
<Tabs defaultActiveKey={selectedPage} id="controlled-tab" onSelect={handleOnSelect}>
|
||||
<Tab title={intl.formatMessage(messages['logistration.register'])} eventKey={REGISTER_PAGE} />
|
||||
<Tab title={intl.formatMessage(messages['logistration.sign.in'])} eventKey={LOGIN_PAGE} />
|
||||
<Redirect to={updatePathWithQueryParams(LOGIN_PAGE)} />
|
||||
{institutionLogin && (
|
||||
<Tabs defaultActiveKey="" id="controlled-tab" onSelect={handleInstitutionLogin}>
|
||||
<Tab title={tabTitle} eventKey={LOGIN_PAGE} />
|
||||
</Tabs>
|
||||
)}
|
||||
<div id="main-content" className="main-content">
|
||||
{!institutionLogin && (
|
||||
<h3 className="mb-4.5">{intl.formatMessage(messages['logistration.sign.in'])}</h3>
|
||||
)}
|
||||
<LoginPage institutionLogin={institutionLogin} handleInstitutionLogin={handleInstitutionLogin} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
: (
|
||||
<div>
|
||||
{institutionLogin
|
||||
? (
|
||||
<Tabs defaultActiveKey="" id="controlled-tab" onSelect={handleInstitutionLogin}>
|
||||
<Tab title={tabTitle} eventKey={selectedPage === LOGIN_PAGE ? LOGIN_PAGE : REGISTER_PAGE} />
|
||||
</Tabs>
|
||||
)
|
||||
: (
|
||||
<>
|
||||
{!tpa && (
|
||||
<Tabs defaultActiveKey={selectedPage} id="controlled-tab" onSelect={handleOnSelect}>
|
||||
<Tab title={intl.formatMessage(messages['logistration.register'])} eventKey={REGISTER_PAGE} />
|
||||
<Tab title={intl.formatMessage(messages['logistration.sign.in'])} eventKey={LOGIN_PAGE} />
|
||||
</Tabs>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{ key && (
|
||||
<Redirect to={updatePathWithQueryParams(key)} />
|
||||
)}
|
||||
<div id="main-content" className="main-content">
|
||||
{selectedPage === LOGIN_PAGE
|
||||
? <LoginPage institutionLogin={institutionLogin} handleInstitutionLogin={handleInstitutionLogin} />
|
||||
: (
|
||||
<RegistrationPage
|
||||
institutionLogin={institutionLogin}
|
||||
handleInstitutionLogin={handleInstitutionLogin}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{ key && (
|
||||
<Redirect to={updatePathWithQueryParams(key)} />
|
||||
)}
|
||||
<div id="main-content" className="main-content">
|
||||
{selectedPage === LOGIN_PAGE
|
||||
? <LoginPage institutionLogin={institutionLogin} handleInstitutionLogin={handleInstitutionLogin} />
|
||||
: <RegistrationPage institutionLogin={institutionLogin} handleInstitutionLogin={handleInstitutionLogin} />}
|
||||
</div>
|
||||
</div>
|
||||
</BaseComponent>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
export default function NotFoundPage() {
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Form, IconButton, useToggle, Tooltip, OverlayTrigger, Icon,
|
||||
Form, Icon, IconButton, OverlayTrigger, Tooltip, useToggle,
|
||||
} from '@edx/paragon';
|
||||
import {
|
||||
Check, Remove, Visibility, VisibilityOff,
|
||||
} from '@edx/paragon/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import messages from './messages';
|
||||
import { LETTER_REGEX, NUMBER_REGEX } from '../data/constants';
|
||||
import messages from './messages';
|
||||
|
||||
const PasswordField = (props) => {
|
||||
const { formatMessage } = props.intl;
|
||||
@@ -39,16 +39,16 @@ const PasswordField = (props) => {
|
||||
const placement = window.innerWidth < 768 ? 'top' : 'left';
|
||||
const tooltip = (
|
||||
<Tooltip id={`password-requirement-${placement}`}>
|
||||
<span id="letter-check" className="d-flex position-relative align-content-start">
|
||||
{LETTER_REGEX.test(props.value) ? <Icon className="text-success mr-1" src={Check} /> : <Icon className="mr-1" src={Remove} />}
|
||||
<span id="letter-check" className="d-flex align-items-center">
|
||||
{LETTER_REGEX.test(props.value) ? <Icon className="text-success mr-1" src={Check} /> : <Icon className="mr-1 text-light-700" src={Remove} />}
|
||||
{formatMessage(messages['one.letter'])}
|
||||
</span>
|
||||
<span id="number-check" className="d-flex position-relative align-content-start">
|
||||
{NUMBER_REGEX.test(props.value) ? <Icon className="text-success mr-1" src={Check} /> : <Icon className="mr-1" src={Remove} />}
|
||||
<span id="number-check" className="d-flex align-items-center">
|
||||
{NUMBER_REGEX.test(props.value) ? <Icon className="text-success mr-1" src={Check} /> : <Icon className="mr-1 text-light-700" src={Remove} />}
|
||||
{formatMessage(messages['one.number'])}
|
||||
</span>
|
||||
<span id="characters-check" className="d-flex position-relative align-content-start">
|
||||
{props.value.length >= 8 ? <Icon className="text-success mr-1" src={Check} /> : <Icon className="mr-1" src={Remove} />}
|
||||
<span id="characters-check" className="d-flex align-items-center">
|
||||
{props.value.length >= 8 ? <Icon className="text-success mr-1" src={Check} /> : <Icon className="mr-1 text-light-700" src={Remove} />}
|
||||
{formatMessage(messages['eight.characters'])}
|
||||
</span>
|
||||
</Tooltip>
|
||||
@@ -63,6 +63,8 @@ const PasswordField = (props) => {
|
||||
type={isPasswordHidden ? 'password' : 'text'}
|
||||
name={props.name}
|
||||
value={props.value}
|
||||
autoComplete={props.autoComplete}
|
||||
aria-invalid={props.errorMessage !== ''}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
onChange={props.handleChange}
|
||||
@@ -88,6 +90,7 @@ PasswordField.defaultProps = {
|
||||
handleFocus: null,
|
||||
handleChange: () => {},
|
||||
showRequirements: true,
|
||||
autoComplete: null,
|
||||
};
|
||||
|
||||
PasswordField.propTypes = {
|
||||
@@ -101,6 +104,7 @@ PasswordField.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
showRequirements: PropTypes.bool,
|
||||
value: PropTypes.string.isRequired,
|
||||
autoComplete: PropTypes.string,
|
||||
};
|
||||
|
||||
export default injectIntl(PasswordField);
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import React from 'react';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Redirect } from 'react-router-dom';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
import { WELCOME_PAGE } from '../data/constants';
|
||||
import { setCookie } from '../data/utils';
|
||||
|
||||
function RedirectLogistration(props) {
|
||||
const {
|
||||
finishAuthUrl, redirectUrl, redirectToWelcomePage, success,
|
||||
finishAuthUrl, redirectUrl, redirectToWelcomePage, success, optionalFields,
|
||||
} = props;
|
||||
let finalRedirectUrl = '';
|
||||
|
||||
@@ -30,7 +29,16 @@ function RedirectLogistration(props) {
|
||||
// use this component to redirect WelcomePage after successful registration
|
||||
// return <Redirect to={WELCOME_PAGE} />;
|
||||
const registrationResult = { redirectUrl: finalRedirectUrl, success };
|
||||
return <Redirect to={{ pathname: WELCOME_PAGE, state: { registrationResult } }} />;
|
||||
return (
|
||||
<Redirect to={{
|
||||
pathname: WELCOME_PAGE,
|
||||
state: {
|
||||
registrationResult,
|
||||
optionalFields,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
window.location.href = finalRedirectUrl;
|
||||
@@ -43,6 +51,7 @@ RedirectLogistration.defaultProps = {
|
||||
success: false,
|
||||
redirectUrl: '',
|
||||
redirectToWelcomePage: false,
|
||||
optionalFields: {},
|
||||
};
|
||||
|
||||
RedirectLogistration.propTypes = {
|
||||
@@ -50,6 +59,7 @@ RedirectLogistration.propTypes = {
|
||||
success: PropTypes.bool,
|
||||
redirectUrl: PropTypes.string,
|
||||
redirectToWelcomePage: PropTypes.bool,
|
||||
optionalFields: PropTypes.shape({}),
|
||||
};
|
||||
|
||||
export default RedirectLogistration;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faSignInAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import messages from './messages';
|
||||
import { LOGIN_PAGE, SUPPORTED_ICON_CLASSES } from '../data/constants';
|
||||
import messages from './messages';
|
||||
|
||||
function SocialAuthProviders(props) {
|
||||
const { intl, referrer, socialAuthProviders } = props;
|
||||
@@ -42,7 +42,7 @@ function SocialAuthProviders(props) {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<span id="provider-name" className="mr-auto pl-2" aria-hidden="true">{provider.name}</span>
|
||||
<span id="provider-name" className="notranslate mr-auto pl-2" aria-hidden="true">{provider.name}</span>
|
||||
<span className="sr-only">
|
||||
{referrer === LOGIN_PAGE
|
||||
? intl.formatMessage(messages['sso.sign.in.with'], { providerName: provider.name })
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { TransitionReplace } from '@edx/paragon';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const onChildExit = (htmlNode) => {
|
||||
// If the leaving child has focus, take control and redirect it
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Alert } from '@edx/paragon';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import messages from './messages';
|
||||
import { LOGIN_PAGE, REGISTER_PAGE } from '../data/constants';
|
||||
import messages from './messages';
|
||||
|
||||
const ThirdPartyAuthAlert = (props) => {
|
||||
const { currentProvider, intl, referrer } = props;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Route } from 'react-router-dom';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { fetchAuthenticatedUser, getAuthenticatedUser } from '@edx/frontend-platform/auth';
|
||||
import { Route } from 'react-router-dom';
|
||||
|
||||
import { DEFAULT_REDIRECT_URL } from '../data/constants';
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,9 +12,9 @@ export const getThirdPartyAuthContextBegin = () => ({
|
||||
type: THIRD_PARTY_AUTH_CONTEXT.BEGIN,
|
||||
});
|
||||
|
||||
export const getThirdPartyAuthContextSuccess = (thirdPartyAuthContext) => ({
|
||||
export const getThirdPartyAuthContextSuccess = (fieldDescriptions, optionalFields, thirdPartyAuthContext) => ({
|
||||
type: THIRD_PARTY_AUTH_CONTEXT.SUCCESS,
|
||||
payload: { thirdPartyAuthContext },
|
||||
payload: { fieldDescriptions, optionalFields, thirdPartyAuthContext },
|
||||
});
|
||||
|
||||
export const getThirdPartyAuthContextFailure = () => ({
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { COMPLETE_STATE, PENDING_STATE } from '../../data/constants';
|
||||
import { THIRD_PARTY_AUTH_CONTEXT } from './actions';
|
||||
|
||||
import { PENDING_STATE, COMPLETE_STATE } from '../../data/constants';
|
||||
|
||||
export const defaultState = {
|
||||
extendedProfile: [],
|
||||
fieldDescriptions: {},
|
||||
optionalFields: {},
|
||||
thirdPartyAuthApiStatus: null,
|
||||
};
|
||||
|
||||
@@ -16,6 +18,9 @@ const reducer = (state = defaultState, action) => {
|
||||
case THIRD_PARTY_AUTH_CONTEXT.SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
extendedProfile: action.payload.fieldDescriptions.extendedProfile,
|
||||
fieldDescriptions: action.payload.fieldDescriptions.fields,
|
||||
optionalFields: action.payload.optionalFields,
|
||||
thirdPartyAuthContext: action.payload.thirdPartyAuthContext,
|
||||
thirdPartyAuthApiStatus: COMPLETE_STATE,
|
||||
};
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import { logError } from '@edx/frontend-platform/logging';
|
||||
import { call, put, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import { logError } from '@edx/frontend-platform/logging';
|
||||
|
||||
// Actions
|
||||
import { setCountryFromThirdPartyAuthContext } from '../../register/data/actions';
|
||||
import {
|
||||
THIRD_PARTY_AUTH_CONTEXT,
|
||||
getThirdPartyAuthContextBegin,
|
||||
getThirdPartyAuthContextSuccess,
|
||||
getThirdPartyAuthContextFailure,
|
||||
getThirdPartyAuthContextSuccess,
|
||||
THIRD_PARTY_AUTH_CONTEXT,
|
||||
} from './actions';
|
||||
|
||||
// Services
|
||||
import {
|
||||
getThirdPartyAuthContext,
|
||||
} from './service';
|
||||
@@ -18,10 +15,13 @@ import {
|
||||
export function* fetchThirdPartyAuthContext(action) {
|
||||
try {
|
||||
yield put(getThirdPartyAuthContextBegin());
|
||||
const { thirdPartyAuthContext } = yield call(getThirdPartyAuthContext, action.payload.urlParams);
|
||||
const { fieldDescriptions, optionalFields, thirdPartyAuthContext } = yield call(
|
||||
getThirdPartyAuthContext, action.payload.urlParams,
|
||||
);
|
||||
|
||||
yield put(setCountryFromThirdPartyAuthContext(thirdPartyAuthContext.countryCode));
|
||||
yield put(getThirdPartyAuthContextSuccess(
|
||||
thirdPartyAuthContext,
|
||||
fieldDescriptions, optionalFields, thirdPartyAuthContext,
|
||||
));
|
||||
} catch (e) {
|
||||
yield put(getThirdPartyAuthContextFailure());
|
||||
|
||||
@@ -8,3 +8,18 @@ export const thirdPartyAuthContextSelector = createSelector(
|
||||
commonComponentsSelector,
|
||||
commonComponents => commonComponents.thirdPartyAuthContext,
|
||||
);
|
||||
|
||||
export const fieldDescriptionSelector = createSelector(
|
||||
commonComponentsSelector,
|
||||
commonComponents => commonComponents.fieldDescriptions,
|
||||
);
|
||||
|
||||
export const extendedProfileSelector = createSelector(
|
||||
commonComponentsSelector,
|
||||
commonComponents => commonComponents.extendedProfile,
|
||||
);
|
||||
|
||||
export const optionalFieldsSelector = createSelector(
|
||||
commonComponentsSelector,
|
||||
commonComponents => commonComponents.optionalFields,
|
||||
);
|
||||
|
||||
@@ -18,6 +18,12 @@ export async function getThirdPartyAuthContext(urlParams) {
|
||||
throw (e);
|
||||
});
|
||||
return {
|
||||
thirdPartyAuthContext: camelCaseObject(convertKeyNames(data, { fullname: 'name' })),
|
||||
fieldDescriptions: data.registration_fields || {},
|
||||
optionalFields: data.optional_fields || {},
|
||||
// For backward compatibility with the API, once https://github.com/openedx/edx-platform/pull/30198 is merged
|
||||
// and deployed update it to use data.context_data
|
||||
thirdPartyAuthContext: camelCaseObject(
|
||||
convertKeyNames(data.context_data || data, { fullname: 'name' }),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { runSaga } from 'redux-saga';
|
||||
|
||||
import { setCountryFromThirdPartyAuthContext } from '../../../register/data/actions';
|
||||
import initializeMockLogging from '../../../setupTest';
|
||||
import * as actions from '../actions';
|
||||
import { fetchThirdPartyAuthContext } from '../sagas';
|
||||
import * as api from '../service';
|
||||
import initializeMockLogging from '../../../setupTest';
|
||||
|
||||
const { loggingService } = initializeMockLogging();
|
||||
|
||||
@@ -26,7 +27,11 @@ describe('fetchThirdPartyAuthContext', () => {
|
||||
|
||||
it('should call service and dispatch success action', async () => {
|
||||
const getThirdPartyAuthContext = jest.spyOn(api, 'getThirdPartyAuthContext')
|
||||
.mockImplementation(() => Promise.resolve({ thirdPartyAuthContext: data }));
|
||||
.mockImplementation(() => Promise.resolve({
|
||||
thirdPartyAuthContext: data,
|
||||
fieldDescriptions: {},
|
||||
optionalFields: {},
|
||||
}));
|
||||
|
||||
const dispatched = [];
|
||||
await runSaga(
|
||||
@@ -38,7 +43,8 @@ describe('fetchThirdPartyAuthContext', () => {
|
||||
expect(getThirdPartyAuthContext).toHaveBeenCalledTimes(1);
|
||||
expect(dispatched).toEqual([
|
||||
actions.getThirdPartyAuthContextBegin(),
|
||||
actions.getThirdPartyAuthContextSuccess(data),
|
||||
setCountryFromThirdPartyAuthContext(),
|
||||
actions.getThirdPartyAuthContextSuccess({}, {}, data),
|
||||
]);
|
||||
getThirdPartyAuthContext.mockClear();
|
||||
});
|
||||
|
||||
@@ -60,6 +60,11 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Show me other ways to sign in or register',
|
||||
description: 'Button text for login',
|
||||
},
|
||||
'enterprisetpa.login.button.text.public.account.creation.disabled': {
|
||||
id: 'enterprisetpa.login.button.text.public.account.creation.disabled',
|
||||
defaultMessage: 'Show me other ways to sign in',
|
||||
description: 'Button text for login when account creation is disabled',
|
||||
},
|
||||
// social auth providers
|
||||
'sso.sign.in.with': {
|
||||
id: 'sso.sign.in.with',
|
||||
@@ -84,17 +89,17 @@ const messages = defineMessages({
|
||||
},
|
||||
'one.letter': {
|
||||
id: 'one.letter',
|
||||
defaultMessage: '1 Letter',
|
||||
defaultMessage: '1 letter',
|
||||
description: 'password requirement to have 1 letter',
|
||||
},
|
||||
'one.number': {
|
||||
id: 'one.number',
|
||||
defaultMessage: '1 Number',
|
||||
defaultMessage: '1 number',
|
||||
description: 'password requirement to have 1 number',
|
||||
},
|
||||
'eight.characters': {
|
||||
id: 'eight.characters',
|
||||
defaultMessage: '8 Characters',
|
||||
defaultMessage: '8 characters',
|
||||
description: 'password requirement to have a minimum of 8 characters',
|
||||
},
|
||||
'password.sr.only.helping.text': {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
|
||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
|
||||
import FormGroup from '../FormGroup';
|
||||
import PasswordField from '../PasswordField';
|
||||
@@ -74,9 +74,9 @@ describe('PasswordField', () => {
|
||||
});
|
||||
passwordField.update();
|
||||
|
||||
expect(passwordField.find('#letter-check span').prop('className')).toEqual('pgn__icon mr-1');
|
||||
expect(passwordField.find('#number-check span').prop('className')).toEqual('pgn__icon mr-1');
|
||||
expect(passwordField.find('#characters-check span').prop('className')).toEqual('pgn__icon mr-1');
|
||||
expect(passwordField.find('#letter-check span').prop('className')).toEqual('pgn__icon mr-1 text-light-700');
|
||||
expect(passwordField.find('#number-check span').prop('className')).toEqual('pgn__icon mr-1 text-light-700');
|
||||
expect(passwordField.find('#characters-check span').prop('className')).toEqual('pgn__icon mr-1 text-light-700');
|
||||
});
|
||||
|
||||
it('should update password requirement checks', async () => {
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import configureStore from 'redux-mock-store';
|
||||
import { Provider } from 'react-redux';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
||||
import * as analytics from '@edx/frontend-platform/analytics';
|
||||
import { configure, injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import * as auth from '@edx/frontend-platform/auth';
|
||||
import Logistration from '../Logistration';
|
||||
import { RenderInstitutionButton } from '../InstitutionLogistration';
|
||||
import { configure, injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { mount } from 'enzyme';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import configureStore from 'redux-mock-store';
|
||||
|
||||
import { COMPLETE_STATE, LOGIN_PAGE } from '../../data/constants';
|
||||
import { RenderInstitutionButton } from '../InstitutionLogistration';
|
||||
import Logistration from '../Logistration';
|
||||
|
||||
jest.mock('@edx/frontend-platform/analytics');
|
||||
jest.mock('@edx/frontend-platform/auth');
|
||||
@@ -51,6 +51,9 @@ describe('Logistration', () => {
|
||||
messages: { 'es-419': {}, de: {}, 'en-us': {} },
|
||||
});
|
||||
|
||||
mergeConfig({
|
||||
ALLOW_PUBLIC_ACCOUNT_CREATION: true,
|
||||
});
|
||||
store = mockStore({
|
||||
register: {
|
||||
registrationResult: { success: false, redirectUrl: '' },
|
||||
@@ -81,9 +84,42 @@ describe('Logistration', () => {
|
||||
expect(logistration.find('#main-content').find('LoginPage').exists()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render only login page when public account creation is disabled', () => {
|
||||
mergeConfig({
|
||||
ALLOW_PUBLIC_ACCOUNT_CREATION: false,
|
||||
DISABLE_ENTERPRISE_LOGIN: 'true',
|
||||
});
|
||||
|
||||
store = mockStore({
|
||||
login: {
|
||||
loginResult: { success: false, redirectUrl: '' },
|
||||
},
|
||||
commonComponents: {
|
||||
thirdPartyAuthContext: {
|
||||
currentProvider: null,
|
||||
finishAuthUrl: null,
|
||||
providers: [],
|
||||
secondaryProviders: [secondaryProviders],
|
||||
},
|
||||
thirdPartyAuthApiStatus: COMPLETE_STATE,
|
||||
},
|
||||
});
|
||||
|
||||
const props = { selectedPage: LOGIN_PAGE };
|
||||
const logistration = mount(reduxWrapper(<IntlLogistration {...props} />));
|
||||
|
||||
// verifying sign in heading for institution login false
|
||||
expect(logistration.find('#main-content').find('h3').text()).toEqual('Sign in');
|
||||
|
||||
// verifying tabs heading for institution login true
|
||||
logistration.find(RenderInstitutionButton).simulate('click', { institutionLogin: true });
|
||||
expect(logistration.find('#controlled-tab').exists()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should display institution login option when secondary providers are present', () => {
|
||||
mergeConfig({
|
||||
DISABLE_ENTERPRISE_LOGIN: 'true',
|
||||
ALLOW_PUBLIC_ACCOUNT_CREATION: 'true',
|
||||
});
|
||||
|
||||
store = mockStore({
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import SocialAuthProviders from '../SocialAuthProviders';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
import registerIcons from '../RegisterFaIcons';
|
||||
import SocialAuthProviders from '../SocialAuthProviders';
|
||||
|
||||
registerIcons();
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import ThirdPartyAuthAlert from '../ThirdPartyAuthAlert';
|
||||
import { IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
||||
import { REGISTER_PAGE } from '../../data/constants';
|
||||
import ThirdPartyAuthAlert from '../ThirdPartyAuthAlert';
|
||||
|
||||
describe('ThirdPartyAuthAlert', () => {
|
||||
let props = {};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { BrowserRouter as Router, MemoryRouter, Switch } from 'react-router-dom';
|
||||
|
||||
import * as auth from '@edx/frontend-platform/auth';
|
||||
import { mount } from 'enzyme';
|
||||
import { MemoryRouter, BrowserRouter as Router, Switch } from 'react-router-dom';
|
||||
|
||||
import { UnAuthOnlyRoute } from '..';
|
||||
import { LOGIN_PAGE } from '../../data/constants';
|
||||
|
||||
@@ -14,8 +14,8 @@ exports[`SocialAuthProviders should match social auth provider with default icon
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="svg-inline--fa fa-sign-in-alt fa-w-16 "
|
||||
data-icon="sign-in-alt"
|
||||
className="svg-inline--fa fa-right-to-bracket "
|
||||
data-icon="right-to-bracket"
|
||||
data-prefix="fas"
|
||||
focusable="false"
|
||||
role="img"
|
||||
@@ -24,7 +24,7 @@ exports[`SocialAuthProviders should match social auth provider with default icon
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M416 448h-84c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h84c17.7 0 32-14.3 32-32V160c0-17.7-14.3-32-32-32h-84c-6.6 0-12-5.4-12-12V76c0-6.6 5.4-12 12-12h84c53 0 96 43 96 96v192c0 53-43 96-96 96zm-47-201L201 79c-15-15-41-4.5-41 17v96H24c-13.3 0-24 10.7-24 24v96c0 13.3 10.7 24 24 24h136v96c0 21.5 26 32 41 17l168-168c9.3-9.4 9.3-24.6 0-34z"
|
||||
d="M352 96h64c17.7 0 32 14.3 32 32V384c0 17.7-14.3 32-32 32H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h64c53 0 96-43 96-96V128c0-53-43-96-96-96H352c-17.7 0-32 14.3-32 32s14.3 32 32 32zm-7.5 177.4c4.8-4.5 7.5-10.8 7.5-17.4s-2.7-12.9-7.5-17.4l-144-136c-7-6.6-17.2-8.4-26-4.6s-14.5 12.5-14.5 22v72H32c-17.7 0-32 14.3-32 32v64c0 17.7 14.3 32 32 32H160v72c0 9.6 5.7 18.2 14.5 22s19 2 26-4.6l144-136z"
|
||||
fill="currentColor"
|
||||
style={Object {}}
|
||||
/>
|
||||
@@ -32,7 +32,7 @@ exports[`SocialAuthProviders should match social auth provider with default icon
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="mr-auto pl-2"
|
||||
className="notranslate mr-auto pl-2"
|
||||
id="provider-name"
|
||||
>
|
||||
Apple
|
||||
@@ -59,7 +59,7 @@ exports[`SocialAuthProviders should match social auth provider with iconClass sn
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="svg-inline--fa fa-google fa-w-16 "
|
||||
className="svg-inline--fa fa-google "
|
||||
data-icon="google"
|
||||
data-prefix="fab"
|
||||
focusable="false"
|
||||
@@ -77,7 +77,7 @@ exports[`SocialAuthProviders should match social auth provider with iconClass sn
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="mr-auto pl-2"
|
||||
className="notranslate mr-auto pl-2"
|
||||
id="provider-name"
|
||||
>
|
||||
Apple
|
||||
@@ -110,7 +110,7 @@ Array [
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="mr-auto pl-2"
|
||||
className="notranslate mr-auto pl-2"
|
||||
id="provider-name"
|
||||
>
|
||||
Apple
|
||||
@@ -139,7 +139,7 @@ Array [
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="mr-auto pl-2"
|
||||
className="notranslate mr-auto pl-2"
|
||||
id="provider-name"
|
||||
>
|
||||
Facebook
|
||||
|
||||
@@ -13,7 +13,7 @@ exports[`ThirdPartyAuthAlert should match login page third party auth alert mess
|
||||
className="alert-message-content"
|
||||
>
|
||||
<p>
|
||||
You have successfully signed into Google, but your Google account does not have a linked edX account. To link your accounts, sign in now using your edX password.
|
||||
You have successfully signed into Google, but your Google account does not have a linked Your Platform Name Here account. To link your accounts, sign in now using your Your Platform Name Here password.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -38,7 +38,7 @@ exports[`ThirdPartyAuthAlert should match register page third party auth alert m
|
||||
Almost done!
|
||||
</div>
|
||||
<p>
|
||||
You've successfully signed into Google! We just need a little more information before you start learning with edX.
|
||||
You've successfully signed into Google! We just need a little more information before you start learning with Your Platform Name Here.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { applyMiddleware, createStore, compose } from 'redux';
|
||||
import thunkMiddleware from 'redux-thunk';
|
||||
import { composeWithDevTools } from 'redux-devtools-extension';
|
||||
import { composeWithDevTools } from '@redux-devtools/extension';
|
||||
import { applyMiddleware, compose, createStore } from 'redux';
|
||||
import { createLogger } from 'redux-logger';
|
||||
import createSagaMiddleware from 'redux-saga';
|
||||
import thunkMiddleware from 'redux-thunk';
|
||||
|
||||
import createRootReducer from './reducers';
|
||||
import rootSaga from './sagas';
|
||||
|
||||
@@ -12,13 +12,16 @@ export const ENTERPRISE_LOGIN_URL = '/enterprise/login';
|
||||
export const SUPPORTED_ICON_CLASSES = ['apple', 'facebook', 'google', 'microsoft'];
|
||||
|
||||
// Error Codes
|
||||
export const FORM_SUBMISSION_ERROR = 'form-submission-error';
|
||||
export const INTERNAL_SERVER_ERROR = 'internal-server-error';
|
||||
export const API_RATELIMIT_ERROR = 'api-ratelimit-error';
|
||||
|
||||
// States
|
||||
// Common States
|
||||
export const DEFAULT_STATE = 'default';
|
||||
export const PENDING_STATE = 'pending';
|
||||
export const COMPLETE_STATE = 'complete';
|
||||
export const FAILURE_STATE = 'failure';
|
||||
export const FORBIDDEN_STATE = 'forbidden';
|
||||
|
||||
// Regex
|
||||
export const VALID_EMAIL_REGEX = '(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+)*'
|
||||
@@ -27,7 +30,8 @@ export const VALID_EMAIL_REGEX = '(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+
|
||||
+ '|\\[(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\]$';
|
||||
export const LETTER_REGEX = /[a-zA-Z]/;
|
||||
export const NUMBER_REGEX = /\d/;
|
||||
export const VALID_NAME_REGEX = /[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)?/gi; // eslint-disable-line no-useless-escape
|
||||
|
||||
// Query string parameters that can be passed to LMS to manage
|
||||
// things like auto-enrollment upon login and registration.
|
||||
export const AUTH_PARAMS = ['course_id', 'enrollment_action', 'course_mode', 'email_opt_in', 'purchase_workflow', 'next'];
|
||||
export const AUTH_PARAMS = ['course_id', 'enrollment_action', 'course_mode', 'email_opt_in', 'purchase_workflow', 'next', 'save_for_later', 'register_for_free'];
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
import { combineReducers } from 'redux';
|
||||
|
||||
import {
|
||||
reducer as loginReducer,
|
||||
storeName as loginStoreName,
|
||||
} from '../login';
|
||||
import {
|
||||
reducer as registerReducer,
|
||||
storeName as registerStoreName,
|
||||
} from '../register';
|
||||
import {
|
||||
reducer as commonComponentsReducer,
|
||||
storeName as commonComponentsStoreName,
|
||||
@@ -16,11 +8,18 @@ import {
|
||||
reducer as forgotPasswordReducer,
|
||||
storeName as forgotPasswordStoreName,
|
||||
} from '../forgot-password';
|
||||
import {
|
||||
reducer as loginReducer,
|
||||
storeName as loginStoreName,
|
||||
} from '../login';
|
||||
import {
|
||||
reducer as registerReducer,
|
||||
storeName as registerStoreName,
|
||||
} from '../register';
|
||||
import {
|
||||
reducer as resetPasswordReducer,
|
||||
storeName as resetPasswordStoreName,
|
||||
} from '../reset-password';
|
||||
|
||||
import {
|
||||
reducer as welcomePageReducers,
|
||||
storeName as welcomePageStoreName,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { all } from 'redux-saga/effects';
|
||||
|
||||
import { saga as registrationSaga } from '../register';
|
||||
import { saga as loginSaga } from '../login';
|
||||
import { saga as commonComponentsSaga } from '../common-components';
|
||||
import { saga as forgotPasswordSaga } from '../forgot-password';
|
||||
import { saga as loginSaga } from '../login';
|
||||
import { saga as registrationSaga } from '../register';
|
||||
import { saga as resetPasswordSaga } from '../reset-password';
|
||||
import { saga as welcomePageSaga } from '../welcome';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Cookies from 'universal-cookie';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import Cookies from 'universal-cookie';
|
||||
|
||||
export function setCookie(cookieName, cookieValue, cookieExpiry) {
|
||||
const cookies = new Cookies();
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
// Utility functions
|
||||
|
||||
import * as QueryString from 'query-string';
|
||||
import { AUTH_PARAMS } from '../constants';
|
||||
|
||||
export default function processLink(link) {
|
||||
let matches;
|
||||
link.replace(/(.*?)<a href=["']([^"']*).*?>([^<]+)<\/a>(.*)/g, function () { // eslint-disable-line func-names
|
||||
matches = Array.prototype.slice.call(arguments, 1, 5); // eslint-disable-line prefer-rest-params
|
||||
});
|
||||
return matches;
|
||||
}
|
||||
import { AUTH_PARAMS } from '../constants';
|
||||
|
||||
export const getTpaProvider = (tpaHintProvider, primaryProviders, secondaryProviders) => {
|
||||
let tpaProvider = null;
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
import { LOGIN_PAGE } from '../constants';
|
||||
import processLink, { updatePathWithQueryParams } from './dataUtils';
|
||||
|
||||
describe('processLink', () => {
|
||||
it('should use the provided processLink function to', () => {
|
||||
const expectedHref = 'http://test.server.com/';
|
||||
const expectedText = 'test link';
|
||||
const link = `<a href="${expectedHref}">${expectedText}</a>`;
|
||||
|
||||
const matches = processLink(link);
|
||||
|
||||
expect(matches[1]).toEqual(expectedHref);
|
||||
expect(matches[2]).toEqual(expectedText);
|
||||
});
|
||||
});
|
||||
import { updatePathWithQueryParams } from './dataUtils';
|
||||
|
||||
describe('updatePathWithQueryParams', () => {
|
||||
it('should append query params into the path', () => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export {
|
||||
default,
|
||||
getTpaProvider,
|
||||
getTpaHint,
|
||||
updatePathWithQueryParams,
|
||||
|
||||
24
src/data/utils/useMobileResponsive.js
Normal file
24
src/data/utils/useMobileResponsive.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { breakpoints } from '@edx/paragon';
|
||||
|
||||
/**
|
||||
* A react hook used to determine if the current window is mobile or not.
|
||||
* returns true if the window is of mobile size.
|
||||
* Code source: https://github.com/edx/prospectus/blob/master/src/utils/useMobileResponsive.js
|
||||
*/
|
||||
const useMobileResponsive = (breakpoint) => {
|
||||
const [isMobileWindow, setIsMobileWindow] = useState();
|
||||
const checkForMobile = () => {
|
||||
setIsMobileWindow(window.matchMedia(`(max-width: ${breakpoint || breakpoints.small.maxWidth}px)`).matches);
|
||||
};
|
||||
useEffect(() => {
|
||||
checkForMobile();
|
||||
window.addEventListener('resize', checkForMobile);
|
||||
// return this function here to clean up the event listener
|
||||
return () => window.removeEventListener('resize', checkForMobile);
|
||||
});
|
||||
return isMobileWindow;
|
||||
};
|
||||
|
||||
export default useMobileResponsive;
|
||||
148
src/field-renderer/FieldRenderer.jsx
Normal file
148
src/field-renderer/FieldRenderer.jsx
Normal file
@@ -0,0 +1,148 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Form, Icon } from '@edx/paragon';
|
||||
import { ExpandMore } from '@edx/paragon/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const FormFieldRenderer = (props) => {
|
||||
let formField = null;
|
||||
const {
|
||||
errorMessage, fieldData, onChangeHandler, isRequired, value,
|
||||
} = props;
|
||||
|
||||
const handleFocus = (e) => {
|
||||
if (props.handleFocus) { props.handleFocus(e); }
|
||||
};
|
||||
|
||||
const handleOnBlur = (e) => {
|
||||
if (props.handleBlur) { props.handleBlur(e); }
|
||||
};
|
||||
|
||||
switch (fieldData.type) {
|
||||
case 'select': {
|
||||
if (!fieldData.options) {
|
||||
return null;
|
||||
}
|
||||
formField = (
|
||||
<Form.Group controlId={fieldData.name} isInvalid={!!(isRequired && errorMessage)}>
|
||||
<Form.Control
|
||||
as="select"
|
||||
name={fieldData.name}
|
||||
value={value}
|
||||
aria-invalid={isRequired && Boolean(errorMessage)}
|
||||
onChange={(e) => onChangeHandler(e)}
|
||||
trailingElement={<Icon src={ExpandMore} />}
|
||||
floatingLabel={fieldData.label}
|
||||
onBlur={handleOnBlur}
|
||||
onFocus={handleFocus}
|
||||
>
|
||||
<option key="default" value="">{fieldData.label}</option>
|
||||
{fieldData.options.map(option => (
|
||||
<option className="data-hj-suppress" key={option[0]} value={option[0]}>{option[1]}</option>
|
||||
))}
|
||||
</Form.Control>
|
||||
{isRequired && errorMessage && (
|
||||
<Form.Control.Feedback id={`${fieldData.name}-error`} type="invalid" className="form-text-size" hasIcon={false}>
|
||||
{errorMessage}
|
||||
</Form.Control.Feedback>
|
||||
)}
|
||||
</Form.Group>
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'textarea': {
|
||||
formField = (
|
||||
<Form.Group controlId={fieldData.name} isInvalid={!!(isRequired && errorMessage)}>
|
||||
<Form.Control
|
||||
as="textarea"
|
||||
name={fieldData.name}
|
||||
value={value}
|
||||
aria-invalid={isRequired && Boolean(errorMessage)}
|
||||
onChange={(e) => onChangeHandler(e)}
|
||||
floatingLabel={fieldData.label}
|
||||
onBlur={handleOnBlur}
|
||||
onFocus={handleFocus}
|
||||
/>
|
||||
{isRequired && errorMessage && (
|
||||
<Form.Control.Feedback id={`${fieldData.name}-error`} type="invalid" className="form-text-size" hasIcon={false}>
|
||||
{errorMessage}
|
||||
</Form.Control.Feedback>
|
||||
)}
|
||||
</Form.Group>
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'text': {
|
||||
formField = (
|
||||
<Form.Group controlId={fieldData.name} isInvalid={!!(isRequired && errorMessage)}>
|
||||
<Form.Control
|
||||
name={fieldData.name}
|
||||
value={value}
|
||||
aria-invalid={isRequired && Boolean(errorMessage)}
|
||||
onChange={(e) => onChangeHandler(e)}
|
||||
floatingLabel={fieldData.label}
|
||||
onBlur={handleOnBlur}
|
||||
onFocus={handleFocus}
|
||||
/>
|
||||
{isRequired && errorMessage && (
|
||||
<Form.Control.Feedback id={`${fieldData.name}-error`} type="invalid" className="form-text-size" hasIcon={false}>
|
||||
{errorMessage}
|
||||
</Form.Control.Feedback>
|
||||
)}
|
||||
</Form.Group>
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'checkbox': {
|
||||
formField = (
|
||||
<Form.Group isInvalid={!!(isRequired && errorMessage)}>
|
||||
<Form.Checkbox
|
||||
id={fieldData.name}
|
||||
checked={!!value}
|
||||
name={fieldData.name}
|
||||
value={value}
|
||||
aria-invalid={isRequired && Boolean(errorMessage)}
|
||||
onChange={(e) => onChangeHandler(e)}
|
||||
onBlur={handleOnBlur}
|
||||
onFocus={handleFocus}
|
||||
>
|
||||
{fieldData.label}
|
||||
</Form.Checkbox>
|
||||
{isRequired && errorMessage && (
|
||||
<Form.Control.Feedback id={`${fieldData.name}-error`} type="invalid" className="form-text-size" hasIcon={false}>
|
||||
{errorMessage}
|
||||
</Form.Control.Feedback>
|
||||
)}
|
||||
</Form.Group>
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return formField;
|
||||
};
|
||||
FormFieldRenderer.defaultProps = {
|
||||
value: '',
|
||||
handleBlur: null,
|
||||
handleFocus: null,
|
||||
errorMessage: '',
|
||||
isRequired: false,
|
||||
};
|
||||
|
||||
FormFieldRenderer.propTypes = {
|
||||
fieldData: PropTypes.shape({
|
||||
type: PropTypes.string,
|
||||
label: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
}).isRequired,
|
||||
onChangeHandler: PropTypes.func.isRequired,
|
||||
handleBlur: PropTypes.func,
|
||||
handleFocus: PropTypes.func,
|
||||
errorMessage: PropTypes.string,
|
||||
isRequired: PropTypes.bool,
|
||||
value: PropTypes.string,
|
||||
};
|
||||
|
||||
export default FormFieldRenderer;
|
||||
1
src/field-renderer/index.jsx
Normal file
1
src/field-renderer/index.jsx
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './FieldRenderer';
|
||||
198
src/field-renderer/tests/FieldRenderer.test.jsx
Normal file
198
src/field-renderer/tests/FieldRenderer.test.jsx
Normal file
@@ -0,0 +1,198 @@
|
||||
import React from 'react';
|
||||
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
import FieldRenderer from '../FieldRenderer';
|
||||
|
||||
describe('FieldRendererTests', () => {
|
||||
let value = '';
|
||||
|
||||
const changeHandler = (e) => {
|
||||
if (e.target.type === 'checkbox') {
|
||||
value = e.target.checked;
|
||||
} else {
|
||||
value = e.target.value;
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
value = '';
|
||||
});
|
||||
|
||||
it('should render select field type', () => {
|
||||
const fieldData = {
|
||||
type: 'select',
|
||||
label: 'Year of Birth',
|
||||
name: 'yob-field',
|
||||
options: [['1997', 1997], ['1998', 1998]],
|
||||
};
|
||||
|
||||
const fieldRenderer = mount(<FieldRenderer value={value} fieldData={fieldData} onChangeHandler={changeHandler} />);
|
||||
const field = fieldRenderer.find('select#yob-field');
|
||||
field.simulate('change', { target: { value: 1997 } });
|
||||
|
||||
expect(field.type()).toEqual('select');
|
||||
expect(fieldRenderer.find('label').text()).toEqual('Year of Birth');
|
||||
expect(value).toEqual(1997);
|
||||
});
|
||||
|
||||
it('should return null if no options are provided for select field', () => {
|
||||
const fieldData = {
|
||||
type: 'select',
|
||||
label: 'Year of Birth',
|
||||
name: 'yob-field',
|
||||
};
|
||||
|
||||
const fieldRenderer = mount(<FieldRenderer fieldData={fieldData} onChangeHandler={() => {}} />);
|
||||
expect(fieldRenderer.html()).toBeNull();
|
||||
});
|
||||
|
||||
it('should render textarea field', () => {
|
||||
const fieldData = {
|
||||
type: 'textarea',
|
||||
label: 'Why do you want to join this platform?',
|
||||
name: 'goals-field',
|
||||
};
|
||||
|
||||
const fieldRenderer = mount(<FieldRenderer value={value} fieldData={fieldData} onChangeHandler={changeHandler} />);
|
||||
const field = fieldRenderer.find('#goals-field').last();
|
||||
field.simulate('change', { target: { value: 'These are my goals.' } });
|
||||
|
||||
expect(field.type()).toEqual('textarea');
|
||||
expect(fieldRenderer.find('label').text()).toEqual('Why do you want to join this platform?');
|
||||
expect(value).toEqual('These are my goals.');
|
||||
});
|
||||
|
||||
it('should render an input field', () => {
|
||||
const fieldData = {
|
||||
type: 'text',
|
||||
label: 'Company',
|
||||
name: 'company-field',
|
||||
};
|
||||
|
||||
const fieldRenderer = mount(<FieldRenderer value={value} fieldData={fieldData} onChangeHandler={changeHandler} />);
|
||||
const field = fieldRenderer.find('#company-field').last();
|
||||
field.simulate('change', { target: { value: 'ABC' } });
|
||||
|
||||
expect(field.type()).toEqual('input');
|
||||
expect(fieldRenderer.find('label').text()).toEqual('Company');
|
||||
expect(value).toEqual('ABC');
|
||||
});
|
||||
|
||||
it('should render checkbox field', () => {
|
||||
const fieldData = {
|
||||
type: 'checkbox',
|
||||
label: 'I agree that edX may send me marketing messages.',
|
||||
name: 'marketing-emails-opt-in-field',
|
||||
};
|
||||
|
||||
const fieldRenderer = mount(<FieldRenderer value={value} fieldData={fieldData} onChangeHandler={changeHandler} />);
|
||||
const field = fieldRenderer.find('input#marketing-emails-opt-in-field');
|
||||
field.simulate('change', { target: { checked: true, type: 'checkbox' } });
|
||||
|
||||
expect(field.prop('type')).toEqual('checkbox');
|
||||
expect(fieldRenderer.find('label').text()).toEqual('I agree that edX may send me marketing messages.');
|
||||
expect(value).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return null if field type is unknown', () => {
|
||||
const fieldData = {
|
||||
type: 'unknown',
|
||||
};
|
||||
|
||||
const fieldRenderer = mount(<FieldRenderer fieldData={fieldData} onChangeHandler={() => {}} />);
|
||||
expect(fieldRenderer.html()).toBeNull();
|
||||
});
|
||||
|
||||
it('should run onBlur and onFocus functions for a field if given', () => {
|
||||
const fieldData = { type: 'text', label: 'Test', name: 'test-field' };
|
||||
let functionValue = '';
|
||||
|
||||
const onBlur = (e) => {
|
||||
functionValue = `${e.target.name} blurred`;
|
||||
};
|
||||
|
||||
const onFocus = (e) => {
|
||||
functionValue = `${e.target.name} focussed`;
|
||||
};
|
||||
|
||||
const fieldRenderer = mount(
|
||||
<FieldRenderer
|
||||
handleFocus={onFocus}
|
||||
handleBlur={onBlur}
|
||||
value={value}
|
||||
fieldData={fieldData}
|
||||
onChangeHandler={changeHandler}
|
||||
/>,
|
||||
);
|
||||
const field = fieldRenderer.find('#test-field').last();
|
||||
|
||||
field.simulate('focus');
|
||||
expect(functionValue).toEqual('test-field focussed');
|
||||
|
||||
field.simulate('blur');
|
||||
expect(functionValue).toEqual('test-field blurred');
|
||||
});
|
||||
|
||||
it('should render error message for required text fields', () => {
|
||||
const fieldData = { type: 'text', label: 'First Name', name: 'first-name-field' };
|
||||
|
||||
const fieldRenderer = mount(
|
||||
<FieldRenderer
|
||||
isRequired
|
||||
fieldData={fieldData}
|
||||
onChangeHandler={changeHandler}
|
||||
errorMessage="Enter your first name"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(fieldRenderer.find('.form-text-size').last().text()).toEqual('Enter your first name');
|
||||
});
|
||||
|
||||
it('should render error message for required select fields', () => {
|
||||
const fieldData = {
|
||||
type: 'select', label: 'Preference', name: 'preference-field', options: [['a', 'Opt 1'], ['b', 'Opt 2']],
|
||||
};
|
||||
|
||||
const fieldRenderer = mount(
|
||||
<FieldRenderer
|
||||
isRequired
|
||||
fieldData={fieldData}
|
||||
onChangeHandler={changeHandler}
|
||||
errorMessage="Select your preference"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(fieldRenderer.find('.form-text-size').last().text()).toEqual('Select your preference');
|
||||
});
|
||||
|
||||
it('should render error message for required textarea fields', () => {
|
||||
const fieldData = { type: 'textarea', label: 'Goals', name: 'goals-field' };
|
||||
|
||||
const fieldRenderer = mount(
|
||||
<FieldRenderer
|
||||
isRequired
|
||||
fieldData={fieldData}
|
||||
onChangeHandler={changeHandler}
|
||||
errorMessage="Tell us your goals"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(fieldRenderer.find('.form-text-size').last().text()).toEqual('Tell us your goals');
|
||||
});
|
||||
|
||||
it('should render error message for required checkbox fields', () => {
|
||||
const fieldData = { type: 'checkbox', label: 'Honor Code', name: 'honor-code-field' };
|
||||
|
||||
const fieldRenderer = mount(
|
||||
<FieldRenderer
|
||||
isRequired
|
||||
fieldData={fieldData}
|
||||
onChangeHandler={changeHandler}
|
||||
errorMessage="You must agree to our Honor Code"
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(fieldRenderer.find('.form-text-size').last().text()).toEqual('You must agree to our Honor Code');
|
||||
});
|
||||
});
|
||||
@@ -1,28 +1,29 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Alert } from '@edx/paragon';
|
||||
import { CheckCircle, Error } from '@edx/paragon/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import messages from './messages';
|
||||
import { INTERNAL_SERVER_ERROR } from '../data/constants';
|
||||
import {
|
||||
COMPLETE_STATE, FORBIDDEN_STATE, FORM_SUBMISSION_ERROR, INTERNAL_SERVER_ERROR,
|
||||
} from '../data/constants';
|
||||
import { PASSWORD_RESET } from '../reset-password/data/constants';
|
||||
import messages from './messages';
|
||||
|
||||
const ForgotPasswordAlert = (props) => {
|
||||
const { email, emailError, intl } = props;
|
||||
let message = '';
|
||||
let heading = intl.formatMessage(messages['forgot.password.error.alert.title']);
|
||||
let { status } = props;
|
||||
|
||||
if (emailError) {
|
||||
status = 'form-submission-error';
|
||||
status = FORM_SUBMISSION_ERROR;
|
||||
}
|
||||
|
||||
let message = '';
|
||||
let heading = intl.formatMessage(messages['forgot.password.error.alert.title']);
|
||||
const supportUrl = getConfig().PASSWORD_RESET_SUPPORT_LINK;
|
||||
switch (status) {
|
||||
case 'complete':
|
||||
case COMPLETE_STATE:
|
||||
heading = intl.formatMessage(messages['confirmation.message.title']);
|
||||
message = (
|
||||
<FormattedMessage
|
||||
@@ -34,14 +35,7 @@ const ForgotPasswordAlert = (props) => {
|
||||
values={{
|
||||
email: <span className="data-hj-suppress">{email}</span>,
|
||||
supportLink: (
|
||||
<Alert.Link
|
||||
className="alert-link"
|
||||
href={supportUrl}
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
window.open(supportUrl, '_blank');
|
||||
}}
|
||||
>
|
||||
<Alert.Link href={getConfig().PASSWORD_RESET_SUPPORT_LINK} target="_blank">
|
||||
{intl.formatMessage(messages['confirmation.support.link'])}
|
||||
</Alert.Link>
|
||||
),
|
||||
@@ -52,11 +46,11 @@ const ForgotPasswordAlert = (props) => {
|
||||
case INTERNAL_SERVER_ERROR:
|
||||
message = intl.formatMessage(messages['internal.server.error']);
|
||||
break;
|
||||
case 'forbidden':
|
||||
case FORBIDDEN_STATE:
|
||||
heading = intl.formatMessage(messages['forgot.password.error.message.title']);
|
||||
message = intl.formatMessage(messages['forgot.password.request.in.progress.message']);
|
||||
break;
|
||||
case 'form-submission-error':
|
||||
case FORM_SUBMISSION_ERROR:
|
||||
message = intl.formatMessage(messages['extend.field.errors'], { emailError });
|
||||
break;
|
||||
case PASSWORD_RESET.INVALID_TOKEN:
|
||||
@@ -79,7 +73,7 @@ const ForgotPasswordAlert = (props) => {
|
||||
return (
|
||||
<Alert
|
||||
id="validation-errors"
|
||||
className="mb-5"
|
||||
className="mb-4"
|
||||
variant={`${status === 'complete' ? 'success' : 'danger'}`}
|
||||
icon={status === 'complete' ? CheckCircle : Error}
|
||||
>
|
||||
|
||||
@@ -1,149 +1,165 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
import { Formik } from 'formik';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Redirect } from 'react-router-dom';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Form,
|
||||
StatefulButton,
|
||||
Hyperlink,
|
||||
Tabs,
|
||||
Tab,
|
||||
Icon,
|
||||
StatefulButton,
|
||||
Tab,
|
||||
Tabs,
|
||||
} from '@edx/paragon';
|
||||
import { ChevronLeft } from '@edx/paragon/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Redirect } from 'react-router-dom';
|
||||
|
||||
import { forgotPassword } from './data/actions';
|
||||
import { forgotPasswordResultSelector } from './data/selectors';
|
||||
|
||||
import messages from './messages';
|
||||
import BaseComponent from '../base-component';
|
||||
import { FormGroup } from '../common-components';
|
||||
import { DEFAULT_STATE, LOGIN_PAGE, VALID_EMAIL_REGEX } from '../data/constants';
|
||||
import { updatePathWithQueryParams, windowScrollTo } from '../data/utils';
|
||||
import { forgotPassword, setForgotPasswordFormData } from './data/actions';
|
||||
import { forgotPasswordResultSelector } from './data/selectors';
|
||||
import ForgotPasswordAlert from './ForgotPasswordAlert';
|
||||
import BaseComponent from '../base-component';
|
||||
import messages from './messages';
|
||||
|
||||
const ForgotPasswordPage = (props) => {
|
||||
const { intl, status, submitState } = props;
|
||||
|
||||
const platformName = getConfig().SITE_NAME;
|
||||
const regex = new RegExp(VALID_EMAIL_REGEX, 'i');
|
||||
const [validationError, setValidationError] = useState('');
|
||||
const emailRegex = new RegExp(VALID_EMAIL_REGEX, 'i');
|
||||
const {
|
||||
intl, status, submitState, emailValidationError,
|
||||
} = props;
|
||||
|
||||
const [email, setEmail] = useState(props.email);
|
||||
const [bannerEmail, setBannerEmail] = useState('');
|
||||
const [formErrors, setFormErrors] = useState('');
|
||||
const [validationError, setValidationError] = useState(emailValidationError);
|
||||
const [key, setKey] = useState('');
|
||||
const supportUrl = getConfig().LOGIN_ISSUE_SUPPORT_LINK;
|
||||
|
||||
useEffect(() => {
|
||||
sendPageEvent('login_and_registration', 'reset');
|
||||
sendTrackEvent('edx.bi.password_reset_form.viewed', { category: 'user-engagement' });
|
||||
}, []);
|
||||
|
||||
const getValidationMessage = (email) => {
|
||||
useEffect(() => {
|
||||
setValidationError(emailValidationError);
|
||||
}, [emailValidationError]);
|
||||
|
||||
useEffect(() => {
|
||||
if (status === 'complete') {
|
||||
setEmail('');
|
||||
}
|
||||
}, [status]);
|
||||
|
||||
const getValidationMessage = (value) => {
|
||||
let error = '';
|
||||
|
||||
if (email === '') {
|
||||
if (value === '') {
|
||||
error = intl.formatMessage(messages['forgot.password.empty.email.field.error']);
|
||||
} else if (!regex.test(email)) {
|
||||
} else if (!emailRegex.test(value)) {
|
||||
error = intl.formatMessage(messages['forgot.password.page.invalid.email.message']);
|
||||
}
|
||||
|
||||
setValidationError(error);
|
||||
return error;
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
props.setForgotPasswordFormData({ email, emailValidationError: getValidationMessage(email) });
|
||||
};
|
||||
|
||||
const handleFocus = () => props.setForgotPasswordFormData({ emailValidationError: '' });
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
setBannerEmail(email);
|
||||
|
||||
const error = getValidationMessage(email);
|
||||
if (error) {
|
||||
setFormErrors(error);
|
||||
props.setForgotPasswordFormData({ email, emailValidationError: error });
|
||||
windowScrollTo({ left: 0, top: 0, behavior: 'smooth' });
|
||||
} else {
|
||||
props.forgotPassword(email);
|
||||
}
|
||||
};
|
||||
|
||||
const tabTitle = (
|
||||
<div className="d-flex">
|
||||
<Icon src={ChevronLeft} className="arrow-back-icon" />
|
||||
<div className="d-inline-flex flex-wrap align-items-center">
|
||||
<Icon src={ChevronLeft} />
|
||||
<span className="ml-2">{intl.formatMessage(messages['sign.in.text'])}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<BaseComponent>
|
||||
<Helmet>
|
||||
<title>{intl.formatMessage(messages['forgot.password.page.title'],
|
||||
{ siteName: getConfig().SITE_NAME })}
|
||||
</title>
|
||||
</Helmet>
|
||||
<div>
|
||||
<Tabs activeKey="" id="controlled-tab-example" onSelect={(k) => setKey(k)}>
|
||||
<Tabs activeKey="" id="controlled-tab" onSelect={(k) => setKey(k)}>
|
||||
<Tab title={tabTitle} eventKey={LOGIN_PAGE} />
|
||||
</Tabs>
|
||||
{ key && (
|
||||
<Redirect to={updatePathWithQueryParams(key)} />
|
||||
)}
|
||||
<div id="main-content" className="main-content">
|
||||
<Formik
|
||||
initialValues={{ email: '' }}
|
||||
validateOnChange={false}
|
||||
validate={(values) => {
|
||||
const validationMessage = getValidationMessage(values.email);
|
||||
|
||||
if (validationMessage !== '') {
|
||||
windowScrollTo({ left: 0, top: 0, behavior: 'smooth' });
|
||||
return { email: validationMessage };
|
||||
}
|
||||
|
||||
return {};
|
||||
}}
|
||||
onSubmit={(values) => { props.forgotPassword(values.email); }}
|
||||
>
|
||||
{({
|
||||
errors, handleSubmit, setFieldValue, values,
|
||||
}) => (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{intl.formatMessage(messages['forgot.password.page.title'],
|
||||
{ siteName: getConfig().SITE_NAME })}
|
||||
</title>
|
||||
</Helmet>
|
||||
<Form className="mw-xs">
|
||||
<ForgotPasswordAlert email={props.email} emailError={errors.email} status={status} />
|
||||
<h4>
|
||||
{intl.formatMessage(messages['forgot.password.page.heading'])}
|
||||
</h4>
|
||||
<p className="mb-4">
|
||||
{intl.formatMessage(messages['forgot.password.page.instructions'])}
|
||||
</p>
|
||||
<FormGroup
|
||||
floatingLabel={intl.formatMessage(messages['forgot.password.page.email.field.label'])}
|
||||
name="email"
|
||||
errorMessage={validationError}
|
||||
value={values.email}
|
||||
handleBlur={() => getValidationMessage(values.email)}
|
||||
handleChange={e => setFieldValue('email', e.target.value)}
|
||||
handleFocus={() => setValidationError('')}
|
||||
helpText={[intl.formatMessage(messages['forgot.password.email.help.text'], { platformName })]}
|
||||
/>
|
||||
<StatefulButton
|
||||
type="submit"
|
||||
variant="brand"
|
||||
className="login-button-width"
|
||||
state={submitState}
|
||||
labels={{
|
||||
default: intl.formatMessage(messages['forgot.password.page.submit.button']),
|
||||
pending: '',
|
||||
}}
|
||||
onClick={handleSubmit}
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
/>
|
||||
<Hyperlink
|
||||
id="forgot-password"
|
||||
className="ml-4 font-weight-500 text-body"
|
||||
destination={supportUrl}
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
window.open(supportUrl, '_blank');
|
||||
}}
|
||||
>{intl.formatMessage(messages['need.help.sign.in.text'])}
|
||||
</Hyperlink>
|
||||
<p className="mt-5 one-rem-font">{intl.formatMessage(messages['additional.help.text'])}
|
||||
<span><Hyperlink isInline destination={`mailto:${getConfig().INFO_EMAIL}`}>{getConfig().INFO_EMAIL}</Hyperlink></span>
|
||||
</p>
|
||||
</Form>
|
||||
</>
|
||||
<Form id="forget-password-form" name="forget-password-form" className="mw-xs">
|
||||
<ForgotPasswordAlert email={bannerEmail} emailError={formErrors} status={status} />
|
||||
<h2 className="h4">
|
||||
{intl.formatMessage(messages['forgot.password.page.heading'])}
|
||||
</h2>
|
||||
<p className="mb-4">
|
||||
{intl.formatMessage(messages['forgot.password.page.instructions'])}
|
||||
</p>
|
||||
<FormGroup
|
||||
floatingLabel={intl.formatMessage(messages['forgot.password.page.email.field.label'])}
|
||||
name="email"
|
||||
value={email}
|
||||
autoComplete="on"
|
||||
errorMessage={validationError}
|
||||
handleChange={(e) => setEmail(e.target.value)}
|
||||
handleBlur={handleBlur}
|
||||
handleFocus={handleFocus}
|
||||
helpText={[intl.formatMessage(messages['forgot.password.email.help.text'], { platformName })]}
|
||||
/>
|
||||
<StatefulButton
|
||||
id="submit-forget-password"
|
||||
name="submit-forget-password"
|
||||
type="submit"
|
||||
variant="brand"
|
||||
className="forgot-password-button-width"
|
||||
state={submitState}
|
||||
labels={{
|
||||
default: intl.formatMessage(messages['forgot.password.page.submit.button']),
|
||||
pending: '',
|
||||
}}
|
||||
onClick={handleSubmit}
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
/>
|
||||
{(getConfig().LOGIN_ISSUE_SUPPORT_LINK) && (
|
||||
<Hyperlink
|
||||
id="forgot-password"
|
||||
name="forgot-password"
|
||||
className="ml-4 font-weight-500 text-body"
|
||||
destination={getConfig().LOGIN_ISSUE_SUPPORT_LINK}
|
||||
target="_blank"
|
||||
showLaunchIcon={false}
|
||||
>
|
||||
{intl.formatMessage(messages['need.help.sign.in.text'])}
|
||||
</Hyperlink>
|
||||
)}
|
||||
</Formik>
|
||||
<p className="mt-5.5 small text-gray-700">
|
||||
{intl.formatMessage(messages['additional.help.text'], { platformName })}
|
||||
<span>
|
||||
<Hyperlink isInline destination={`mailto:${getConfig().INFO_EMAIL}`}>{getConfig().INFO_EMAIL}</Hyperlink>
|
||||
</span>
|
||||
</p>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
</BaseComponent>
|
||||
@@ -151,15 +167,18 @@ const ForgotPasswordPage = (props) => {
|
||||
};
|
||||
|
||||
ForgotPasswordPage.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
email: PropTypes.string,
|
||||
emailValidationError: PropTypes.string,
|
||||
forgotPassword: PropTypes.func.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
setForgotPasswordFormData: PropTypes.func.isRequired,
|
||||
status: PropTypes.string,
|
||||
submitState: PropTypes.string,
|
||||
};
|
||||
|
||||
ForgotPasswordPage.defaultProps = {
|
||||
email: '',
|
||||
emailValidationError: '',
|
||||
status: null,
|
||||
submitState: DEFAULT_STATE,
|
||||
};
|
||||
@@ -168,5 +187,6 @@ export default connect(
|
||||
forgotPasswordResultSelector,
|
||||
{
|
||||
forgotPassword,
|
||||
setForgotPasswordFormData,
|
||||
},
|
||||
)(injectIntl(ForgotPasswordPage));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { AsyncActionType } from '../../data/utils';
|
||||
|
||||
export const FORGOT_PASSWORD = new AsyncActionType('FORGOT', 'PASSWORD');
|
||||
export const FORGOT_PASSWORD_PERSIST_FORM_DATA = 'FORGOT_PASSWORD_PERSIST_FORM_DATA';
|
||||
|
||||
// Forgot Password
|
||||
export const forgotPassword = email => ({
|
||||
@@ -24,3 +25,8 @@ export const forgotPasswordForbidden = () => ({
|
||||
export const forgotPasswordServerError = () => ({
|
||||
type: FORGOT_PASSWORD.FAILURE,
|
||||
});
|
||||
|
||||
export const setForgotPasswordFormData = (forgotPasswordFormData) => ({
|
||||
type: FORGOT_PASSWORD_PERSIST_FORM_DATA,
|
||||
payload: { forgotPasswordFormData },
|
||||
});
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { FORGOT_PASSWORD } from './actions';
|
||||
import { INTERNAL_SERVER_ERROR, PENDING_STATE } from '../../data/constants';
|
||||
import { PASSWORD_RESET_FAILURE } from '../../reset-password/data/actions';
|
||||
import { FORGOT_PASSWORD, FORGOT_PASSWORD_PERSIST_FORM_DATA } from './actions';
|
||||
|
||||
export const defaultState = {
|
||||
status: '',
|
||||
submitState: '',
|
||||
email: '',
|
||||
emailValidationError: '',
|
||||
};
|
||||
|
||||
const reducer = (state = defaultState, action = null) => {
|
||||
@@ -13,28 +14,42 @@ const reducer = (state = defaultState, action = null) => {
|
||||
switch (action.type) {
|
||||
case FORGOT_PASSWORD.BEGIN:
|
||||
return {
|
||||
email: state.email,
|
||||
status: 'pending',
|
||||
submitState: PENDING_STATE,
|
||||
};
|
||||
case FORGOT_PASSWORD.SUCCESS:
|
||||
return {
|
||||
...action.payload,
|
||||
...defaultState,
|
||||
status: 'complete',
|
||||
};
|
||||
case FORGOT_PASSWORD.FORBIDDEN:
|
||||
return {
|
||||
email: state.email,
|
||||
status: 'forbidden',
|
||||
};
|
||||
case FORGOT_PASSWORD.FAILURE:
|
||||
return {
|
||||
email: state.email,
|
||||
status: INTERNAL_SERVER_ERROR,
|
||||
};
|
||||
case PASSWORD_RESET_FAILURE:
|
||||
return {
|
||||
status: action.payload.errorCode,
|
||||
};
|
||||
case FORGOT_PASSWORD_PERSIST_FORM_DATA: {
|
||||
const { forgotPasswordFormData } = action.payload;
|
||||
return {
|
||||
...state,
|
||||
...forgotPasswordFormData,
|
||||
};
|
||||
}
|
||||
default:
|
||||
return defaultState;
|
||||
return {
|
||||
...defaultState,
|
||||
email: state.email,
|
||||
emailValidationError: state.emailValidationError,
|
||||
};
|
||||
}
|
||||
}
|
||||
return state;
|
||||
|
||||
@@ -5,11 +5,10 @@ import { call, put, takeEvery } from 'redux-saga/effects';
|
||||
import {
|
||||
FORGOT_PASSWORD,
|
||||
forgotPasswordBegin,
|
||||
forgotPasswordSuccess,
|
||||
forgotPasswordForbidden,
|
||||
forgotPasswordServerError,
|
||||
forgotPasswordSuccess,
|
||||
} from './actions';
|
||||
|
||||
import { forgotPassword } from './service';
|
||||
|
||||
// Services
|
||||
|
||||
34
src/forgot-password/data/tests/reducers.test.js
Normal file
34
src/forgot-password/data/tests/reducers.test.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import {
|
||||
FORGOT_PASSWORD_PERSIST_FORM_DATA,
|
||||
} from '../actions';
|
||||
import reducer from '../reducers';
|
||||
|
||||
describe('forgot password reducer', () => {
|
||||
it('should set email and emailValidationError', () => {
|
||||
const state = {
|
||||
status: '',
|
||||
submitState: '',
|
||||
email: '',
|
||||
emailValidationError: '',
|
||||
};
|
||||
const forgotPasswordFormData = {
|
||||
email: 'test@gmail',
|
||||
emailValidationError: 'Enter a valid email address',
|
||||
};
|
||||
const action = {
|
||||
type: FORGOT_PASSWORD_PERSIST_FORM_DATA,
|
||||
payload: { forgotPasswordFormData },
|
||||
};
|
||||
|
||||
expect(
|
||||
reducer(state, action),
|
||||
).toEqual(
|
||||
{
|
||||
status: '',
|
||||
submitState: '',
|
||||
email: 'test@gmail',
|
||||
emailValidationError: 'Enter a valid email address',
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,16 +1,16 @@
|
||||
import { runSaga } from 'redux-saga';
|
||||
|
||||
import initializeMockLogging from '../../../setupTest';
|
||||
import * as actions from '../actions';
|
||||
import { handleForgotPassword } from '../sagas';
|
||||
import * as api from '../service';
|
||||
import initializeMockLogging from '../../../setupTest';
|
||||
|
||||
const { loggingService } = initializeMockLogging();
|
||||
|
||||
describe('handleForgotPassword', () => {
|
||||
const params = {
|
||||
payload: {
|
||||
formData: {
|
||||
forgotPasswordFormData: {
|
||||
email: 'test@test.com',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -51,11 +51,6 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Enter your email',
|
||||
description: 'Error message that appears when user tries to submit empty email field',
|
||||
},
|
||||
'forgot.password.invalid.email.heading': {
|
||||
id: 'forgot.password.invalid.email',
|
||||
defaultMessage: 'An error occurred.',
|
||||
description: 'heading for invalid email',
|
||||
},
|
||||
'forgot.password.invalid.email.message': {
|
||||
id: 'forgot.password.invalid.email.message',
|
||||
defaultMessage: "The email address you've provided isn't formatted correctly.",
|
||||
@@ -84,7 +79,7 @@ const messages = defineMessages({
|
||||
},
|
||||
'additional.help.text': {
|
||||
id: 'additional.help.text',
|
||||
defaultMessage: 'For additional help, contact edX support at ',
|
||||
defaultMessage: 'For additional help, contact {platformName} support at ',
|
||||
description: 'additional help text on forgot password page',
|
||||
},
|
||||
'sign.in.text': {
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import React from 'react';
|
||||
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { Provider } from 'react-redux';
|
||||
import { MemoryRouter, Router } from 'react-router-dom';
|
||||
import configureStore from 'redux-mock-store';
|
||||
import { createMemoryHistory } from 'history';
|
||||
|
||||
import * as analytics from '@edx/frontend-platform/analytics';
|
||||
import CookiePolicyBanner from '@edx/frontend-component-cookie-policy-banner';
|
||||
import { mergeConfig } from '@edx/frontend-platform';
|
||||
import { IntlProvider, injectIntl, configure } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import * as analytics from '@edx/frontend-platform/analytics';
|
||||
import * as auth from '@edx/frontend-platform/auth';
|
||||
import ForgotPasswordPage from '../ForgotPasswordPage';
|
||||
import { configure, injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { mount } from 'enzyme';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { MemoryRouter, Router } from 'react-router-dom';
|
||||
import configureStore from 'redux-mock-store';
|
||||
|
||||
import { INTERNAL_SERVER_ERROR, LOGIN_PAGE } from '../../data/constants';
|
||||
import { PASSWORD_RESET } from '../../reset-password/data/constants';
|
||||
import { setForgotPasswordFormData } from '../data/actions';
|
||||
import ForgotPasswordPage from '../ForgotPasswordPage';
|
||||
|
||||
jest.mock('@edx/frontend-platform/analytics');
|
||||
jest.mock('@edx/frontend-platform/auth');
|
||||
@@ -66,7 +66,15 @@ describe('ForgotPasswordPage', () => {
|
||||
};
|
||||
});
|
||||
|
||||
it('not should display need other help signing in button', () => {
|
||||
const wrapper = mount(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
||||
expect(wrapper.find('#forgot-password').exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should display need other help signing in button', () => {
|
||||
mergeConfig({
|
||||
LOGIN_ISSUE_SUPPORT_LINK: '/support',
|
||||
});
|
||||
const wrapper = mount(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
||||
expect(wrapper.find('#forgot-password').first().text()).toEqual('Need help signing in?');
|
||||
});
|
||||
@@ -125,28 +133,61 @@ describe('ForgotPasswordPage', () => {
|
||||
expect(forgotPasswordPage.find('#email-invalid-feedback').exists()).toEqual(false);
|
||||
});
|
||||
|
||||
it('should display error message on blur event', async () => {
|
||||
const validationMessage = 'Enter your email';
|
||||
it('should set error in redux store on onBlur', () => {
|
||||
const forgotPasswordFormData = {
|
||||
email: 'test@gmail',
|
||||
emailValidationError: 'Enter a valid email address',
|
||||
};
|
||||
|
||||
props = {
|
||||
...props,
|
||||
email: 'test@gmail',
|
||||
emailValidationError: '',
|
||||
};
|
||||
|
||||
store.dispatch = jest.fn(store.dispatch);
|
||||
const forgotPasswordPage = mount(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
||||
const emailInput = forgotPasswordPage.find('input#email');
|
||||
|
||||
await act(async () => {
|
||||
await emailInput.simulate('blur', { target: { value: '', name: 'email' } });
|
||||
});
|
||||
forgotPasswordPage.find('input#email').simulate('blur');
|
||||
expect(store.dispatch).toHaveBeenCalledWith(setForgotPasswordFormData(forgotPasswordFormData));
|
||||
});
|
||||
|
||||
it('should display error message if available in props', async () => {
|
||||
const validationMessage = 'Enter your email';
|
||||
props = {
|
||||
...props,
|
||||
emailValidationError: validationMessage,
|
||||
email: '',
|
||||
};
|
||||
const forgotPasswordPage = mount(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
||||
forgotPasswordPage.update();
|
||||
expect(forgotPasswordPage.find('.pgn__form-text-invalid').text()).toEqual(validationMessage);
|
||||
});
|
||||
|
||||
it('should clear error message on focus event', async () => {
|
||||
const validationMessage = 'Enter your email';
|
||||
it('should clear error in redux store on onFocus', () => {
|
||||
const forgotPasswordFormData = {
|
||||
emailValidationError: '',
|
||||
};
|
||||
|
||||
props = {
|
||||
...props,
|
||||
email: 'test@gmail',
|
||||
emailValidationError: 'Enter a valid email address',
|
||||
};
|
||||
|
||||
store.dispatch = jest.fn(store.dispatch);
|
||||
const forgotPasswordPage = mount(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
||||
await act(async () => { await forgotPasswordPage.find('button.btn-brand').simulate('click'); });
|
||||
|
||||
forgotPasswordPage.update();
|
||||
expect(forgotPasswordPage.find('.pgn__form-text-invalid').text()).toEqual(validationMessage);
|
||||
|
||||
forgotPasswordPage.find('input#email').simulate('focus');
|
||||
expect(store.dispatch).toHaveBeenCalledWith(setForgotPasswordFormData(forgotPasswordFormData));
|
||||
});
|
||||
|
||||
it('should clear error message when cleared in props on focus', async () => {
|
||||
props = {
|
||||
...props,
|
||||
emailValidationError: '',
|
||||
email: '',
|
||||
};
|
||||
const forgotPasswordPage = mount(reduxWrapper(<IntlForgotPasswordPage {...props} />));
|
||||
forgotPasswordPage.update();
|
||||
expect(forgotPasswordPage.find('#email-invalid-feedback').exists()).toEqual(false);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
import arMessages from './messages/ar.json';
|
||||
import caMessages from './messages/ca.json';
|
||||
// no need to import en messages-- they are in the defaultMessage field
|
||||
import dedeMessages from './messages/de_DE.json';
|
||||
import es419Messages from './messages/es_419.json';
|
||||
import frMessages from './messages/fr.json';
|
||||
import zhcnMessages from './messages/zh_CN.json';
|
||||
import heMessages from './messages/he.json';
|
||||
import hiMessages from './messages/hi.json';
|
||||
import idMessages from './messages/id.json';
|
||||
import ititMessages from './messages/it_IT.json';
|
||||
import kokrMessages from './messages/ko_kr.json';
|
||||
import plMessages from './messages/pl.json';
|
||||
import ptbrMessages from './messages/pt_br.json';
|
||||
import ptptMessages from './messages/pt_PT.json';
|
||||
import ruMessages from './messages/ru.json';
|
||||
import thMessages from './messages/th.json';
|
||||
import ukMessages from './messages/uk.json';
|
||||
import zhcnMessages from './messages/zh_CN.json';
|
||||
|
||||
const messages = {
|
||||
ar: arMessages,
|
||||
@@ -19,6 +23,9 @@ const messages = {
|
||||
'es-419': es419Messages,
|
||||
fr: frMessages,
|
||||
'zh-cn': zhcnMessages,
|
||||
'it-it': ititMessages,
|
||||
'pt-pt': ptptMessages,
|
||||
'de-de': dedeMessages,
|
||||
ca: caMessages,
|
||||
he: heMessages,
|
||||
id: idMessages,
|
||||
@@ -28,6 +35,7 @@ const messages = {
|
||||
ru: ruMessages,
|
||||
th: thMessages,
|
||||
uk: ukMessages,
|
||||
hi: hiMessages,
|
||||
};
|
||||
|
||||
export default messages;
|
||||
|
||||
@@ -1,199 +1,231 @@
|
||||
{
|
||||
"start.learning": "Start learning",
|
||||
"with.site.name": "with {siteName}",
|
||||
"complete.your.profile.1": "Complete",
|
||||
"complete.your.profile.2": "your profile",
|
||||
"welcome.to.platform": "Welcome to {siteName}, {username}!",
|
||||
"institution.login.page.sub.heading": "Choose your institution from the list below",
|
||||
"forgot.password.confirmation.title": "Check your email",
|
||||
"forgot.password.confirmation.support.link": "contact technical support",
|
||||
"forgot.password.confirmation.info": "If you do not receive a password reset message after 1 minute, verify that you entered the correct email address, or check your spam folder.",
|
||||
"logistration.sign.in": "Sign in",
|
||||
"logistration.register": "Register",
|
||||
"internal.server.error.message": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"server.ratelimit.error.message": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"enterprisetpa.title.heading": "Would you like to sign in using your {providerName} credentials?",
|
||||
"enterprisetpa.sso.button.title": "Sign in using {providerName}",
|
||||
"enterprisetpa.login.button.text": "Show me other ways to sign in or register",
|
||||
"sso.sign.in.with": "Sign in with {providerName}",
|
||||
"sso.create.account.using": "Create account using {providerName}",
|
||||
"show.password": "Show password",
|
||||
"hide.password": "Hide password",
|
||||
"one.letter": "1 Letter",
|
||||
"one.number": "1 Number",
|
||||
"eight.characters": "8 Characters",
|
||||
"password.sr.only.helping.text": "Password must contain at least 8 characters, at least one letter, and at least one number",
|
||||
"tpa.alert.heading": "Almost done!",
|
||||
"login.third.party.auth.account.not.linked": "You have successfully signed into {currentProvider}, but your {currentProvider} account does not have a linked {platformName} account. To link your accounts, sign in now using your {platformName} password.",
|
||||
"register.third.party.auth.account.not.linked": "You've successfully signed into {currentProvider}! We just need a little more information before you start learning with {platformName}.",
|
||||
"error.notfound.message": "الصفحة التي تبحث عنها غير متوفرة أو هناك خطأ في نص الرابط. الرجاء التحقق من الرابط والمحاولة مجددا.",
|
||||
"forgot.password.confirmation.message": "We sent an email to {email} with instructions to reset your password.\n If you do not receive a password reset message after 1 minute, verify that you entered\n the correct email address, or check your spam folder. If you need further assistance, {supportLink}.",
|
||||
"forgot.password.page.title": "Forgot Password | {siteName}",
|
||||
"forgot.password.page.heading": "Reset password",
|
||||
"forgot.password.page.instructions": "Please enter your email address below and we will send you an email with instructions on how to reset your password.",
|
||||
"forgot.password.page.invalid.email.message": "Enter a valid email address",
|
||||
"forgot.password.page.email.field.label": "Email",
|
||||
"forgot.password.page.submit.button": "Submit",
|
||||
"forgot.password.error.alert.title.": "We were unable to contact you.",
|
||||
"forgot.password.error.message.title": "An error occurred.",
|
||||
"forgot.password.request.in.progress.message": "Your previous request is in progress, please try again in a few moments.",
|
||||
"forgot.password.empty.email.field.error": "Enter your email",
|
||||
"forgot.password.invalid.email": "An error occurred.",
|
||||
"forgot.password.invalid.email.message": "The email address you've provided isn't formatted correctly.",
|
||||
"forgot.password.email.help.text": "The email address you used to register with {platformName}",
|
||||
"confirmation.message.title": "Check your email",
|
||||
"confirmation.support.link": "contact technical support",
|
||||
"need.help.sign.in.text": "Need help signing in?",
|
||||
"additional.help.text": "For additional help, contact edX support at ",
|
||||
"sign.in.text": "Sign in",
|
||||
"extend.field.errors": "{emailError} below.",
|
||||
"invalid.token.heading": "Invalid password reset link",
|
||||
"invalid.token.error.message": "This password reset link is invalid. It may have been used already. Enter your email below to receive a new link.",
|
||||
"token.validation.rate.limit.error.heading": "Too many requests",
|
||||
"token.validation.rate.limit.error": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"token.validation.internal.sever.error.heading": "Token validation failure",
|
||||
"token.validation.internal.sever.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"internal.server.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"rate.limit.error": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"account.activation.error.message": "Something went wrong, please {supportLink} to resolve this issue.",
|
||||
"login.inactive.user.error": "أنت بحاجة لتنشيط حسابك من أجل تسجيل الدخول {lineBreak}\n{lineBreak}لقد أرسلنا للتو رابط التفعيل إلى البريد الإلكتروني {email}. تحقق من مجلدات الرسائل غير المرغوب فيها أو {supportLink} إذا لم تستلم بريدًا إلكترونيًا.",
|
||||
"login.incorrect.credentials.error.attempts.text.1": "The username, email or password you entered is incorrect. You have {remainingAttempts} more sign in\n attempts before your account is temporarily locked.",
|
||||
"login.incorrect.credentials.error.attempts.text.2": "If you've forgotten your password, {resetLink}",
|
||||
"account.locked.out.message.2": "To be on the safe side, you can {resetLink} before trying again.",
|
||||
"login.incorrect.credentials.error.with.reset.link": "The username, email, or password you entered is incorrect. Please try again or {resetLink}.",
|
||||
"login.page.title": "Login | {siteName}",
|
||||
"login.user.identity.label": "Username or email",
|
||||
"login.password.label": "Password",
|
||||
"sign.in.button": "Sign in",
|
||||
"sign.in.btn.pending.state": "Loading",
|
||||
"need.help.signing.in.collapsible.menu": "Need help signing in?",
|
||||
"forgot.password.link": "Forgot my password",
|
||||
"forgot.password": "Forgot password",
|
||||
"other.sign.in.issues": "Other sign in issues",
|
||||
"need.other.help.signing.in.collapsible.menu": "Need other help signing in?",
|
||||
"institution.login.button": "Institution/campus credentials",
|
||||
"institution.login.page.title": "Sign in with institution/campus credentials",
|
||||
"institution.login.page.back.button": "Back to sign in",
|
||||
"create.an.account": "Create an account",
|
||||
"login.other.options.heading": "Or sign in with:",
|
||||
"non.compliant.password.title": "We recently changed our password requirements",
|
||||
"non.compliant.password.message": "Your current password does not meet the new security requirements. We just sent a password-reset message to the email address associated with this account. Thank you for helping us keep your data safe.",
|
||||
"account.locked.out.message.1": "To protect your account, it's been temporarily locked. Try again in 30 minutes.",
|
||||
"first.time.here": "First time here?",
|
||||
"email.help.message": "The email address you used to register with edX.",
|
||||
"enterprise.login.btn.text": "Company or school credentials",
|
||||
"email.format.validation.message": "The email address you've provided isn't formatted correctly.",
|
||||
"username.or.email.format.validation.less.chars.message": "Username or email must have at least 3 characters.",
|
||||
"email.validation.message": "Enter your username or email",
|
||||
"password.validation.message": "Password criteria has not been met",
|
||||
"register.link": "Create an account",
|
||||
"sign.in.heading": "Sign in",
|
||||
"account.activation.success.message.title": "Success! You have activated your account.",
|
||||
"account.activation.success.message": "You will now receive email updates and alerts from us related to the courses you are enrolled in. Sign in to continue.",
|
||||
"account.already.activated.message": "This account has already been activated.",
|
||||
"account.activation.error.message.title": "Your account could not be activated",
|
||||
"account.activation.support.link": "contact support",
|
||||
"login.rate.limit.reached.message": "Too many failed login attempts. Try again later.",
|
||||
"login.failure.header.title": "We couldn't sign you in.",
|
||||
"contact.support.link": "contact {platformName} support",
|
||||
"login.incorrect.credentials.error": "The username, email, or password you entered is incorrect. Please try again.",
|
||||
"login.failed.attempt.error": "You have {remainingAttempts} more sign in attempts before your account is temporarily locked.",
|
||||
"login.locked.out.error.message": "To protect your account, it’s been temporarily locked. Try again in {lockedOutPeriod} minutes.",
|
||||
"login.form.invalid.error.message": "Please fill in the fields below.",
|
||||
"login.incorrect.credentials.error.reset.link.text": "reset your password",
|
||||
"login.incorrect.credentials.error.before.account.blocked.text": "click here to reset it.",
|
||||
"register.page.title": "Register | {siteName}",
|
||||
"registration.fullname.label": "Full name",
|
||||
"registration.email.label": "Email",
|
||||
"registration.username.label": "Public username",
|
||||
"registration.password.label": "Password",
|
||||
"registration.country.label": "Country/Region",
|
||||
"help.text.name": "This name will be used by any certificates that you earn.",
|
||||
"help.text.username.1": "The name that will identify you in your courses.",
|
||||
"help.text.username.2": "This can not be changed later.",
|
||||
"help.text.email": "For account activation and important updates",
|
||||
"create.account.button": "Create an account",
|
||||
"create.an.account.btn.pending.state": "Loading",
|
||||
"registration.other.options.heading": "Or register with:",
|
||||
"register.institution.login.button": "Institution/campus credentials",
|
||||
"register.institution.login.page.title": "Register with institution/campus credentials",
|
||||
"empty.name.field.error": "Enter your full name",
|
||||
"empty.email.field.error": "Enter your email",
|
||||
"empty.country.field.error": "Select your country or region of residence",
|
||||
"email.invalid.format.error": "Enter a valid email address",
|
||||
"email.ratelimit.less.chars.validation.message": "Email must have 3 characters.",
|
||||
"username.validation.message": "Username must be between 2 and 30 characters",
|
||||
"username.format.validation.message": "Usernames can only contain letters (A-Z, a-z), numerals (0-9), underscores (_), and hyphens (-).",
|
||||
"support.education.research": "Support education research by providing additional information. (Optional)",
|
||||
"registration.request.failure.header": "We couldn't create your account.",
|
||||
"registration.empty.form.submission.error": "Please check your responses and try again.",
|
||||
"registration.request.server.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"registration.rate.limit.error": "Too many failed registration attempts. Try again later.",
|
||||
"registration.tpa.session.expired": "Registration using {provider} has timed out.",
|
||||
"terms.of.service.and.honor.code": "Terms of Service and Honor Code",
|
||||
"privacy.policy": "Privacy Policy",
|
||||
"registration.year.of.birth.label": "Year of birth (optional)",
|
||||
"registration.field.gender.options.label": "Gender (optional)",
|
||||
"registration.goals.label": "Tell us why you're interested in edX (optional)",
|
||||
"registration.field.gender.options.f": "Female",
|
||||
"registration.field.gender.options.m": "Male",
|
||||
"registration.field.gender.options.o": "Other/Prefer not to say",
|
||||
"registration.field.education.levels.label": "Highest level of education completed (optional)",
|
||||
"registration.field.education.levels.p": "Doctorate",
|
||||
"registration.field.education.levels.m": "Master's or professional degree",
|
||||
"registration.field.education.levels.b": "Bachelor's degree",
|
||||
"registration.field.education.levels.a": "Associate's degree",
|
||||
"registration.field.education.levels.hs": "Secondary/high school",
|
||||
"registration.field.education.levels.jhs": "Junior secondary/junior high/middle school",
|
||||
"registration.field.education.levels.el": "Elementary/primary school",
|
||||
"registration.field.education.levels.none": "No formal education",
|
||||
"registration.field.education.levels.other": "Other education",
|
||||
"registration.username.suggestion.label": "Available:",
|
||||
"registration.using.tpa.form.heading": "Finish creating your account",
|
||||
"did.you.mean.alert.text": "Did you mean",
|
||||
"register.page.terms.of.service.and.honor.code": "By creating an account, you agree to the {tosAndHonorCode} and you acknowledge that {platformName} and each\n Member process your personal data in accordance with the {privacyPolicy}.",
|
||||
"sign.in": "Sign in",
|
||||
"reset.password.page.title": "Reset Password | {siteName}",
|
||||
"reset.password": "Reset password",
|
||||
"reset.password.page.instructions": "Enter and confirm your new password.",
|
||||
"new.password.label": "New password",
|
||||
"confirm.password.label": "Confirm password",
|
||||
"passwords.do.not.match": "Passwords do not match",
|
||||
"confirm.your.password": "Confirm your password",
|
||||
"forgot.password.confirmation.sign.in.link": "sign in",
|
||||
"reset.password.request.forgot.password.text": "Forgot password",
|
||||
"reset.password.request.invalid.token.header": "Invalid password reset link",
|
||||
"reset.password.empty.new.password.field.error": "Please enter your new password.",
|
||||
"reset.password.failure.heading": "We couldn't reset your password.",
|
||||
"reset.password.form.submission.error": "Please check your responses and try again.",
|
||||
"reset.password.request.server.error": "Failed to reset password",
|
||||
"reset.password.token.validation.sever.error": "Token validation failure",
|
||||
"reset.server.rate.limit.error": "Too many requests.",
|
||||
"reset.password.success.heading": "Password reset complete.",
|
||||
"reset.password.success": "Your password has been reset. Sign in to your account.",
|
||||
"progressive.profiling.page.title": "Optional Fields | {siteName}",
|
||||
"progressive.profiling.page.heading": "A few questions for you will help us get smarter.",
|
||||
"gender.options.label": "Gender (optional)",
|
||||
"gender.options.f": "Female",
|
||||
"gender.options.m": "Male",
|
||||
"gender.options.o": "Other/Prefer not to say",
|
||||
"education.levels.label": "Highest level of education completed (optional)",
|
||||
"education.levels.p": "Doctorate",
|
||||
"education.levels.m": "Master's or professional degree",
|
||||
"education.levels.b": "Bachelor's degree",
|
||||
"education.levels.a": "Associate's degree",
|
||||
"education.levels.hs": "Secondary/high school",
|
||||
"education.levels.jhs": "Junior secondary/junior high/middle school",
|
||||
"education.levels.el": "Elementary/primary school",
|
||||
"education.levels.none": "No formal education",
|
||||
"education.levels.other": "Other education",
|
||||
"year.of.birth.label": "Year of birth (optional)",
|
||||
"optional.fields.information.link": "Learn more about how we use this information.",
|
||||
"optional.fields.submit.button": "Submit",
|
||||
"optional.fields.skip.button": "Skip for now",
|
||||
"continue.to.platform": "Continue to {platformName}",
|
||||
"modal.title": "Thanks for letting us know.",
|
||||
"modal.description": "You can complete your profile in settings at any time if you change your mind.",
|
||||
"welcome.page.error.heading": "We couldn't update your profile",
|
||||
"welcome.page.error.message": "An error occurred. You can complete your profile in settings at any time."
|
||||
"start.learning": "ابدأ التعلم ",
|
||||
"with.site.name": "مع {siteName}",
|
||||
"complete.your.profile.1": "أكمل",
|
||||
"complete.your.profile.2": "ملفك الشخصي",
|
||||
"welcome.to.platform": "أهلا بك {username} في {siteName}",
|
||||
"institution.login.page.sub.heading": "اختر مؤسستك من القائمة أدناه",
|
||||
"forgot.password.confirmation.title": "تفقّد بريدك الإلكتروني",
|
||||
"forgot.password.confirmation.support.link": "اتصل بالدعم الفني",
|
||||
"forgot.password.confirmation.info": "إن لم تستلم رسالة إعادة تعيين كلمة المرور بعد دقيقة واحدة، فتحقق من أنك أدخلت عنوان البريد الإلكتروني الصحيح، أو تفقّد مجلد الرسائل غير المرغوب فيها في بريدك الإلكتروني.",
|
||||
"logistration.sign.in": "تسجيل الدخول",
|
||||
"logistration.register": "التسجيل",
|
||||
"internal.server.error.message": "حدث خطأ ما. جرّب تحديث الصفحة أو تحقق من اتصالك بالانترنت.",
|
||||
"server.ratelimit.error.message": "حدث خطأ بسبب كثرة الطلبات. رجاءً حاول مرة أخرى بعد مضي بعض الوقت.",
|
||||
"enterprisetpa.title.heading": "هل ترغب في تسجيل الدخول باستخدام بيانات {providerName} الخاصة بك؟",
|
||||
"enterprisetpa.sso.button.title": "تسجيل الدخول باستخدام {providerName}",
|
||||
"enterprisetpa.login.button.text": "أرِني وسائل أخرى لتسجيل الدخول أو للتسجيل",
|
||||
"sso.sign.in.with": "تسجيل الدخول باستخدام {providerName}",
|
||||
"sso.create.account.using": "إنشاء حساب باستخدام {providerName}",
|
||||
"show.password": "إظهار كلمة المرور",
|
||||
"hide.password": "اخفاء كلمة المرور",
|
||||
"one.letter": "حرف واحد",
|
||||
"one.number": "رقم واحد",
|
||||
"eight.characters": "8 رموز",
|
||||
"password.sr.only.helping.text": "يجب أن تحتوي كلمة المرور على الأقل 8 رموز، منها حرف واحد و رقم واحد على الأقل.",
|
||||
"tpa.alert.heading": "انتهينا تقريبا!",
|
||||
"login.third.party.auth.account.not.linked": "لقد نجحت في تسجيل الدخول إلى {currentProvider}، لكن حسابك على {currentProvider} غير موصول بأي حساب على {platformName}. لوصل حساباتك، سجّل الدخول الآن باستخدام كلمة مرورك على {platformName}.",
|
||||
"register.third.party.auth.account.not.linked": "لقد سجلت دخولك بنجاح إلى {currentProvider}! نحتاج فقط قليلاً بعدُ من المعلومات قبل أن تبدأ التعلم مع {platformName}.",
|
||||
"error.notfound.message": "الصفحة التي تبحث عنها غير متوفرة أو هناك خطأ في العنوان. رجاءً تحقق من العنوان و حاول مجددًا.",
|
||||
"forgot.password.confirmation.message": "لقد أرسلنا بريدًا إلكترونيًا إلى {email} به إرشادات لإعادة ضبط كلمة المرور الخاصة بك. إن لم تستلم رسالة إعادة ضبط كلمة المرور بعد دقيقة واحدة، فتحقق من إدخال عنوان البريد الإلكتروني الصحيح، أو تفقد مجلد الرسائل غير المرغوب فيها. إن احتجت مزيدًا من المساعدة، {supportLink}.",
|
||||
"forgot.password.page.title": "نسيت كلمة المرور | {siteName}",
|
||||
"forgot.password.page.heading": "إعادة ضبط كلمة المرور",
|
||||
"forgot.password.page.instructions": "رجاءً أدخل عنوان بريدك الإلكتروني أدناه وسنرسل إليك بريدًا به إرشادات بخصوص كيفية إعادة ضبط كلمة مرورك.",
|
||||
"forgot.password.page.invalid.email.message": "أدخل عنوان بريد إلكتروني صحيح",
|
||||
"forgot.password.page.email.field.label": "البريد الإلكتروني",
|
||||
"forgot.password.page.submit.button": "إرسال",
|
||||
"forgot.password.error.alert.title.": "لم نتمكن من الاتصال بك.",
|
||||
"forgot.password.error.message.title": "حدث خطأ ما.",
|
||||
"forgot.password.request.in.progress.message": "طلبك السابق قيد التنفيذ، يرجى المحاولة مرة أخرى بعد لحظات قليلة.",
|
||||
"forgot.password.empty.email.field.error": "أدخل بريدك الإلكتروني",
|
||||
"forgot.password.invalid.email.message": "صيغة عنوان البريد الإلكتروني الذي أدخلته غير صحيحة",
|
||||
"forgot.password.email.help.text": "عنوان البريد الإلكتروني الذي استخدمته للتسجيل في {platformName}",
|
||||
"confirmation.message.title": "تفقّد بريدك الإلكتروني",
|
||||
"confirmation.support.link": "اتصل بالدعم الفني",
|
||||
"need.help.sign.in.text": "هل تحتاج مساعدة في تسجيل الدخول؟",
|
||||
"additional.help.text": "للمزيد من المساعدة، اتصل بدعم {platformName} على ",
|
||||
"sign.in.text": "تسجيل الدخول",
|
||||
"extend.field.errors": "{emailError} أدناه.",
|
||||
"invalid.token.heading": "رابط إعادة ضبط كلمة المرور غير صالح",
|
||||
"invalid.token.error.message": "رابط إعادة ضبط كلمة المرور هذا غير صالح. قد يكون مستعمَلا من قبل. أدخل بريدك الإلكتروني أدناه لتلقي رابط جديد.",
|
||||
"token.validation.rate.limit.error.heading": "طلبات أكثر مما ينبغي",
|
||||
"token.validation.rate.limit.error": "حدث خطأ بسبب كثرة الطلبات. رجاءً حاول مرة أخرى بعد مضي بعض الوقت.",
|
||||
"token.validation.internal.sever.error.heading": "فشل في التحقق من صحة الشارة",
|
||||
"token.validation.internal.sever.error": "حدث خطأ ما. جرب تحديث الصفحة أو تحقق من اتصالك بالإنترنت.",
|
||||
"internal.server.error": "حدث خطأ ما. جرب تحديث الصفحة أو تحقق من اتصالك بالإنترنت.",
|
||||
"rate.limit.error": "حدث خطأ بسبب كثرة الطلبات. رجاءً حاول مرة أخرى بعد مضي بعض الوقت.",
|
||||
"account.activation.error.message": "شي ما لم يسر على ما يرام، يرجى {supportLink} لحل هذه المشكلة.",
|
||||
"login.inactive.user.error": "أنت بحاجة لتفعيل حسابك من أجل تسجيل الدخول{lineBreak}\n{lineBreak}لقد أرسلنا للتو رابطًا للتفعيل إلى {email}. إن لم تتلقّ بريدًا إلكترونيا، تفقّد مجلدات الرسائل غير المرغوب فيها أو {supportLink}.",
|
||||
"allowed.domain.login.error": "كونك مستخدمًا على {allowedDomain}، فإن عليك تسجيل الدخول باستخدام {tpaLink} الخاص بـ {allowedDomain} .",
|
||||
"login.incorrect.credentials.error.attempts.text.1": "اسم المستخدم أو البريد الإلكتروني أو كلمة المرور التي أدخلتها غير صحيحة. لديك {remainingAttempts, plural,\n one {محاولة واحدة}\n two {محاولتان}\n few {# محاولات}\n many {# محاولة}\n other {# محاولة}\n} أخرى لتسجيل الدخول قبل أن يتم إقفال حسابك مؤقتًا.",
|
||||
"login.incorrect.credentials.error.attempts.text.2": "إن نسيت كلمة مرورك، {resetLink}",
|
||||
"account.locked.out.message.2": "لتكون في مأمن، يمكنك {resetLink} قبل تكرار المحاولة.",
|
||||
"login.incorrect.credentials.error.with.reset.link": "اسم المستخدم أو البريد الإلكتروني أو كلمة المرور التي أدخلتها غير صحيحة. يرجى تكرار المحاولة أو {resetLink}.",
|
||||
"login.page.title": "تسجيل الدخول | {siteName}",
|
||||
"login.user.identity.label": "اسم المستخدم أو البريد الإلكتروني",
|
||||
"login.password.label": "كلمة المرور",
|
||||
"sign.in.button": "تسجيل الدخول",
|
||||
"sign.in.btn.pending.state": "التحميل جارٍ",
|
||||
"need.help.signing.in.collapsible.menu": "هل تحتاج مساعدة في تسجيل الدخول؟",
|
||||
"forgot.password.link": "نسيت كلمة مروري",
|
||||
"forgot.password": "نسيت كلمة المرور",
|
||||
"other.sign.in.issues": "مشاكل أخرى عند تسجيل الدخول",
|
||||
"need.other.help.signing.in.collapsible.menu": "هل تحتاج مساعدة أخرى في تسجيل الدخول؟",
|
||||
"institution.login.button": "بيانات المؤسسة / الجامعة",
|
||||
"institution.login.page.title": "تسجيل الدخول باستخدام بيانات المؤسسة / الجامعة",
|
||||
"institution.login.page.back.button": "العودة إلى تسجيل الدخول",
|
||||
"create.an.account": " أنشئ حساباً جديداً.",
|
||||
"login.other.options.heading": "أو قم بتسجيل الدخول باستخدام:",
|
||||
"non.compliant.password.title": "لقد غيرنا متطلبات أمان كلمة المرور مؤخرًا",
|
||||
"non.compliant.password.message": "كلمة مرورك الحالية لا تستسجيب لمتطلبات الأمان الجديدة. لقد أرسلنا للتو رسالة لإعادة ضبط كلمة المرور إلى عنوان البريد الإلكتروني المرتبط بهذا الحساب. شكرًا لك على مساعدتنا في الحفاظ على سلامة بياناتك.",
|
||||
"account.locked.out.message.1": "لحماية حسابك، تم إقفاله مؤقتًا. حاول مرة أخرى بعد 30 دقيقة.",
|
||||
"first.time.here": "أول مرة لك هنا؟",
|
||||
"email.help.message": "عنوان البريد الإلكتروني الذي استخدمته للتسجيل في edX.",
|
||||
"enterprise.login.btn.text": "بيانات الشركة أو المدرسة",
|
||||
"email.format.validation.message": "صيغة عنوان البريد الإلكتروني الذي أدخلته غير صحيحة",
|
||||
"username.or.email.format.validation.less.chars.message": "يجب أن يحتوي اسم المستخدم أو البريد الإلكتروني على 3 أحرف على الأقل.",
|
||||
"email.validation.message": "أدخل اسم المستخدم أو البريد الإلكتروني الخاص بك",
|
||||
"password.validation.message": "لم يتم استيفاء معايير كلمة المرور",
|
||||
"register.link": " أنشئ حساباً",
|
||||
"sign.in.heading": "تسجيل الدخول",
|
||||
"account.activation.success.message.title": "نجح الأمر! لقد قمت بتفعيل حسابك.",
|
||||
"account.activation.success.message": "ستصلك الآن تحديثات وتنبيهات عبر البريد الإلكتروني منا تتعلق بالمساقات التي قمت بالتسجيل فيها. قم بتسجيل الدخول للمتابعة.",
|
||||
"account.activation.info.message": "هذا الحساب مفعَّل من قبل.",
|
||||
"account.activation.error.message.title": "لا يمكن تفعيل حسابك",
|
||||
"account.activation.support.link": "الاتصال بالدعم",
|
||||
"tpa.account.link": "حساب {provider}",
|
||||
"account.confirmation.success.message.title": "نجحت العملية! لقد أكدت بريدك الإلكتروني.",
|
||||
"account.confirmation.success.message": "سجل دخولك للمتابعة.",
|
||||
"account.confirmation.info.message": "هذا البريد الإلكتروني مؤكد من قبل.",
|
||||
"account.confirmation.error.message.title": "لا يمكن تأكيد بريدك الإلكتروني",
|
||||
"login.rate.limit.reached.message": "كثرت محاولات تسجيل الدخول الفاشلة. رجاءً أعد المحاولة لاحقًا.",
|
||||
"login.failure.header.title": "لم نتمكّن من تسجيل دخولك.",
|
||||
"contact.support.link": "اتصل بدعم {platformName}",
|
||||
"login.incorrect.credentials.error": "اسم المستخدم أو البريد الإلكتروني أو كلمة المرور التي أدخلتها غير صحيحة. حاول مرة اخرى.",
|
||||
"login.failed.attempt.error": "لديك {remainingAttempts, plural,\none {محاولة واحدة}\ntwo {محاولتان}\nfew {# محاولات}\nmany {# محاولة}\nother {# محاولة}\n} أخرى لتسجيل الدخول قبل أن يتم إقفال حسابك مؤقتًا.",
|
||||
"login.locked.out.error.message": "لحماية حسابك، تم إقفاله مؤقتًا. حاول مرة أخرى بعد {lockedOutPeriod, plural,\n one {دقيقة واحدة}\n two {دقيقتين}\n few {# دقائق}\n many {# دقيقة}\n other {# دقيقة}\n}.",
|
||||
"login.form.invalid.error.message": "رجاءً املأ الحقول أدناه.",
|
||||
"login.incorrect.credentials.error.reset.link.text": "إعادة ضبط كلمه المرور",
|
||||
"login.incorrect.credentials.error.before.account.blocked.text": "انقر هنا لإعادة ضبطها.",
|
||||
"password.security.nudge.title": "أمان كلمة المرور",
|
||||
"password.security.block.title": "مطلوب تغيير كلمة المرور",
|
||||
"password.security.nudge.body": "اكتشف نظامنا أن كلمة مرورك ضعيفة. ننصحك بتغييرها حتى يظل حسابك آمنًا.",
|
||||
"password.security.block.body": "اكتشف نظامنا أن كلمة مرورك صعيفة. غيّر كلمة مرورك حتى يظل حسابك آمنًا.",
|
||||
"password.security.close.button": "إغلاق",
|
||||
"password.security.redirect.to.reset.password.button": "إعادة ضبط كلمة المرور",
|
||||
"progressive.profiling.page.title": "الحقول الاختيارية | {siteName}",
|
||||
"progressive.profiling.page.heading": "بعض الأسئلة الموجهة لك ستساعدنا كي نزداد ذكاءً.",
|
||||
"optional.fields.information.link": "معرفة المزيد عن كيفية استخدامنا لهذه المعلومات.",
|
||||
"optional.fields.submit.button": "إرسال",
|
||||
"optional.fields.skip.button": "التخطي مؤقتا",
|
||||
"optional.fields.next.button": "Next",
|
||||
"continue.to.platform": "المواصلة إلى {platformName}",
|
||||
"modal.title": "شكرا لإعلامنا.",
|
||||
"modal.description": "إن غيرت رأيك، قيمكنك إكمال ملفك الشخصي ضمن الإعدادات في أي وقت.",
|
||||
"welcome.page.error.heading": "لم نتمكن من تحديث ملفك الشخصي",
|
||||
"welcome.page.error.message": "حدث خطأ ما. يمكنك إكمال ملفك الشخصي ضمن الإعدادات في أي وقت.",
|
||||
"recommendation.page.title": "Recommendations| {siteName}",
|
||||
"recommendation.page.heading": "We have a few recommendations to get you started.",
|
||||
"recommendation.skip.button": "Skip for now",
|
||||
"register.page.title": "التسجيل | {siteName}",
|
||||
"registration.fullname.label": "الاسم الكامل",
|
||||
"registration.email.label": "البريد الإلكتروني",
|
||||
"registration.username.label": "اسم المستخدم العامّ",
|
||||
"registration.password.label": "كلمة المرور",
|
||||
"registration.country.label": "البلد / المنطقة",
|
||||
"registration.opt.in.label": "أوافق على تلقّي رسائل تسويقية من {siteName}.",
|
||||
"help.text.name": "سيتم استخدام هذا الاسم في أي شهادات تحصل عليها.",
|
||||
"help.text.username.1": "الاسم الذي ستُعرَف به في مساقاتك.",
|
||||
"help.text.username.2": "لا يمكن تغيير هذا لاحقًا.",
|
||||
"help.text.email": "لتفعيل الحساب و التحديثات الهامة",
|
||||
"create.account.for.free.button": "إنشاء حساب مجانا",
|
||||
"create.an.account.btn.pending.state": "التحميل جارٍ",
|
||||
"registration.other.options.heading": "أو سجل باستخدام:",
|
||||
"register.institution.login.button": "بيانات المؤسسة / الجامعة",
|
||||
"register.institution.login.page.title": "التسجيل باستخدام بيانات المؤسسة / الجامعة",
|
||||
"empty.name.field.error": "أدخل اسمك الكامل",
|
||||
"empty.email.field.error": "أدخل بريدك الإلكتروني",
|
||||
"email.do.not.match": "عناوين البريد الإلكتروني غير متطابقة.",
|
||||
"empty.username.field.error": "يجب أن يتكون اسم المستخدم من 2 إلى 30 حرفًا",
|
||||
"empty.password.field.error": "لم يتم استيفاء معايير كلمة المرور",
|
||||
"empty.country.field.error": "حدد بلدك أو منطقة إقامتك",
|
||||
"email.invalid.format.error": "أدخل بريدا إلكترونيا صحيحا",
|
||||
"email.ratelimit.less.chars.validation.message": "يجب أن يتكون البريد الإلكتروني من 3 أحرف على الأقل.",
|
||||
"username.validation.message": "يجب أن يتكون اسم المستخدم من 2 إلى 30 حرفًا",
|
||||
"name.validation.message": "أدخل اسمًا صحيحا",
|
||||
"username.format.validation.message": "يمكن أن تحتوي أسماء المستخدمين فقط على أحرف (A-Z، a-z)، و أرقام (0-9)، و أسطر سفلية (_)، و واصلات (-). لا يمكن أن تحتوي أسماء المستخدمين على مسافات",
|
||||
"support.education.research": "دعم الأبحاث التربوية من خلال توفير معلومات إضافية. (اختياري)",
|
||||
"registration.request.failure.header": "لم نتمكّن من إنشاء حسابك.",
|
||||
"registration.empty.form.submission.error": "رجاءً تحقّق من أجوبتك و حاول مجددا.",
|
||||
"registration.request.server.error": "حدث خطأ ما. جرب تحديث الصفحة أو تحقق من اتصالك بالإنترنت.",
|
||||
"registration.rate.limit.error": "كثرت محاولات التسجيل الفاشلة. أعد المحاولة لاحقًا.",
|
||||
"registration.tpa.session.expired": "نفد وقت التسجيل باستخدام {provider}.",
|
||||
"terms.of.service.and.honor.code": "شروط الخدمة وميثاق الشرف الأكاديمي",
|
||||
"privacy.policy": "سياسة الخصوصية",
|
||||
"honor.code": "ميثاق الشرف الأكاديمي",
|
||||
"terms.of.service": "شروط الخدمة",
|
||||
"registration.year.of.birth.label": "سنة الميلاد (اختياري)",
|
||||
"registration.field.gender.options.label": "الجنس (اختياري)",
|
||||
"registration.goals.label": "أخبرنا عن سبب اهتمامك بـ edX (اختياري)",
|
||||
"registration.field.gender.options.f": "أنثى",
|
||||
"registration.field.gender.options.m": "ذكر",
|
||||
"registration.field.gender.options.o": "آخر / أفضل عدم التصريح",
|
||||
"registration.field.education.levels.label": "أعلى مستوى تعليمي مكتمل (اختياري)",
|
||||
"registration.field.education.levels.p": "دكتوراه",
|
||||
"registration.field.education.levels.m": "ماجستير / ماستر أو شهادة مهنيّة",
|
||||
"registration.field.education.levels.b": "بكالوريوس / ليسانس",
|
||||
"registration.field.education.levels.a": "درجة الزمالة / دبلوم الدراسات الجامعية",
|
||||
"registration.field.education.levels.hs": "الثانوية العامة / البكالوريا",
|
||||
"registration.field.education.levels.jhs": "المدرسة الإعدادية / المتوسطة",
|
||||
"registration.field.education.levels.el": "المدرسة الابتدائية / الأساسية",
|
||||
"registration.field.education.levels.none": "دون تعليم رسمي",
|
||||
"registration.field.education.levels.other": "نوع آخر من التعليم",
|
||||
"registration.username.suggestion.label": "مقترح:",
|
||||
"registration.using.tpa.form.heading": "إتمام إنشاء حسابك",
|
||||
"did.you.mean.alert.text": "هل تقصد",
|
||||
"register.page.terms.of.service": "أوافق على {termsOfService} الخاصة بـ{platformName} ",
|
||||
"sign.in": "تسجيل الدخول",
|
||||
"reset.password.page.title": "إعادة ضبط كلمة المرور | {siteName}",
|
||||
"reset.password": "إعادة ضبط كلمة المرور",
|
||||
"reset.password.page.instructions": "قم بإدخال و تأكيد كلمة مرورك.",
|
||||
"new.password.label": "كلمة المرور الجديدة",
|
||||
"confirm.password.label": "تأكيد كلمة المرور",
|
||||
"passwords.do.not.match": "كلمتا المرور غير متطابقتين",
|
||||
"confirm.your.password": "تأكيد كلمة مرورك",
|
||||
"forgot.password.confirmation.sign.in.link": "تسجيل الدخول",
|
||||
"reset.password.request.forgot.password.text": "نسيت كلمة المرور",
|
||||
"reset.password.request.invalid.token.header": "رابط إعادة ضبط كلمة المرور غير صالح",
|
||||
"reset.password.empty.new.password.field.error": "رجاءً أدخل كلمة مرورك الجديدة.",
|
||||
"reset.password.failure.heading": "لم نتمكن من إعادة ضبط كلمة مرورك.",
|
||||
"reset.password.form.submission.error": "رجاءً تحقق من أجوبتك وحاول مجددًا.",
|
||||
"reset.password.request.server.error": "فشلت إعادة ضبط كلمة المرور",
|
||||
"reset.password.token.validation.sever.error": "فشل التحقق من صحة الشارة",
|
||||
"reset.server.rate.limit.error": "طلبات أكثر مما ينبغي.",
|
||||
"reset.password.success.heading": "تمت إعادة ضبط كلمة المرور.",
|
||||
"reset.password.success": "تمت إعادة ضبط كلمة مرورك. سجل الدخول إلى حسابك.",
|
||||
"progressive.profiling.page.title": "الحقول الاختيارية | {siteName}",
|
||||
"progressive.profiling.page.heading": "بعض الأسئلة الموجهة لك ستساعدنا كي نزداد ذكاءً.",
|
||||
"gender.options.label": "الجنس (اختياري)",
|
||||
"gender.options.f": "أنثى",
|
||||
"gender.options.m": "ذكر",
|
||||
"gender.options.o": "آخر / أفضل عدم التصريح",
|
||||
"education.levels.label": "أعلى مستوى تعليمي مكتمل (اختياري)",
|
||||
"education.levels.p": "دكتوراه",
|
||||
"education.levels.m": "ماجستير / ماستر أو شهادة مهنيّة",
|
||||
"education.levels.b": "بكالوريوس / ليسانس",
|
||||
"education.levels.a": "درجة الزمالة / دبلوم الدراسات الجامعية",
|
||||
"education.levels.hs": "الثانوية العامة / البكالوريا",
|
||||
"education.levels.jhs": "المدرسة الإعدادية / المتوسطة",
|
||||
"education.levels.el": "المدرسة الابتدائية / الأساسية",
|
||||
"education.levels.none": "دون تعليم رسمي",
|
||||
"education.levels.other": "نوع آخر من التعليم",
|
||||
"year.of.birth.label": "سنة الميلاد (اختياري)",
|
||||
"optional.fields.information.link": "معرفة المزيد عن كيفية استخدامنا لهذه المعلومات.",
|
||||
"optional.fields.submit.button": "إرسال",
|
||||
"optional.fields.skip.button": "التخطي مؤقتا",
|
||||
"continue.to.platform": "المواصلة إلى {platformName}",
|
||||
"modal.title": "شكرا لإعلامنا.",
|
||||
"modal.description": "إن غيرت رأيك، قيمكنك إكمال ملفك الشخصي ضمن الإعدادات في أي وقت.",
|
||||
"welcome.page.error.heading": "لم نتمكن من تحديث ملفك الشخصي",
|
||||
"welcome.page.error.message": "حدث خطأ ما. يمكنك إكمال ملفك الشخصي ضمن الإعدادات في أي وقت."
|
||||
}
|
||||
163
src/i18n/messages/de_DE.json
Normal file
163
src/i18n/messages/de_DE.json
Normal file
@@ -0,0 +1,163 @@
|
||||
{
|
||||
"start.learning": "Beginne zu lernen",
|
||||
"with.site.name": "mit {siteName}",
|
||||
"complete.your.profile.1": "Vervollständige",
|
||||
"complete.your.profile.2": "dein Profil",
|
||||
"welcome.to.platform": "Willkommen bei {siteName}, {username}!",
|
||||
"institution.login.page.sub.heading": "Wählen Sie Ihre Institution aus der folgenden Liste aus",
|
||||
"logistration.sign.in": "Anmelden",
|
||||
"logistration.register": "Registrieren",
|
||||
"enterprisetpa.title.heading": "Möchten Sie sich mit Ihren {providerName}-Anmeldedaten anmelden?",
|
||||
"enterprisetpa.login.button.text": "Andere Möglichkeiten für die Anmeldung oder Registrierung",
|
||||
"sso.sign.in.with": "Melden Sie sich mit {providerName} an",
|
||||
"sso.create.account.using": "Erstellen Sie ein Konto mit {providerName}",
|
||||
"show.password": "Passwort anzeigen",
|
||||
"hide.password": "Passwort verbergen",
|
||||
"one.letter": "1 Buchstabe",
|
||||
"one.number": "1 Nummer",
|
||||
"eight.characters": "8 Charaktere",
|
||||
"password.sr.only.helping.text": "Das Passwort muss mindestens 8 Zeichen, mindestens einen Buchstaben und mindestens eine Zahl enthalten",
|
||||
"tpa.alert.heading": "Fast fertig!",
|
||||
"login.third.party.auth.account.not.linked": "Sie haben sich erfolgreich bei {currentProvider} angemeldet, aber Ihr {currentProvider}-Konto hat kein verknüpftes {platformName}-Konto. Um Ihre Konten zu verknüpfen, melden Sie sich jetzt mit Ihrem {platformName}-Passwort an.",
|
||||
"register.third.party.auth.account.not.linked": "Sie haben sich erfolgreich bei {currentProvider} angemeldet! Wir brauchen nur ein paar mehr Informationen, bevor Sie anfangen, mit {platformName} zu lernen.",
|
||||
"registration.using.tpa.form.heading": "Beenden Sie die Erstellung Ihres Kontos",
|
||||
"error.notfound.message": "Die gesuchte Seite ist nicht verfügbar oder es liegt ein Fehler in der URL vor. Bitte überprüfen Sie die URL und versuchen Sie es erneut.",
|
||||
"forgot.password.confirmation.message": "Wir haben eine E-Mail mit Anweisungen zum Zurücksetzen Ihres Passworts an {email} gesendet. Wenn Sie nach 1 Minute keine Nachricht zum Zurücksetzen des Passworts erhalten, überprüfen Sie, ob Sie die richtige E-Mail-Adresse eingegeben haben, oder überprüfen Sie Ihren Spam-Ordner. Wenn Sie weitere Hilfe benötigen, {supportLink}.",
|
||||
"forgot.password.page.title": "Passwort vergessen | {siteName}",
|
||||
"forgot.password.page.heading": "Passwort zurücksetzen",
|
||||
"forgot.password.page.instructions": "Bitte geben Sie unten Ihre E-Mail-Adresse ein und wir senden Ihnen eine E-Mail mit Anweisungen zum Zurücksetzen Ihres Passworts.",
|
||||
"forgot.password.page.invalid.email.message": "Geben sie eine gültige E-Mail-Adresse an",
|
||||
"forgot.password.page.email.field.label": "E-Mail Adresse",
|
||||
"forgot.password.page.submit.button": "Einreichen",
|
||||
"forgot.password.error.alert.title.": "Wir konnten Sie nicht kontaktieren.",
|
||||
"forgot.password.error.message.title": "Ein Fehler ist aufgetreten.",
|
||||
"forgot.password.request.in.progress.message": "Ihre vorherige Anfrage ist in Bearbeitung, bitte versuchen Sie es in wenigen Augenblicken erneut.",
|
||||
"forgot.password.empty.email.field.error": "Geben sie ihre E-Mail Adresse ein",
|
||||
"forgot.password.email.help.text": "Die E-Mail-Adresse, mit der Sie sich bei {platformName} registriert haben",
|
||||
"confirmation.message.title": "Prüfen Sie Ihr E-Mail-Postfach",
|
||||
"confirmation.support.link": "wenden Sie sich an den technischen Support",
|
||||
"need.help.sign.in.text": "Brauchen Sie Hilfe bei der Anmeldung?",
|
||||
"additional.help.text": "Wenden Sie sich für weitere Hilfe an den {platformName}-Support unter",
|
||||
"sign.in.text": "Anmelden",
|
||||
"extend.field.errors": "{emailError} unten.",
|
||||
"invalid.token.heading": "Ungültiger Link zum Zurücksetzen des Passworts",
|
||||
"invalid.token.error.message": "Dieser Link zum Zurücksetzen des Passwortes ist ungültig. Möglicherweise wurde es bereits verwendet. Geben Sie unten Ihre E-Mail-Adresse ein, um einen neuen Link zu erhalten.",
|
||||
"token.validation.rate.limit.error.heading": "Zu viele Anfragen",
|
||||
"token.validation.rate.limit.error": "Aufgrund von zu vieler Anfragen ist ein Fehler aufgetreten. Bitte versuchen Sie es nach einiger Zeit erneut.",
|
||||
"token.validation.internal.sever.error.heading": "Token-Validierungsfehler",
|
||||
"token.validation.internal.sever.error": "Ein Fehler ist aufgetreten. Versuchen Sie, die Seite zu aktualisieren, oder überprüfen Sie Ihre Internetverbindung.",
|
||||
"internal.server.error": "Ein Fehler ist aufgetreten. Versuchen Sie, die Seite zu aktualisieren, oder überprüfen Sie Ihre Internetverbindung.",
|
||||
"account.activation.error.message": "Etwas ist schief gelaufen, bitte {supportLink} um dieses Problem zu lösen.",
|
||||
"login.inactive.user.error": "Um sich anzumelden, müssen Sie Ihr Konto aktivieren.{lineBreak} {lineBreak}Wir haben gerade einen Aktivierungslink an {email} gesendet. Wenn Sie keine E-Mail erhalten, überprüfen Sie Ihre Spam-Ordner oder {supportLink}.",
|
||||
"allowed.domain.login.error": "Als {allowedDomain}-Benutzer müssen Sie sich mit Ihrem {allowedDomain} {tpaLink} anmelden.",
|
||||
"login.incorrect.credentials.error.attempts.text.1": "Der eingegebene Benutzername, die E-Mail oder das Passwort ist falsch. Sie haben {remainingAttempts} weitere Anmeldeversuche, bevor Ihr Konto vorübergehend gesperrt wird.",
|
||||
"login.incorrect.credentials.error.attempts.text.2": "Wenn Sie Ihr Passwort vergessen haben, {resetLink}",
|
||||
"account.locked.out.message.2": "Um auf der sicheren Seite zu sein, können Sie {resetLink} tun, bevor Sie es erneut versuchen.",
|
||||
"login.incorrect.credentials.error.with.reset.link": "Der eingegebene Benutzername, die E-Mail-Adresse oder das Passwort ist falsch. Bitte versuchen Sie es erneut oder {resetLink}.",
|
||||
"login.page.title": "Anmelden | {siteName}",
|
||||
"login.user.identity.label": "Benutzername oder E-Mail-Adresse",
|
||||
"login.password.label": "Passwort",
|
||||
"sign.in.button": "Anmelden",
|
||||
"forgot.password": "Passwort vergessen",
|
||||
"institution.login.button": "Zeugnisse der Institution/des Campus",
|
||||
"institution.login.page.title": "Melden Sie sich mit Institutions-/Campus-Anmeldeinformationen an",
|
||||
"login.other.options.heading": "Oder melden Sie sich an mit:",
|
||||
"non.compliant.password.title": "Wir haben kürzlich unsere Passwortanforderungen geändert",
|
||||
"non.compliant.password.message": "Ihr aktuelles Passwort entspricht nicht den neuen Sicherheitsanforderungen. Wir haben gerade eine Nachricht zum Zurücksetzen des Passworts an die mit diesem Konto verknüpfte E-Mail-Adresse gesendet. Vielen Dank, dass Sie uns helfen, Ihre Daten zu schützen.",
|
||||
"account.locked.out.message.1": "Um Ihr Konto zu schützen, wurde es vorübergehend gesperrt. Versuchen Sie es in 30 Minuten erneut.",
|
||||
"enterprise.login.btn.text": "Arbeits- oder Schulzeugnisse",
|
||||
"username.or.email.format.validation.less.chars.message": "Benutzername oder E-Mail müssen mindestens 3 Zeichen lang sein.",
|
||||
"email.validation.message": "Geben Sie Ihren Benutzernamen oder Ihre E-Mail-Adresse ein",
|
||||
"password.validation.message": "Die Passwortkriterien wurden nicht erfüllt",
|
||||
"account.activation.success.message.title": "Super! Sie haben Ihr Konto aktiviert.",
|
||||
"account.activation.success.message": "Sie erhalten jetzt E-Mail-Updates und Benachrichtigungen von uns in Bezug auf die Kurse, für die Sie eingeschrieben sind. Melden Sie sich an, um fortzufahren.",
|
||||
"account.activation.info.message": "Dieses Konto wurde bereits aktiviert.",
|
||||
"account.activation.error.message.title": "Ihr Konto konnte nicht aktiviert werden",
|
||||
"account.activation.support.link": "kontaktieren Sie den Support",
|
||||
"account.confirmation.success.message.title": "Super! Sie haben Ihre E-Mail bestätigt.",
|
||||
"account.confirmation.success.message": "Melden Sie sich an, um fortzufahren.",
|
||||
"account.confirmation.info.message": "Diese E-Mail-Adresse wurde bereits bestätigt.",
|
||||
"account.confirmation.error.message.title": "Ihre E-Mail-Adresse konnte nicht bestätigt werden",
|
||||
"tpa.account.link": "{provider}-Konto",
|
||||
"internal.server.error.message": "Ein Fehler ist aufgetreten. Versuchen Sie, die Seite zu aktualisieren, oder überprüfen Sie Ihre Internetverbindung.",
|
||||
"login.rate.limit.reached.message": "Zu viele fehlgeschlagene Anmeldeversuche. Bitte versuche es später noch einmal.",
|
||||
"login.failure.header.title": "Wir konnten Sie leider nicht einloggen.",
|
||||
"contact.support.link": "Wenden Sie sich an den Support der {platformName}",
|
||||
"login.incorrect.credentials.error": "Der eingegebene Benutzername, die E-Mail-Adresse oder das Passwort ist falsch. Bitte versuche es erneut.",
|
||||
"login.form.invalid.error.message": "Bitte füllen Sie die unten stehenden Felder aus.",
|
||||
"login.incorrect.credentials.error.reset.link.text": "Setzen Sie Ihr Passwort zurück",
|
||||
"login.incorrect.credentials.error.before.account.blocked.text": "Klicken Sie hier, um es zurückzusetzen.",
|
||||
"password.security.nudge.title": "Passwortsicherheit",
|
||||
"password.security.block.title": "Passwortänderung erforderlich",
|
||||
"password.security.nudge.body": "Unser System hat festgestellt, dass Ihr Passwort angreifbar ist. Wir empfehlen Ihnen, es zu ändern, damit Ihr Konto sicher bleibt.",
|
||||
"password.security.block.body": "Unser System hat festgestellt, dass Ihr Passwort angreifbar ist. Ändern Sie Ihr Passwort, damit Ihr Konto sicher bleibt.",
|
||||
"password.security.close.button": "Schließen",
|
||||
"password.security.redirect.to.reset.password.button": "Setzen Sie Ihr Passwort zurück",
|
||||
"progressive.profiling.page.title": "Optionale Felder | {siteName}",
|
||||
"progressive.profiling.page.heading": "Ein paar Fragen an Sie helfen uns, schlauer zu werden.",
|
||||
"optional.fields.information.link": "Erfahren Sie mehr darüber, wie wir diese Informationen verwenden.",
|
||||
"optional.fields.submit.button": "Einreichen",
|
||||
"optional.fields.skip.button": "Überspringen",
|
||||
"optional.fields.next.button": "Next",
|
||||
"continue.to.platform": "Weiter zu {platformName}",
|
||||
"modal.title": "Danke, dass Sie uns das mitteilen.",
|
||||
"modal.description": "Sie können Ihr Profil jederzeit in den Einstellungen vervollständigen, wenn Sie Ihre Meinung ändern.",
|
||||
"welcome.page.error.heading": "Wir konnten Ihr Profil nicht aktualisieren",
|
||||
"welcome.page.error.message": "Ein Fehler ist aufgetreten. Sie können Ihr Profil jederzeit in den Einstellungen vervollständigen.",
|
||||
"recommendation.page.title": "Recommendations| {siteName}",
|
||||
"recommendation.page.heading": "We have a few recommendations to get you started.",
|
||||
"recommendation.skip.button": "Skip for now",
|
||||
"register.page.title": "Registrieren | {siteName}",
|
||||
"registration.fullname.label": "Vollständiger Name",
|
||||
"registration.email.label": "E-Mail-Adresse",
|
||||
"registration.username.label": "Öffentlicher Benutzername",
|
||||
"registration.password.label": "Passwort",
|
||||
"registration.country.label": "Land/Region",
|
||||
"registration.opt.in.label": "Ich stimme zu, dass {siteName} mir Marketingmitteilungen senden darf.",
|
||||
"help.text.name": "Dieser Name wird von allen Zertifikaten verwendet, die Sie erwerben.",
|
||||
"help.text.username.1": "Der Name, der Sie in Ihren Kursen identifiziert.",
|
||||
"help.text.username.2": "Dies kann später nicht mehr geändert werden.",
|
||||
"help.text.email": "Für die Kontoaktivierung und wichtige Updates",
|
||||
"create.account.for.free.button": "Erstellen Sie kostenlos ein Benutzerkonto",
|
||||
"registration.other.options.heading": "Oder registrieren Sie sich bei:",
|
||||
"register.institution.login.button": "Zeugnisse der Institution/des Campus",
|
||||
"register.institution.login.page.title": "Registrieren Sie sich mit Institutions-/Campus-Anmeldeinformationen",
|
||||
"empty.name.field.error": "Geben Sie Ihren vollständigen Namen ein",
|
||||
"empty.email.field.error": "Geben Sie Ihre E-Mail-Adresse ein",
|
||||
"empty.username.field.error": "Der Benutzername muss zwischen 2 und 30 Zeichen lang sein",
|
||||
"empty.password.field.error": "Kennwortkriterien wurden nicht erfüllt",
|
||||
"empty.country.field.error": "Wählen Sie das Land oder die Region Ihres Wohnsitzes aus",
|
||||
"email.do.not.match": "Die E-Mail-Adressen stimmen nicht überein.",
|
||||
"email.invalid.format.error": "Geben sie eine gültige E-Mail-Adresse an",
|
||||
"username.validation.message": "Der Benutzername muss zwischen 2 und 30 Zeichen lang sein",
|
||||
"name.validation.message": "Geben Sie einen gültigen Namen ein",
|
||||
"username.format.validation.message": "Benutzernamen dürfen nur Buchstaben (AZ, az), Ziffern (0-9), Unterstriche (_) und Bindestriche (-) enthalten. Benutzernamen dürfen keine Leerzeichen enthalten",
|
||||
"registration.request.failure.header": "Wir konnten Ihr Konto leider nicht erstellen.",
|
||||
"registration.empty.form.submission.error": "Bitte überprüfen Sie Ihre Antworten und versuchen Sie es erneut.",
|
||||
"registration.request.server.error": "Ein Fehler ist aufgetreten. Versuchen Sie, die Seite zu aktualisieren, oder überprüfen Sie Ihre Internetverbindung.",
|
||||
"registration.rate.limit.error": "Zu viele fehlgeschlagene Registrierungsversuche. Versuchen Sie es später noch einmal.",
|
||||
"registration.tpa.session.expired": "Die Registrierung mit {provider} ist abgelaufen.",
|
||||
"terms.of.service.and.honor.code": "Nutzungsbedingungen und Verhaltenskodex",
|
||||
"privacy.policy": "Datenschutzbestimmungen",
|
||||
"honor.code": "Verhaltenskodex",
|
||||
"terms.of.service": "Nutzungsbedingungen",
|
||||
"registration.username.suggestion.label": "Empfohlen:",
|
||||
"did.you.mean.alert.text": "Meinten Sie",
|
||||
"register.page.terms.of.service.and.honor.code": "Wenn Sie ein Konto erstellen, stimmen Sie den {tosAndHonorCode} zu und erkennen an, dass {platformName} und jedes \nMitglied Ihre personenbezogenen Daten in Übereinstimmung mit den {privacyPolicy} verarbeitet.",
|
||||
"register.page.honor.code": "Ich stimme den {platformName} {tosAndHonorCode} zu",
|
||||
"register.page.terms.of.service": "Ich stimme den {platformName} {termsOfService} zu",
|
||||
"sign.in": "Anmelden",
|
||||
"reset.password.page.title": "Passwort zurücksetzen | {siteName}",
|
||||
"reset.password": "Passwort zurücksetzen",
|
||||
"reset.password.page.instructions": "Neues Passwort eingeben und bestätigen",
|
||||
"new.password.label": "Neues Passwort",
|
||||
"confirm.password.label": "Kennwort bestätigen",
|
||||
"passwords.do.not.match": "Passwörter stimmen nicht überein",
|
||||
"confirm.your.password": "Bestätigen Sie Ihr Passwort",
|
||||
"reset.password.failure.heading": "Wir konnten Ihr Passwort nicht zurücksetzen.",
|
||||
"reset.password.form.submission.error": "Bitte überprüfen Sie Ihre Antworten und versuchen Sie es erneut.",
|
||||
"reset.server.rate.limit.error": "Zu viele Anfragen.",
|
||||
"reset.password.success.heading": "Zurücksetzen des Passworts abgeschlossen.",
|
||||
"reset.password.success": "Ihr Passwort wurde zurückgesetzt. Melden Sie sich bei Ihrem Konto an.",
|
||||
"rate.limit.error": "Aufgrund zu vieler Anfragen ist ein Fehler aufgetreten. Bitte versuchen Sie es nach einiger Zeit erneut."
|
||||
}
|
||||
@@ -19,9 +19,9 @@
|
||||
"sso.create.account.using": "Crear una cuenta con {providerName}",
|
||||
"show.password": "Mostrar contraseña",
|
||||
"hide.password": "Ocultar contraseña",
|
||||
"one.letter": "1 Letra",
|
||||
"one.number": "1 Número ",
|
||||
"eight.characters": "8 Caracteres ",
|
||||
"one.letter": "1 letra",
|
||||
"one.number": "1 número",
|
||||
"eight.characters": "8 caracteres",
|
||||
"password.sr.only.helping.text": "La contraseña debe contener al menos 8 caracteres, al menos una letra y al menos un número",
|
||||
"tpa.alert.heading": "¡Ya casi has terminado!",
|
||||
"login.third.party.auth.account.not.linked": "Te has registrado correctamente en {currentProvider}, pero tu cuenta de {currentProvider} no tiene una cuenta de {platformName} asociada. Para asociar tus cuentas, inicia sesión ahora usando tu contraseña de {platformName}.",
|
||||
@@ -38,13 +38,12 @@
|
||||
"forgot.password.error.message.title": "Ha ocurrido un error.",
|
||||
"forgot.password.request.in.progress.message": "Su solicitud anterior está en progreso, por favor inténtalo de nuevo en unos minutos.",
|
||||
"forgot.password.empty.email.field.error": "Introduce tu email",
|
||||
"forgot.password.invalid.email": "Ha ocurrido un error.",
|
||||
"forgot.password.invalid.email.message": "La dirección de correo que has ingresado no está en el formato correcto.",
|
||||
"forgot.password.email.help.text": "El correo electrónico que utilizaste para registrarte en {platformName}",
|
||||
"confirmation.message.title": "Verifica tu correo electrónico",
|
||||
"confirmation.support.link": "entra en contacto con el equipo de soporte técnico",
|
||||
"need.help.sign.in.text": "¿Necesitas ayuda para iniciar sesión?",
|
||||
"additional.help.text": "Para obtener ayuda, pónte en contacto con el servicio de soporte de edX en ",
|
||||
"additional.help.text": "Para obtener ayuda adicional, comuníquese con el soporte de {platformName} en",
|
||||
"sign.in.text": "Iniciar sesión",
|
||||
"extend.field.errors": "{emailError} a continuación.",
|
||||
"invalid.token.heading": "Enlace de restablecimiento de contraseña inválido",
|
||||
@@ -57,6 +56,7 @@
|
||||
"rate.limit.error": "Se ha producido un error debido a demasiadas solicitudes. Por favor, inténtalo de nuevo después de algún tiempo.",
|
||||
"account.activation.error.message": "Algo no funcionó correctamente, por favor {supportLink} para resolver este problema.",
|
||||
"login.inactive.user.error": "Para iniciar sesión, debes activar tu cuenta..{lineBreak}\n {lineBreak} Acabamos de enviar un enlace de activación a {email}. Si no recibes un correo electrónico,\n revisa tus carpetas de spam o {supportLink}.",
|
||||
"allowed.domain.login.error": "Como usuario {allowedDomain}, debe iniciar sesión con su {allowedDomain} {tpaLink}.",
|
||||
"login.incorrect.credentials.error.attempts.text.1": "El nombre de usuario, el email o la contraseña que has introducido son incorrectos. Tienes {remainingAttempts} intentos más de inicio de sesión\n antes de que tu cuenta se bloquee temporalmente.",
|
||||
"login.incorrect.credentials.error.attempts.text.2": "Si has olvidado tu contraseña, {resetLink}",
|
||||
"account.locked.out.message.2": "Para estar seguro, puedes {resetLink} antes de volver a intentarlo.",
|
||||
@@ -90,9 +90,14 @@
|
||||
"sign.in.heading": "Iniciar sesión",
|
||||
"account.activation.success.message.title": "Ha sido un éxito. Has activado tu cuenta.",
|
||||
"account.activation.success.message": "Ahora recibirás por correo electrónico actualizaciones y alertas relacionadas con los cursos en los que estás inscrito. Inicia sesión para continuar.",
|
||||
"account.already.activated.message": "La cuenta ya ha sido activada.",
|
||||
"account.activation.info.message": "La cuenta ya ha sido activada.",
|
||||
"account.activation.error.message.title": "Tu cuenta no ha podido ser activada",
|
||||
"account.activation.support.link": "contacta al equipo de soporte de edX",
|
||||
"tpa.account.link": "{provider} cuenta",
|
||||
"account.confirmation.success.message.title": "¡Éxito! Has confirmado tu correo electrónico.",
|
||||
"account.confirmation.success.message": "Inicia sesión para continuar.",
|
||||
"account.confirmation.info.message": "Este correo electrónico ya ha sido confirmado.",
|
||||
"account.confirmation.error.message.title": "Tu correo electrónico no pudo ser confirmado",
|
||||
"login.rate.limit.reached.message": "Demasiados intentos fallidos de inicio de sesión. Inténtelo de nuevo más tarde.",
|
||||
"login.failure.header.title": "No se ha podido iniciar tu sesión.",
|
||||
"contact.support.link": "entrar en contacto con el soporte de {platformName}",
|
||||
@@ -102,28 +107,53 @@
|
||||
"login.form.invalid.error.message": "Por favor, complete los siguientes campos.",
|
||||
"login.incorrect.credentials.error.reset.link.text": "restablecer la contraseña",
|
||||
"login.incorrect.credentials.error.before.account.blocked.text": "Pulse aquí para restablecerla.",
|
||||
"password.security.nudge.title": "Seguridad de contraseña",
|
||||
"password.security.block.title": "Cambio de contraseña requerido",
|
||||
"password.security.nudge.body": "Nuestro sistema detectó que su contraseña es vulnerable. Le recomendamos que lo cambie para que su cuenta se mantenga segura.",
|
||||
"password.security.block.body": "Nuestro sistema detectó que su contraseña es vulnerable. Cambie su contraseña para que su cuenta permanezca segura.",
|
||||
"password.security.close.button": "Cerrar",
|
||||
"password.security.redirect.to.reset.password.button": "Restablece tu contraseña",
|
||||
"progressive.profiling.page.title": "Campos opcionales | {siteName}",
|
||||
"progressive.profiling.page.heading": "Unas cuantas preguntas para ti nos ayudarán a mejorar.",
|
||||
"optional.fields.information.link": "Aprende más sobre cómo usamos esta información.",
|
||||
"optional.fields.submit.button": "Enviar",
|
||||
"optional.fields.skip.button": "Saltar por ahora ",
|
||||
"optional.fields.next.button": "Next",
|
||||
"continue.to.platform": "Continuar a {platformName}",
|
||||
"modal.title": "Gracias por informarnos.",
|
||||
"modal.description": "Puedes completar tu perfil en los ajustes en cualquier momento si cambias de opinión.",
|
||||
"welcome.page.error.heading": "No hemos podido actualizar tu perfil",
|
||||
"welcome.page.error.message": "Se ha producido un error. Puedes completar tu perfil en los ajustes en cualquier momento.",
|
||||
"recommendation.page.title": "Recommendations| {siteName}",
|
||||
"recommendation.page.heading": "We have a few recommendations to get you started.",
|
||||
"recommendation.skip.button": "Skip for now",
|
||||
"register.page.title": "Register | {siteName}",
|
||||
"registration.fullname.label": "Nombre completo",
|
||||
"registration.email.label": "Correo electrónico",
|
||||
"registration.username.label": "Nombre de usuario público",
|
||||
"registration.password.label": "Contraseña",
|
||||
"registration.country.label": "País/Región",
|
||||
"registration.opt.in.label": "Acepto que {siteName} pueda enviarme mensajes de marketing.",
|
||||
"help.text.name": "Este nombre será utilizado por los certificados que obtengas.",
|
||||
"help.text.username.1": "El nombre que te identificará en tus cursos.",
|
||||
"help.text.username.2": "Esto no puede modificarse posteriormente.",
|
||||
"help.text.email": "Para la activación de la cuenta y las actualizaciones importantes",
|
||||
"create.account.button": "Crear una cuenta",
|
||||
"create.account.for.free.button": "Crea una cuenta gratis",
|
||||
"create.an.account.btn.pending.state": "Cargando",
|
||||
"registration.other.options.heading": "O regístrese con:",
|
||||
"register.institution.login.button": "Credenciales de la institución/campus",
|
||||
"register.institution.login.page.title": "Registro con credenciales de la institución/campus",
|
||||
"empty.name.field.error": "Introduce tu nombre completo",
|
||||
"empty.email.field.error": "Introduce tu email",
|
||||
"email.do.not.match": "Los correos electrónicos no son iguales.",
|
||||
"empty.username.field.error": "El nombre de usuario debe tener entre 2 y 30 caracteres",
|
||||
"empty.password.field.error": "No se han cumplido los criterios de la contraseña",
|
||||
"empty.country.field.error": "Selecciona tu país o región de residencia",
|
||||
"email.invalid.format.error": "Introduce una dirección de correo electrónico válida",
|
||||
"email.ratelimit.less.chars.validation.message": "El correo electrónico debe tener 3 caracteres.",
|
||||
"username.validation.message": "El nombre de usuario debe tener entre 2 y 30 caracteres",
|
||||
"username.format.validation.message": "Los nombres de usuario únicamente pueden contener las letras (A-Z, a-z), números (0-9), guión bajo (_) y guiones (-).",
|
||||
"name.validation.message": "Introduce un nombre válido",
|
||||
"username.format.validation.message": "Los nombres de usuario solo pueden contener letras (A-Z, a-z), números (0-9), guiones bajos (_) y guiones (-). Los nombres de usuario no pueden contener espacios",
|
||||
"support.education.research": "Apoya la investigación sobre educación proporcionando información adicional. (Opcional)",
|
||||
"registration.request.failure.header": "No pudimos crear tu cuenta.",
|
||||
"registration.empty.form.submission.error": "Por favor, verifica tus respuestas y vuelve a intentarlo.",
|
||||
@@ -132,6 +162,8 @@
|
||||
"registration.tpa.session.expired": "Inscripción usando {provider} ha expirado.",
|
||||
"terms.of.service.and.honor.code": "Condiciones de servicio y código de honor",
|
||||
"privacy.policy": "Política de privacidad ",
|
||||
"honor.code": "Código de Honor",
|
||||
"terms.of.service": "Términos de servicio",
|
||||
"registration.year.of.birth.label": "Año de nacimiento (opcional)",
|
||||
"registration.field.gender.options.label": "Género (opcional)",
|
||||
"registration.goals.label": "Díganos por qué estás interesado en edX (opcional)",
|
||||
@@ -148,10 +180,10 @@
|
||||
"registration.field.education.levels.el": "Enseñanza primaria",
|
||||
"registration.field.education.levels.none": "Ninguna educación formal",
|
||||
"registration.field.education.levels.other": "Otra educación",
|
||||
"registration.username.suggestion.label": "Disponible:",
|
||||
"registration.username.suggestion.label": "Se recomienda:",
|
||||
"registration.using.tpa.form.heading": "Termina de crear tu cuenta",
|
||||
"did.you.mean.alert.text": "¿Quieres decir",
|
||||
"register.page.terms.of.service.and.honor.code": "Al crear una cuenta, aceptas el {tosAndHonorCode} y reconoces que {platformName} y cada\n Miembro procesa tus datos personales de acuerdo con la {privacyPolicy}.",
|
||||
"register.page.terms.of.service": "Acepto lo siguiente: {platformName} {termsOfService}",
|
||||
"sign.in": "Iniciar sesión",
|
||||
"reset.password.page.title": "Restablecer contraseña | {siteName}",
|
||||
"reset.password": "Restablecer mi contraseña",
|
||||
|
||||
@@ -1,199 +1,231 @@
|
||||
{
|
||||
"start.learning": "Start learning",
|
||||
"with.site.name": "with {siteName}",
|
||||
"complete.your.profile.1": "Complete",
|
||||
"complete.your.profile.2": "your profile",
|
||||
"welcome.to.platform": "Welcome to {siteName}, {username}!",
|
||||
"institution.login.page.sub.heading": "Choose your institution from the list below",
|
||||
"forgot.password.confirmation.title": "Check your email",
|
||||
"forgot.password.confirmation.support.link": "contact technical support",
|
||||
"forgot.password.confirmation.info": "If you do not receive a password reset message after 1 minute, verify that you entered the correct email address, or check your spam folder.",
|
||||
"logistration.sign.in": "Sign in",
|
||||
"logistration.register": "Register",
|
||||
"internal.server.error.message": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"server.ratelimit.error.message": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"enterprisetpa.title.heading": "Would you like to sign in using your {providerName} credentials?",
|
||||
"enterprisetpa.sso.button.title": "Sign in using {providerName}",
|
||||
"enterprisetpa.login.button.text": "Show me other ways to sign in or register",
|
||||
"sso.sign.in.with": "Sign in with {providerName}",
|
||||
"sso.create.account.using": "Create account using {providerName}",
|
||||
"show.password": "Show password",
|
||||
"hide.password": "Hide password",
|
||||
"one.letter": "1 Letter",
|
||||
"one.number": "1 Number",
|
||||
"eight.characters": "8 Characters",
|
||||
"password.sr.only.helping.text": "Password must contain at least 8 characters, at least one letter, and at least one number",
|
||||
"tpa.alert.heading": "Almost done!",
|
||||
"login.third.party.auth.account.not.linked": "You have successfully signed into {currentProvider}, but your {currentProvider} account does not have a linked {platformName} account. To link your accounts, sign in now using your {platformName} password.",
|
||||
"register.third.party.auth.account.not.linked": "You've successfully signed into {currentProvider}! We just need a little more information before you start learning with {platformName}.",
|
||||
"error.notfound.message": "The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again.",
|
||||
"forgot.password.confirmation.message": "We sent an email to {email} with instructions to reset your password.\n If you do not receive a password reset message after 1 minute, verify that you entered\n the correct email address, or check your spam folder. If you need further assistance, {supportLink}.",
|
||||
"forgot.password.page.title": "Forgot Password | {siteName}",
|
||||
"forgot.password.page.heading": "Reset password",
|
||||
"forgot.password.page.instructions": "Please enter your email address below and we will send you an email with instructions on how to reset your password.",
|
||||
"start.learning": "Démarrer l'apprentissage",
|
||||
"with.site.name": "avec {siteName}",
|
||||
"complete.your.profile.1": "Terminé",
|
||||
"complete.your.profile.2": "votre profil",
|
||||
"welcome.to.platform": "Bienvenue sur {siteName}, {username}!",
|
||||
"institution.login.page.sub.heading": "Sélectionner votre institution dans la liste ci-dessous",
|
||||
"forgot.password.confirmation.title": "Vérifiez votre email",
|
||||
"forgot.password.confirmation.support.link": "contacter le support technique",
|
||||
"forgot.password.confirmation.info": "Si vous ne recevez pas de message de réinitialisation de mot de passe après 1 minute, vérifiez que vous avez entré la bonne adresse courriel ou vérifiez votre dossier de pourriels.",
|
||||
"logistration.sign.in": "Connectez-vous",
|
||||
"logistration.register": "S'inscrire",
|
||||
"internal.server.error.message": "Une erreur est survenue. Essayer de rafraîchir la page, ou vérifier votre connexion Internet.",
|
||||
"server.ratelimit.error.message": "Une erreur s'est produite en raison d'un trop grand nombre de demandes. Veuillez réessayer après un certain temps.",
|
||||
"enterprisetpa.title.heading": "Souhaitez-vous vous connecter à l'aide de vos identifiants {providerName} ?",
|
||||
"enterprisetpa.sso.button.title": "Connectez-vous avec {providerName}",
|
||||
"enterprisetpa.login.button.text": "Montrez-moi d'autres méthodes pour me connecter ou m'inscrire",
|
||||
"sso.sign.in.with": "Connectez-vous avec {providerName}",
|
||||
"sso.create.account.using": "Créer un compte avec {providerName}",
|
||||
"show.password": "Afficher le mot de passe",
|
||||
"hide.password": "Cacher le mot de passe ",
|
||||
"one.letter": "1 letter",
|
||||
"one.number": "1 number",
|
||||
"eight.characters": "8 characters",
|
||||
"password.sr.only.helping.text": "Le mot de passe doit contenir au moins 8 caractères, au moins une lettre et au moins un chiffre",
|
||||
"tpa.alert.heading": "Presque fini !",
|
||||
"login.third.party.auth.account.not.linked": "Vous vous êtes connecté avec succès à {currentProvider}, mais votre compte {currentProvider} n'a pas de compte relié à {platformName}. Pour lier vos comptes, connectez-vous en utilisant votre mot de passe {platformName}.",
|
||||
"register.third.party.auth.account.not.linked": "Vous vous êtes connecté avec succès à {currentProvider} ! Nous avons juste besoin d'un peu plus d'informations avant que vous commenciez à apprendre avec {platformName}.",
|
||||
"error.notfound.message": "La page que vous recherchez n'est pas disponible ou il y a une erreur dans l'URL. Veuillez vérifier l'URL et réessayer.",
|
||||
"forgot.password.confirmation.message": "Nous avons envoyé un courriel à {email} avec des instructions pour réinitialiser votre mot de passe.\n Si vous ne recevez pas de message de réinitialisation de mot de passe après 1 minute, vérifiez que vous avez saisi\nl'adresse courriel correctement, ou vérifiez votre dossier de courriel indésirable. Si vous avez besoin d'aide supplémentaire, {supportLink}.",
|
||||
"forgot.password.page.title": " Mot de passe oublié | {siteName}",
|
||||
"forgot.password.page.heading": "Réinitialiser le mot de passe",
|
||||
"forgot.password.page.instructions": "Veuillez entrer votre adresse courriel ci-dessous et nous vous enverrons un courriel avec les instructions pour réinitialiser votre mot de passe.",
|
||||
"forgot.password.page.invalid.email.message": "Enter a valid email address",
|
||||
"forgot.password.page.email.field.label": "Email",
|
||||
"forgot.password.page.submit.button": "Submit",
|
||||
"forgot.password.error.alert.title.": "We were unable to contact you.",
|
||||
"forgot.password.error.message.title": "An error occurred.",
|
||||
"forgot.password.page.submit.button": "Envoyez",
|
||||
"forgot.password.error.alert.title.": "Nous n'avons pas pu vous contacter.",
|
||||
"forgot.password.error.message.title": "Une erreur est survenue.",
|
||||
"forgot.password.request.in.progress.message": "Your previous request is in progress, please try again in a few moments.",
|
||||
"forgot.password.empty.email.field.error": "Enter your email",
|
||||
"forgot.password.invalid.email": "An error occurred.",
|
||||
"forgot.password.invalid.email.message": "The email address you've provided isn't formatted correctly.",
|
||||
"forgot.password.email.help.text": "The email address you used to register with {platformName}",
|
||||
"confirmation.message.title": "Check your email",
|
||||
"confirmation.support.link": "contact technical support",
|
||||
"need.help.sign.in.text": "Need help signing in?",
|
||||
"additional.help.text": "For additional help, contact edX support at ",
|
||||
"sign.in.text": "Sign in",
|
||||
"extend.field.errors": "{emailError} below.",
|
||||
"invalid.token.heading": "Invalid password reset link",
|
||||
"invalid.token.error.message": "This password reset link is invalid. It may have been used already. Enter your email below to receive a new link.",
|
||||
"token.validation.rate.limit.error.heading": "Too many requests",
|
||||
"token.validation.rate.limit.error": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"token.validation.internal.sever.error.heading": "Token validation failure",
|
||||
"token.validation.internal.sever.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"internal.server.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"rate.limit.error": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"account.activation.error.message": "Something went wrong, please {supportLink} to resolve this issue.",
|
||||
"login.inactive.user.error": "In order to sign in, you need to activate your account.{lineBreak}\n {lineBreak}We just sent an activation link to {email}. If you do not receive an email,\n check your spam folders or {supportLink}.",
|
||||
"login.incorrect.credentials.error.attempts.text.1": "The username, email or password you entered is incorrect. You have {remainingAttempts} more sign in\n attempts before your account is temporarily locked.",
|
||||
"login.incorrect.credentials.error.attempts.text.2": "If you've forgotten your password, {resetLink}",
|
||||
"account.locked.out.message.2": "To be on the safe side, you can {resetLink} before trying again.",
|
||||
"login.incorrect.credentials.error.with.reset.link": "The username, email, or password you entered is incorrect. Please try again or {resetLink}.",
|
||||
"login.page.title": "Login | {siteName}",
|
||||
"login.user.identity.label": "Username or email",
|
||||
"login.password.label": "Password",
|
||||
"sign.in.button": "Sign in",
|
||||
"sign.in.btn.pending.state": "Loading",
|
||||
"need.help.signing.in.collapsible.menu": "Need help signing in?",
|
||||
"forgot.password.link": "Forgot my password",
|
||||
"forgot.password": "Forgot password",
|
||||
"other.sign.in.issues": "Other sign in issues",
|
||||
"need.other.help.signing.in.collapsible.menu": "Need other help signing in?",
|
||||
"institution.login.button": "Institution/campus credentials",
|
||||
"institution.login.page.title": "Sign in with institution/campus credentials",
|
||||
"institution.login.page.back.button": "Back to sign in",
|
||||
"create.an.account": "Create an account",
|
||||
"login.other.options.heading": "Or sign in with:",
|
||||
"non.compliant.password.title": "We recently changed our password requirements",
|
||||
"non.compliant.password.message": "Your current password does not meet the new security requirements. We just sent a password-reset message to the email address associated with this account. Thank you for helping us keep your data safe.",
|
||||
"account.locked.out.message.1": "To protect your account, it's been temporarily locked. Try again in 30 minutes.",
|
||||
"first.time.here": "First time here?",
|
||||
"email.help.message": "The email address you used to register with edX.",
|
||||
"enterprise.login.btn.text": "Company or school credentials",
|
||||
"email.format.validation.message": "The email address you've provided isn't formatted correctly.",
|
||||
"username.or.email.format.validation.less.chars.message": "Username or email must have at least 3 characters.",
|
||||
"email.validation.message": "Enter your username or email",
|
||||
"password.validation.message": "Password criteria has not been met",
|
||||
"register.link": "Create an account",
|
||||
"sign.in.heading": "Sign in",
|
||||
"account.activation.success.message.title": "Success! You have activated your account.",
|
||||
"account.activation.success.message": "You will now receive email updates and alerts from us related to the courses you are enrolled in. Sign in to continue.",
|
||||
"account.already.activated.message": "This account has already been activated.",
|
||||
"account.activation.error.message.title": "Your account could not be activated",
|
||||
"account.activation.support.link": "contact support",
|
||||
"login.rate.limit.reached.message": "Too many failed login attempts. Try again later.",
|
||||
"login.failure.header.title": "We couldn't sign you in.",
|
||||
"contact.support.link": "contact {platformName} support",
|
||||
"login.incorrect.credentials.error": "The username, email, or password you entered is incorrect. Please try again.",
|
||||
"login.failed.attempt.error": "You have {remainingAttempts} more sign in attempts before your account is temporarily locked.",
|
||||
"login.locked.out.error.message": "To protect your account, it’s been temporarily locked. Try again in {lockedOutPeriod} minutes.",
|
||||
"login.form.invalid.error.message": "Please fill in the fields below.",
|
||||
"login.incorrect.credentials.error.reset.link.text": "reset your password",
|
||||
"login.incorrect.credentials.error.before.account.blocked.text": "click here to reset it.",
|
||||
"register.page.title": "Register | {siteName}",
|
||||
"registration.fullname.label": "Full name",
|
||||
"forgot.password.empty.email.field.error": "Saisissez votre courriel",
|
||||
"forgot.password.invalid.email.message": "L'adresse email que vous avez fournie est incorrecte.",
|
||||
"forgot.password.email.help.text": "L'adresse courriel que vous avez utilisée pour vous inscrire sur {platformName}",
|
||||
"confirmation.message.title": "Vérifiez votre email",
|
||||
"confirmation.support.link": "contacter le support technique",
|
||||
"need.help.sign.in.text": "Besoin d'aide pour vous enregistrer?",
|
||||
"additional.help.text": "For additional help, contact {platformName} support at ",
|
||||
"sign.in.text": "Connectez-vous",
|
||||
"extend.field.errors": "{emailError} ci-dessous.",
|
||||
"invalid.token.heading": "Lien de réinitialisation du mot de passe non valide",
|
||||
"invalid.token.error.message": "Ce lien de réinitialisation de mot de passe n'est pas valide. Il a peut-être déjà été utilisé. Entrez votre courriel ci-dessous pour recevoir un nouveau lien.",
|
||||
"token.validation.rate.limit.error.heading": "Trop de demandes",
|
||||
"token.validation.rate.limit.error": "Une erreur s'est produite en raison d'un trop grand nombre de demandes. Veuillez réessayer après un certain temps.",
|
||||
"token.validation.internal.sever.error.heading": "Échec de la validation du jeton",
|
||||
"token.validation.internal.sever.error": "Une erreur est survenue. Essayer de rafraîchir la page, ou vérifier votre connexion Internet.",
|
||||
"internal.server.error": "Une erreur est survenue. Essayer de rafraîchir la page, ou vérifier votre connexion Internet.",
|
||||
"rate.limit.error": "Une erreur s'est produite en raison d'un trop grand nombre de demandes. Veuillez réessayer après un certain temps.",
|
||||
"account.activation.error.message": "Une erreur s'est produite, veuillez {supportLink} pour résoudre ce problème.",
|
||||
"login.inactive.user.error": "Pour vous connecter, vous devez activer votre compte.{lineBreak}\n {lineBreak}Nous venons d'envoyer un lien d'activation à {email}. Si vous ne recevez pas de courriel,\n vérifiez vos dossiers de spam ou {supportLink}.",
|
||||
"allowed.domain.login.error": "As {allowedDomain} user, You must login with your {allowedDomain} {tpaLink}.",
|
||||
"login.incorrect.credentials.error.attempts.text.1": "Le nom d'utilisateur, le courriel ou le mot de passe que vous avez entré est incorrect. Vous avez {remainingAttempts} tentatives\n de connexion avant que votre compte soit temporairement verrouillé.",
|
||||
"login.incorrect.credentials.error.attempts.text.2": "Si vous avez oublié votre mot de passe, {resetLink}",
|
||||
"account.locked.out.message.2": "Par mesure de sécurité, vous pouvez {resetLink} avant de réessayer.",
|
||||
"login.incorrect.credentials.error.with.reset.link": "Le nom d'utilisateur, l'adresse courriel ou le mot de passe que vous avez saisis sont incorrects. Veuillez réessayer ou {resetLink}.",
|
||||
"login.page.title": "Connexion | {siteName}",
|
||||
"login.user.identity.label": "Nom d'utilisateur ou courriel",
|
||||
"login.password.label": "Mot de passe",
|
||||
"sign.in.button": "Connectez-vous",
|
||||
"sign.in.btn.pending.state": "Chargement en cours",
|
||||
"need.help.signing.in.collapsible.menu": "Besoin d'aide pour vous enregistrer?",
|
||||
"forgot.password.link": "J'ai oublié mon mot de passe",
|
||||
"forgot.password": "Mot de passe oublié",
|
||||
"other.sign.in.issues": "Autres problèmes de connexion",
|
||||
"need.other.help.signing.in.collapsible.menu": "Encore besoin d'aide pour vous enregistrer?",
|
||||
"institution.login.button": "Identifiants de l'établissement/du campus",
|
||||
"institution.login.page.title": "Connectez vous avec les crédentiels d'institution ou de campus",
|
||||
"institution.login.page.back.button": "Retour à la connexion",
|
||||
"create.an.account": "Créer un compte",
|
||||
"login.other.options.heading": "Ou se connecter avec :",
|
||||
"non.compliant.password.title": "Nous avons récemment modifié nos exigences en matière de mot de passe",
|
||||
"non.compliant.password.message": "Votre mot de passe actuel ne répond pas aux nouvelles exigences de sécurité. Nous venons d'envoyer un message de réinitialisation de mot de passe à l'adresse courriel associée à ce compte. Merci de nous aider à protéger vos données.",
|
||||
"account.locked.out.message.1": "Pour protéger votre compte, il a été temporairement verrouillé. Réessayez dans 30 minutes.",
|
||||
"first.time.here": "C'est votre première visite ?",
|
||||
"email.help.message": "L'adresse électronique que vous avez utilisée pour vous inscrire à edX.",
|
||||
"enterprise.login.btn.text": "Identifiants de la compagnie ou de l'école",
|
||||
"email.format.validation.message": "L'adresse email que vous avez fournie est incorrecte.",
|
||||
"username.or.email.format.validation.less.chars.message": "Le nom d'utilisateur ou l'adresse courriel doit comporter au moins 3 caractères.",
|
||||
"email.validation.message": "Entrez votre nom d'utilisateur ou votre adresse courriel",
|
||||
"password.validation.message": "Les critères de mot de passe n'ont pas été remplis",
|
||||
"register.link": "Créer un compte",
|
||||
"sign.in.heading": "Connectez-vous",
|
||||
"account.activation.success.message.title": "Succès! Vous avez activé votre compte.",
|
||||
"account.activation.success.message": "Vous recevrez maintenant des mises à jour par courriel et des alertes de notre part concernant les cours auxquels vous êtes inscrit. Connectez-vous pour continuer.",
|
||||
"account.activation.info.message": "Ce compte a déjà été activé.",
|
||||
"account.activation.error.message.title": "Votre compte n'a pas pu être activé",
|
||||
"account.activation.support.link": "contacter le support",
|
||||
"tpa.account.link": "{provider} account",
|
||||
"account.confirmation.success.message.title": "Succès ! Vous avez confirmé votre courriel.",
|
||||
"account.confirmation.success.message": "Se connecter pour continuer.",
|
||||
"account.confirmation.info.message": "Ce courriel a déjà été confirmé.",
|
||||
"account.confirmation.error.message.title": "Votre courriel ne peut pas être confirmé.",
|
||||
"login.rate.limit.reached.message": "Trop de tentatives de connexion échouées. Réessayez plus tard.",
|
||||
"login.failure.header.title": "Nous n'avons pas pu vous connecter.",
|
||||
"contact.support.link": "veuillez contacter le support {platformName}",
|
||||
"login.incorrect.credentials.error": "Le nom d'utilisateur, l'adresse courriel ou le mot de passe que vous avez saisis sont incorrects. Veuillez réessayer.",
|
||||
"login.failed.attempt.error": "Il vous reste {remainingAttempts} tentatives de connexion supplémentaires avant que votre compte ne soit temporairement verrouillé.",
|
||||
"login.locked.out.error.message": "Pour protéger votre compte, il a été temporairement verrouillé. Réessayez dans {lockedOutPeriod} minutes.",
|
||||
"login.form.invalid.error.message": "Veuillez remplir les champs ci-dessous.",
|
||||
"login.incorrect.credentials.error.reset.link.text": "réinitialiser votre mot de passe",
|
||||
"login.incorrect.credentials.error.before.account.blocked.text": "cliquez ici pour le réinitialiser.",
|
||||
"password.security.nudge.title": "Sécurité du mot de passe",
|
||||
"password.security.block.title": "Changement de mot de passe requis",
|
||||
"password.security.nudge.body": "Notre système a détecté que votre mot de passe est vulnérable. Nous vous recommandons de le modifier afin que votre compte reste sécurisé.",
|
||||
"password.security.block.body": "Notre système a détecté que votre mot de passe est vulnérable. Changez votre mot de passe afin que votre compte reste sécurisé.",
|
||||
"password.security.close.button": "Fermer",
|
||||
"password.security.redirect.to.reset.password.button": "Réinitialiser votre mot de passe",
|
||||
"progressive.profiling.page.title": "Champs optionnels | {siteName}",
|
||||
"progressive.profiling.page.heading": "Quelques questions pour vous nous aideront à devenir plus intelligents.",
|
||||
"optional.fields.information.link": "En savoir plus sur la façon dont nous utilisons ces informations.",
|
||||
"optional.fields.submit.button": "Envoyez",
|
||||
"optional.fields.skip.button": "Ignorer pour l'instant",
|
||||
"optional.fields.next.button": "Next",
|
||||
"continue.to.platform": "Continuer vers {platformName}",
|
||||
"modal.title": "Merci de nous en informer.",
|
||||
"modal.description": "Vous pouvez compléter votre profil dans les paramètres à tout moment si vous changez d'avis.",
|
||||
"welcome.page.error.heading": "Nous n'avons pas pu mettre à jour votre profil",
|
||||
"welcome.page.error.message": "Une erreur s'est produite. Vous pouvez compléter votre profil dans les paramètres à tout moment.",
|
||||
"recommendation.page.title": "Recommendations| {siteName}",
|
||||
"recommendation.page.heading": "We have a few recommendations to get you started.",
|
||||
"recommendation.skip.button": "Skip for now",
|
||||
"register.page.title": "S'inscrire | {siteName}",
|
||||
"registration.fullname.label": "Nom complet",
|
||||
"registration.email.label": "Email",
|
||||
"registration.username.label": "Public username",
|
||||
"registration.password.label": "Password",
|
||||
"registration.country.label": "Country/Region",
|
||||
"help.text.name": "This name will be used by any certificates that you earn.",
|
||||
"help.text.username.1": "The name that will identify you in your courses.",
|
||||
"help.text.username.2": "This can not be changed later.",
|
||||
"help.text.email": "For account activation and important updates",
|
||||
"create.account.button": "Create an account",
|
||||
"create.an.account.btn.pending.state": "Loading",
|
||||
"registration.other.options.heading": "Or register with:",
|
||||
"register.institution.login.button": "Institution/campus credentials",
|
||||
"register.institution.login.page.title": "Register with institution/campus credentials",
|
||||
"empty.name.field.error": "Enter your full name",
|
||||
"empty.email.field.error": "Enter your email",
|
||||
"empty.country.field.error": "Select your country or region of residence",
|
||||
"registration.username.label": "Nom d'utilisateur public",
|
||||
"registration.password.label": "Mot de passe",
|
||||
"registration.country.label": "Pays/Région",
|
||||
"registration.opt.in.label": "{siteName} peux m'envoyer des messages de marketing.",
|
||||
"help.text.name": "Ce nom sera utilisé pour toutes les attestations que vous obtiendrez.",
|
||||
"help.text.username.1": "Le nom qui vous identifiera dans vos cours.",
|
||||
"help.text.username.2": "Cela ne peut pas être modifié ultérieurement.",
|
||||
"help.text.email": "Pour l'activation du compte et les mises à jour importantes",
|
||||
"create.account.for.free.button": "Créer un compte gratuitement",
|
||||
"create.an.account.btn.pending.state": "Chargement en cours",
|
||||
"registration.other.options.heading": "Ou inscrivez-vous avec :",
|
||||
"register.institution.login.button": "Identifiants de l'établissement/du campus",
|
||||
"register.institution.login.page.title": "Inscription avec les crédentiels d'institution ou de campus",
|
||||
"empty.name.field.error": "Saisissez votre nom complet",
|
||||
"empty.email.field.error": "Saisissez votre courriel",
|
||||
"email.do.not.match": "The email addresses do not match.",
|
||||
"empty.username.field.error": "Le nom d'utilisateur doit comporter entre 2 et 30 caractères",
|
||||
"empty.password.field.error": "Les critères de mot de passe n'ont pas été remplis",
|
||||
"empty.country.field.error": "Sélectionnez votre pays ou région de résidence",
|
||||
"email.invalid.format.error": "Enter a valid email address",
|
||||
"email.ratelimit.less.chars.validation.message": "Email must have 3 characters.",
|
||||
"username.validation.message": "Username must be between 2 and 30 characters",
|
||||
"username.format.validation.message": "Usernames can only contain letters (A-Z, a-z), numerals (0-9), underscores (_), and hyphens (-).",
|
||||
"support.education.research": "Support education research by providing additional information. (Optional)",
|
||||
"registration.request.failure.header": "We couldn't create your account.",
|
||||
"registration.empty.form.submission.error": "Please check your responses and try again.",
|
||||
"registration.request.server.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"registration.rate.limit.error": "Too many failed registration attempts. Try again later.",
|
||||
"registration.tpa.session.expired": "Registration using {provider} has timed out.",
|
||||
"terms.of.service.and.honor.code": "Terms of Service and Honor Code",
|
||||
"privacy.policy": "Privacy Policy",
|
||||
"registration.year.of.birth.label": "Year of birth (optional)",
|
||||
"registration.field.gender.options.label": "Gender (optional)",
|
||||
"registration.goals.label": "Tell us why you're interested in edX (optional)",
|
||||
"registration.field.gender.options.f": "Female",
|
||||
"registration.field.gender.options.m": "Male",
|
||||
"registration.field.gender.options.o": "Other/Prefer not to say",
|
||||
"registration.field.education.levels.label": "Highest level of education completed (optional)",
|
||||
"registration.field.education.levels.p": "Doctorate",
|
||||
"registration.field.education.levels.m": "Master's or professional degree",
|
||||
"registration.field.education.levels.b": "Bachelor's degree",
|
||||
"registration.field.education.levels.a": "Associate's degree",
|
||||
"registration.field.education.levels.hs": "Secondary/high school",
|
||||
"registration.field.education.levels.jhs": "Junior secondary/junior high/middle school",
|
||||
"registration.field.education.levels.el": "Elementary/primary school",
|
||||
"registration.field.education.levels.none": "No formal education",
|
||||
"registration.field.education.levels.other": "Other education",
|
||||
"registration.username.suggestion.label": "Available:",
|
||||
"registration.using.tpa.form.heading": "Finish creating your account",
|
||||
"did.you.mean.alert.text": "Did you mean",
|
||||
"register.page.terms.of.service.and.honor.code": "By creating an account, you agree to the {tosAndHonorCode} and you acknowledge that {platformName} and each\n Member process your personal data in accordance with the {privacyPolicy}.",
|
||||
"sign.in": "Sign in",
|
||||
"reset.password.page.title": "Reset Password | {siteName}",
|
||||
"reset.password": "Reset password",
|
||||
"reset.password.page.instructions": "Enter and confirm your new password.",
|
||||
"new.password.label": "New password",
|
||||
"confirm.password.label": "Confirm password",
|
||||
"passwords.do.not.match": "Passwords do not match",
|
||||
"confirm.your.password": "Confirm your password",
|
||||
"forgot.password.confirmation.sign.in.link": "sign in",
|
||||
"reset.password.request.forgot.password.text": "Forgot password",
|
||||
"reset.password.request.invalid.token.header": "Invalid password reset link",
|
||||
"reset.password.empty.new.password.field.error": "Please enter your new password.",
|
||||
"reset.password.failure.heading": "We couldn't reset your password.",
|
||||
"reset.password.form.submission.error": "Please check your responses and try again.",
|
||||
"reset.password.request.server.error": "Failed to reset password",
|
||||
"reset.password.token.validation.sever.error": "Token validation failure",
|
||||
"reset.server.rate.limit.error": "Too many requests.",
|
||||
"reset.password.success.heading": "Password reset complete.",
|
||||
"reset.password.success": "Your password has been reset. Sign in to your account.",
|
||||
"progressive.profiling.page.title": "Optional Fields | {siteName}",
|
||||
"progressive.profiling.page.heading": "A few questions for you will help us get smarter.",
|
||||
"gender.options.label": "Gender (optional)",
|
||||
"gender.options.f": "Female",
|
||||
"gender.options.m": "Male",
|
||||
"gender.options.o": "Other/Prefer not to say",
|
||||
"education.levels.label": "Highest level of education completed (optional)",
|
||||
"education.levels.p": "Doctorate",
|
||||
"education.levels.m": "Master's or professional degree",
|
||||
"education.levels.b": "Bachelor's degree",
|
||||
"education.levels.a": "Associate's degree",
|
||||
"education.levels.hs": "Secondary/high school",
|
||||
"education.levels.jhs": "Junior secondary/junior high/middle school",
|
||||
"education.levels.el": "Elementary/primary school",
|
||||
"education.levels.none": "No formal education",
|
||||
"education.levels.other": "Other education",
|
||||
"year.of.birth.label": "Year of birth (optional)",
|
||||
"optional.fields.information.link": "Learn more about how we use this information.",
|
||||
"optional.fields.submit.button": "Submit",
|
||||
"optional.fields.skip.button": "Skip for now",
|
||||
"continue.to.platform": "Continue to {platformName}",
|
||||
"modal.title": "Thanks for letting us know.",
|
||||
"modal.description": "You can complete your profile in settings at any time if you change your mind.",
|
||||
"welcome.page.error.heading": "We couldn't update your profile",
|
||||
"welcome.page.error.message": "An error occurred. You can complete your profile in settings at any time."
|
||||
"email.ratelimit.less.chars.validation.message": "Le courriel doit comporter 3 caractères.",
|
||||
"username.validation.message": "Le nom d'utilisateur doit comporter entre 2 et 30 caractères",
|
||||
"name.validation.message": "Enter a valid name",
|
||||
"username.format.validation.message": "Usernames can only contain letters (A-Z, a-z), numerals (0-9), underscores (_), and hyphens (-). Usernames cannot contain spaces",
|
||||
"support.education.research": "Soutenez la recherche en éducation en fournissant des informations additionnelles. (Optionel)",
|
||||
"registration.request.failure.header": "Nous n'avons pas pu créer votre compte.",
|
||||
"registration.empty.form.submission.error": "Veuillez vérifier vos réponses et réessayer.",
|
||||
"registration.request.server.error": "Une erreur est survenue. Essayer de rafraîchir la page, ou vérifier votre connexion Internet.",
|
||||
"registration.rate.limit.error": "Trop de tentatives d'inscriptions ont échoué. Réessayez plus tard.",
|
||||
"registration.tpa.session.expired": "L'inscription avec {provider} a échouée.",
|
||||
"terms.of.service.and.honor.code": "Conditions d'utilisation et Code d'honneur",
|
||||
"privacy.policy": "Politique de confidentialité",
|
||||
"honor.code": "Code d'honneur",
|
||||
"terms.of.service": " Conditions d'utilisation",
|
||||
"registration.year.of.birth.label": "Année de naissance (facultatif)",
|
||||
"registration.field.gender.options.label": "Sexe (facultatif)",
|
||||
"registration.goals.label": "Dites-nous pourquoi vous êtes intéressé par edX (facultatif)",
|
||||
"registration.field.gender.options.f": "Femme",
|
||||
"registration.field.gender.options.m": "Homme",
|
||||
"registration.field.gender.options.o": "Autre / Préfère ne pas répondre",
|
||||
"registration.field.education.levels.label": "Plus haut niveau de scolarité atteint (facultatif)",
|
||||
"registration.field.education.levels.p": "Doctorat",
|
||||
"registration.field.education.levels.m": "Master ou diplôme professionnel",
|
||||
"registration.field.education.levels.b": "Diplôme de premier cycle supérieur",
|
||||
"registration.field.education.levels.a": "Grade de l'associé",
|
||||
"registration.field.education.levels.hs": "Lycée / enseignement secondaire",
|
||||
"registration.field.education.levels.jhs": "Collège / enseignement secondaire inférieur",
|
||||
"registration.field.education.levels.el": "Enseignement primaire",
|
||||
"registration.field.education.levels.none": "Sans diplôme",
|
||||
"registration.field.education.levels.other": "Autre niveau d'étude",
|
||||
"registration.username.suggestion.label": "Suggéré :",
|
||||
"registration.using.tpa.form.heading": "Terminer la création de votre compte",
|
||||
"did.you.mean.alert.text": "Vouliez-vous dire",
|
||||
"register.page.terms.of.service": "J'accepte les {termsOfService} {platformName}",
|
||||
"sign.in": "Connectez-vous",
|
||||
"reset.password.page.title": "Réinitialiser le mot de passe | {siteName}",
|
||||
"reset.password": "Réinitialiser le mot de passe",
|
||||
"reset.password.page.instructions": "Saisir et confirmer votre nouveau mot de passe.",
|
||||
"new.password.label": "Nouveau mot de passe",
|
||||
"confirm.password.label": "Confirmer le mot de passe",
|
||||
"passwords.do.not.match": "Les mots de passe ne correspondent pas",
|
||||
"confirm.your.password": "Confirmer votre mot de passe",
|
||||
"forgot.password.confirmation.sign.in.link": "connexion",
|
||||
"reset.password.request.forgot.password.text": "Mot de passe oublié",
|
||||
"reset.password.request.invalid.token.header": "Lien de réinitialisation du mot de passe non valide",
|
||||
"reset.password.empty.new.password.field.error": "Veuillez entrer votre nouveau mot de passe.",
|
||||
"reset.password.failure.heading": "Nous n'avons pas pu réinitialiser votre mot de passe.",
|
||||
"reset.password.form.submission.error": "Veuillez vérifier vos réponses et réessayer.",
|
||||
"reset.password.request.server.error": "Échec de la réinitialisation du mot de passe",
|
||||
"reset.password.token.validation.sever.error": "Échec de la validation du jeton",
|
||||
"reset.server.rate.limit.error": "Trop de demandes.",
|
||||
"reset.password.success.heading": "Réinitialisation du mot de passe complétée.",
|
||||
"reset.password.success": "Votre mot de passe a été réinitialisé. Connectez-vous à votre compte.",
|
||||
"progressive.profiling.page.title": "Champs optionnels | {siteName}",
|
||||
"progressive.profiling.page.heading": "Quelques questions pour vous nous aideront à devenir plus intelligents.",
|
||||
"gender.options.label": "Sexe (facultatif)",
|
||||
"gender.options.f": "Femme",
|
||||
"gender.options.m": "Homme",
|
||||
"gender.options.o": "Autre / Préfère ne pas répondre",
|
||||
"education.levels.label": "Plus haut niveau de scolarité atteint (facultatif)",
|
||||
"education.levels.p": "Doctorat",
|
||||
"education.levels.m": "Master ou diplôme professionnel",
|
||||
"education.levels.b": "Diplôme de premier cycle supérieur",
|
||||
"education.levels.a": "Grade de l'associé",
|
||||
"education.levels.hs": "Lycée / enseignement secondaire",
|
||||
"education.levels.jhs": "Collège / enseignement secondaire inférieur",
|
||||
"education.levels.el": "Enseignement primaire",
|
||||
"education.levels.none": "Sans diplôme",
|
||||
"education.levels.other": "Autre niveau d'étude",
|
||||
"year.of.birth.label": "Année de naissance (facultatif)",
|
||||
"optional.fields.information.link": "En savoir plus sur la façon dont nous utilisons ces informations.",
|
||||
"optional.fields.submit.button": "Envoyez",
|
||||
"optional.fields.skip.button": "Ignorer pour l'instant",
|
||||
"continue.to.platform": "Continuer vers {platformName}",
|
||||
"modal.title": "Merci de nous en informer.",
|
||||
"modal.description": "Vous pouvez compléter votre profil dans les paramètres à tout moment si vous changez d'avis.",
|
||||
"welcome.page.error.heading": "Nous n'avons pas pu mettre à jour votre profil",
|
||||
"welcome.page.error.message": "Une erreur s'est produite. Vous pouvez compléter votre profil dans les paramètres à tout moment."
|
||||
}
|
||||
231
src/i18n/messages/hi.json
Normal file
231
src/i18n/messages/hi.json
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"start.learning": "Start learning",
|
||||
"with.site.name": "with {siteName}",
|
||||
"complete.your.profile.1": "Complete",
|
||||
"complete.your.profile.2": "your profile",
|
||||
"welcome.to.platform": "Welcome to {siteName}, {username}!",
|
||||
"institution.login.page.sub.heading": "Choose your institution from the list below",
|
||||
"forgot.password.confirmation.title": "Check your email",
|
||||
"forgot.password.confirmation.support.link": "contact technical support",
|
||||
"forgot.password.confirmation.info": "If you do not receive a password reset message after 1 minute, verify that you entered the correct email address, or check your spam folder.",
|
||||
"logistration.sign.in": "Sign in",
|
||||
"logistration.register": "Register",
|
||||
"internal.server.error.message": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"server.ratelimit.error.message": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"enterprisetpa.title.heading": "Would you like to sign in using your {providerName} credentials?",
|
||||
"enterprisetpa.sso.button.title": "Sign in using {providerName}",
|
||||
"enterprisetpa.login.button.text": "Show me other ways to sign in or register",
|
||||
"sso.sign.in.with": "Sign in with {providerName}",
|
||||
"sso.create.account.using": "Create account using {providerName}",
|
||||
"show.password": "Show password",
|
||||
"hide.password": "Hide password",
|
||||
"one.letter": "1 letter",
|
||||
"one.number": "1 number",
|
||||
"eight.characters": "8 characters",
|
||||
"password.sr.only.helping.text": "Password must contain at least 8 characters, at least one letter, and at least one number",
|
||||
"tpa.alert.heading": "Almost done!",
|
||||
"login.third.party.auth.account.not.linked": "You have successfully signed into {currentProvider}, but your {currentProvider} account does not have a linked {platformName} account. To link your accounts, sign in now using your {platformName} password.",
|
||||
"register.third.party.auth.account.not.linked": "You've successfully signed into {currentProvider}! We just need a little more information before you start learning with {platformName}.",
|
||||
"error.notfound.message": "The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again.",
|
||||
"forgot.password.confirmation.message": "We sent an email to {email} with instructions to reset your password.\n If you do not receive a password reset message after 1 minute, verify that you entered\n the correct email address, or check your spam folder. If you need further assistance, {supportLink}.",
|
||||
"forgot.password.page.title": "Forgot Password | {siteName}",
|
||||
"forgot.password.page.heading": "Reset password",
|
||||
"forgot.password.page.instructions": "Please enter your email address below and we will send you an email with instructions on how to reset your password.",
|
||||
"forgot.password.page.invalid.email.message": "Enter a valid email address",
|
||||
"forgot.password.page.email.field.label": "Email",
|
||||
"forgot.password.page.submit.button": "Submit",
|
||||
"forgot.password.error.alert.title.": "We were unable to contact you.",
|
||||
"forgot.password.error.message.title": "An error occurred.",
|
||||
"forgot.password.request.in.progress.message": "Your previous request is in progress, please try again in a few moments.",
|
||||
"forgot.password.empty.email.field.error": "Enter your email",
|
||||
"forgot.password.invalid.email.message": "The email address you've provided isn't formatted correctly.",
|
||||
"forgot.password.email.help.text": "The email address you used to register with {platformName}",
|
||||
"confirmation.message.title": "Check your email",
|
||||
"confirmation.support.link": "contact technical support",
|
||||
"need.help.sign.in.text": "Need help signing in?",
|
||||
"additional.help.text": "For additional help, contact {platformName} support at ",
|
||||
"sign.in.text": "Sign in",
|
||||
"extend.field.errors": "{emailError} below.",
|
||||
"invalid.token.heading": "Invalid password reset link",
|
||||
"invalid.token.error.message": "This password reset link is invalid. It may have been used already. Enter your email below to receive a new link.",
|
||||
"token.validation.rate.limit.error.heading": "Too many requests",
|
||||
"token.validation.rate.limit.error": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"token.validation.internal.sever.error.heading": "Token validation failure",
|
||||
"token.validation.internal.sever.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"internal.server.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"rate.limit.error": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"account.activation.error.message": "Something went wrong, please {supportLink} to resolve this issue.",
|
||||
"login.inactive.user.error": "In order to sign in, you need to activate your account.{lineBreak}\n {lineBreak}We just sent an activation link to {email}. If you do not receive an email,\n check your spam folders or {supportLink}.",
|
||||
"allowed.domain.login.error": "As {allowedDomain} user, You must login with your {allowedDomain} {tpaLink}.",
|
||||
"login.incorrect.credentials.error.attempts.text.1": "The username, email or password you entered is incorrect. You have {remainingAttempts} more sign in\n attempts before your account is temporarily locked.",
|
||||
"login.incorrect.credentials.error.attempts.text.2": "If you've forgotten your password, {resetLink}",
|
||||
"account.locked.out.message.2": "To be on the safe side, you can {resetLink} before trying again.",
|
||||
"login.incorrect.credentials.error.with.reset.link": "The username, email, or password you entered is incorrect. Please try again or {resetLink}.",
|
||||
"login.page.title": "Login | {siteName}",
|
||||
"login.user.identity.label": "Username or email",
|
||||
"login.password.label": "Password",
|
||||
"sign.in.button": "Sign in",
|
||||
"sign.in.btn.pending.state": "Loading",
|
||||
"need.help.signing.in.collapsible.menu": "Need help signing in?",
|
||||
"forgot.password.link": "Forgot my password",
|
||||
"forgot.password": "Forgot password",
|
||||
"other.sign.in.issues": "Other sign in issues",
|
||||
"need.other.help.signing.in.collapsible.menu": "Need other help signing in?",
|
||||
"institution.login.button": "Institution/campus credentials",
|
||||
"institution.login.page.title": "Sign in with institution/campus credentials",
|
||||
"institution.login.page.back.button": "Back to sign in",
|
||||
"create.an.account": "Create an account",
|
||||
"login.other.options.heading": "Or sign in with:",
|
||||
"non.compliant.password.title": "We recently changed our password requirements",
|
||||
"non.compliant.password.message": "Your current password does not meet the new security requirements. We just sent a password-reset message to the email address associated with this account. Thank you for helping us keep your data safe.",
|
||||
"account.locked.out.message.1": "To protect your account, it's been temporarily locked. Try again in 30 minutes.",
|
||||
"first.time.here": "First time here?",
|
||||
"email.help.message": "The email address you used to register with edX.",
|
||||
"enterprise.login.btn.text": "Company or school credentials",
|
||||
"email.format.validation.message": "The email address you've provided isn't formatted correctly.",
|
||||
"username.or.email.format.validation.less.chars.message": "Username or email must have at least 3 characters.",
|
||||
"email.validation.message": "Enter your username or email",
|
||||
"password.validation.message": "Password criteria has not been met",
|
||||
"register.link": "Create an account",
|
||||
"sign.in.heading": "Sign in",
|
||||
"account.activation.success.message.title": "Success! You have activated your account.",
|
||||
"account.activation.success.message": "You will now receive email updates and alerts from us related to the courses you are enrolled in. Sign in to continue.",
|
||||
"account.activation.info.message": "This account has already been activated.",
|
||||
"account.activation.error.message.title": "Your account could not be activated",
|
||||
"account.activation.support.link": "contact support",
|
||||
"tpa.account.link": "{provider} account",
|
||||
"account.confirmation.success.message.title": "Success! You have confirmed your email.",
|
||||
"account.confirmation.success.message": "Sign in to continue.",
|
||||
"account.confirmation.info.message": "This email has already been confirmed.",
|
||||
"account.confirmation.error.message.title": "Your email could not be confirmed",
|
||||
"login.rate.limit.reached.message": "Too many failed login attempts. Try again later.",
|
||||
"login.failure.header.title": "We couldn't sign you in.",
|
||||
"contact.support.link": "contact {platformName} support",
|
||||
"login.incorrect.credentials.error": "The username, email, or password you entered is incorrect. Please try again.",
|
||||
"login.failed.attempt.error": "You have {remainingAttempts} more sign in attempts before your account is temporarily locked.",
|
||||
"login.locked.out.error.message": "To protect your account, it’s been temporarily locked. Try again in {lockedOutPeriod} minutes.",
|
||||
"login.form.invalid.error.message": "Please fill in the fields below.",
|
||||
"login.incorrect.credentials.error.reset.link.text": "reset your password",
|
||||
"login.incorrect.credentials.error.before.account.blocked.text": "click here to reset it.",
|
||||
"password.security.nudge.title": "Password security",
|
||||
"password.security.block.title": "Password change required",
|
||||
"password.security.nudge.body": "Our system detected that your password is vulnerable. We recommend you change it so that your account stays secure.",
|
||||
"password.security.block.body": "Our system detected that your password is vulnerable. Change your password so that your account stays secure.",
|
||||
"password.security.close.button": "Close",
|
||||
"password.security.redirect.to.reset.password.button": "Reset your password",
|
||||
"progressive.profiling.page.title": "Optional Fields | {siteName}",
|
||||
"progressive.profiling.page.heading": "A few questions for you will help us get smarter.",
|
||||
"optional.fields.information.link": "Learn more about how we use this information.",
|
||||
"optional.fields.submit.button": "Submit",
|
||||
"optional.fields.skip.button": "Skip for now",
|
||||
"optional.fields.next.button": "Next",
|
||||
"continue.to.platform": "Continue to {platformName}",
|
||||
"modal.title": "Thanks for letting us know.",
|
||||
"modal.description": "You can complete your profile in settings at any time if you change your mind.",
|
||||
"welcome.page.error.heading": "We couldn't update your profile",
|
||||
"welcome.page.error.message": "An error occurred. You can complete your profile in settings at any time.",
|
||||
"recommendation.page.title": "Recommendations| {siteName}",
|
||||
"recommendation.page.heading": "We have a few recommendations to get you started.",
|
||||
"recommendation.skip.button": "Skip for now",
|
||||
"register.page.title": "Register | {siteName}",
|
||||
"registration.fullname.label": "Full name",
|
||||
"registration.email.label": "Email",
|
||||
"registration.username.label": "Public username",
|
||||
"registration.password.label": "Password",
|
||||
"registration.country.label": "Country/Region",
|
||||
"registration.opt.in.label": "I agree that {siteName} may send me marketing messages.",
|
||||
"help.text.name": "This name will be used by any certificates that you earn.",
|
||||
"help.text.username.1": "The name that will identify you in your courses.",
|
||||
"help.text.username.2": "This can not be changed later.",
|
||||
"help.text.email": "For account activation and important updates",
|
||||
"create.account.for.free.button": "Create an account for free",
|
||||
"create.an.account.btn.pending.state": "Loading",
|
||||
"registration.other.options.heading": "Or register with:",
|
||||
"register.institution.login.button": "Institution/campus credentials",
|
||||
"register.institution.login.page.title": "Register with institution/campus credentials",
|
||||
"empty.name.field.error": "Enter your full name",
|
||||
"empty.email.field.error": "Enter your email",
|
||||
"email.do.not.match": "The email addresses do not match.",
|
||||
"empty.username.field.error": "Username must be between 2 and 30 characters",
|
||||
"empty.password.field.error": "Password criteria has not been met",
|
||||
"empty.country.field.error": "Select your country or region of residence",
|
||||
"email.invalid.format.error": "Enter a valid email address",
|
||||
"email.ratelimit.less.chars.validation.message": "Email must have 3 characters.",
|
||||
"username.validation.message": "Username must be between 2 and 30 characters",
|
||||
"name.validation.message": "Enter a valid name",
|
||||
"username.format.validation.message": "Usernames can only contain letters (A-Z, a-z), numerals (0-9), underscores (_), and hyphens (-). Usernames cannot contain spaces",
|
||||
"support.education.research": "Support education research by providing additional information. (Optional)",
|
||||
"registration.request.failure.header": "We couldn't create your account.",
|
||||
"registration.empty.form.submission.error": "Please check your responses and try again.",
|
||||
"registration.request.server.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"registration.rate.limit.error": "Too many failed registration attempts. Try again later.",
|
||||
"registration.tpa.session.expired": "Registration using {provider} has timed out.",
|
||||
"terms.of.service.and.honor.code": "Terms of Service and Honor Code",
|
||||
"privacy.policy": "Privacy Policy",
|
||||
"honor.code": "Honor Code",
|
||||
"terms.of.service": "Terms of Service",
|
||||
"registration.year.of.birth.label": "Year of birth (optional)",
|
||||
"registration.field.gender.options.label": "Gender (optional)",
|
||||
"registration.goals.label": "Tell us why you're interested in edX (optional)",
|
||||
"registration.field.gender.options.f": "Female",
|
||||
"registration.field.gender.options.m": "Male",
|
||||
"registration.field.gender.options.o": "Other/Prefer not to say",
|
||||
"registration.field.education.levels.label": "Highest level of education completed (optional)",
|
||||
"registration.field.education.levels.p": "Doctorate",
|
||||
"registration.field.education.levels.m": "Master's or professional degree",
|
||||
"registration.field.education.levels.b": "Bachelor's degree",
|
||||
"registration.field.education.levels.a": "Associate's degree",
|
||||
"registration.field.education.levels.hs": "Secondary/high school",
|
||||
"registration.field.education.levels.jhs": "Junior secondary/junior high/middle school",
|
||||
"registration.field.education.levels.el": "Elementary/primary school",
|
||||
"registration.field.education.levels.none": "No formal education",
|
||||
"registration.field.education.levels.other": "Other education",
|
||||
"registration.username.suggestion.label": "Suggested:",
|
||||
"registration.using.tpa.form.heading": "Finish creating your account",
|
||||
"did.you.mean.alert.text": "Did you mean",
|
||||
"register.page.terms.of.service": "I agree to the {platformName} {termsOfService}",
|
||||
"sign.in": "Sign in",
|
||||
"reset.password.page.title": "Reset Password | {siteName}",
|
||||
"reset.password": "Reset password",
|
||||
"reset.password.page.instructions": "Enter and confirm your new password.",
|
||||
"new.password.label": "New password",
|
||||
"confirm.password.label": "Confirm password",
|
||||
"passwords.do.not.match": "Passwords do not match",
|
||||
"confirm.your.password": "Confirm your password",
|
||||
"forgot.password.confirmation.sign.in.link": "sign in",
|
||||
"reset.password.request.forgot.password.text": "Forgot password",
|
||||
"reset.password.request.invalid.token.header": "Invalid password reset link",
|
||||
"reset.password.empty.new.password.field.error": "Please enter your new password.",
|
||||
"reset.password.failure.heading": "We couldn't reset your password.",
|
||||
"reset.password.form.submission.error": "Please check your responses and try again.",
|
||||
"reset.password.request.server.error": "Failed to reset password",
|
||||
"reset.password.token.validation.sever.error": "Token validation failure",
|
||||
"reset.server.rate.limit.error": "Too many requests.",
|
||||
"reset.password.success.heading": "Password reset complete.",
|
||||
"reset.password.success": "Your password has been reset. Sign in to your account.",
|
||||
"progressive.profiling.page.title": "Optional Fields | {siteName}",
|
||||
"progressive.profiling.page.heading": "A few questions for you will help us get smarter.",
|
||||
"gender.options.label": "Gender (optional)",
|
||||
"gender.options.f": "Female",
|
||||
"gender.options.m": "Male",
|
||||
"gender.options.o": "Other/Prefer not to say",
|
||||
"education.levels.label": "Highest level of education completed (optional)",
|
||||
"education.levels.p": "Doctorate",
|
||||
"education.levels.m": "Master's or professional degree",
|
||||
"education.levels.b": "Bachelor's degree",
|
||||
"education.levels.a": "Associate's degree",
|
||||
"education.levels.hs": "Secondary/high school",
|
||||
"education.levels.jhs": "Junior secondary/junior high/middle school",
|
||||
"education.levels.el": "Elementary/primary school",
|
||||
"education.levels.none": "No formal education",
|
||||
"education.levels.other": "Other education",
|
||||
"year.of.birth.label": "Year of birth (optional)",
|
||||
"optional.fields.information.link": "Learn more about how we use this information.",
|
||||
"optional.fields.submit.button": "Submit",
|
||||
"optional.fields.skip.button": "Skip for now",
|
||||
"continue.to.platform": "Continue to {platformName}",
|
||||
"modal.title": "Thanks for letting us know.",
|
||||
"modal.description": "You can complete your profile in settings at any time if you change your mind.",
|
||||
"welcome.page.error.heading": "We couldn't update your profile",
|
||||
"welcome.page.error.message": "An error occurred. You can complete your profile in settings at any time."
|
||||
}
|
||||
231
src/i18n/messages/it_IT.json
Normal file
231
src/i18n/messages/it_IT.json
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"start.learning": "Inizia a imparare",
|
||||
"with.site.name": "con {siteName}",
|
||||
"complete.your.profile.1": "Completata",
|
||||
"complete.your.profile.2": "Il tuo profilo",
|
||||
"welcome.to.platform": "Benvenuto in {siteName}, {username}!",
|
||||
"institution.login.page.sub.heading": "Scegli il tuo istituto dall'elenco sottostante",
|
||||
"forgot.password.confirmation.title": "Controlla la tua casella di posta",
|
||||
"forgot.password.confirmation.support.link": "contatta il supporto tecnico",
|
||||
"forgot.password.confirmation.info": "Se non ricevi un messaggio di reimpostazione della password entro 1 minuto, verifica di aver inserito l'indirizzo e-mail corretto o controlla la cartella della posta indesiderata.",
|
||||
"logistration.sign.in": "Accedi",
|
||||
"logistration.register": "Registrazione",
|
||||
"internal.server.error.message": "Si è verificato un errore. Prova ad aggiornare la pagina oppure verifica la connessione internet.",
|
||||
"server.ratelimit.error.message": "Si è verificato un errore dovuto alle troppe richieste. Prova di nuovo più tardi.",
|
||||
"enterprisetpa.title.heading": "Vuoi accedere utilizzando le credenziali {providerName}?",
|
||||
"enterprisetpa.sso.button.title": "Accedi utilizzando {providerName}",
|
||||
"enterprisetpa.login.button.text": "Mostrami altre modalità di accesso o registrazione",
|
||||
"sso.sign.in.with": "Accedi con {providerName}",
|
||||
"sso.create.account.using": "Crea un account utilizzando {providerName}",
|
||||
"show.password": "Mostra password",
|
||||
"hide.password": "Nascondi password",
|
||||
"one.letter": "1 lettera",
|
||||
"one.number": "1 numero",
|
||||
"eight.characters": "8 caratteri",
|
||||
"password.sr.only.helping.text": "La password deve contenere almeno 8 caratteri, almeno una lettera e almeno un numero",
|
||||
"tpa.alert.heading": "Quasi fatto!",
|
||||
"login.third.party.auth.account.not.linked": "Hai correttamente effettuato l'accesso in {currentProvider}, ma il tuo account {currentProvider} non ha un account {platformName} ad esso abbinato. Per collegare i tuoi account accesi utilizzando la password {platformName}. ",
|
||||
"register.third.party.auth.account.not.linked": "Hai eseguito correttamente l'accesso a {a03f0f8cfb85cz0}! Abbiamo solo bisogno di un po' più di informazioni prima di iniziare a imparare con {platformName}.",
|
||||
"error.notfound.message": "La pagina che stai cercando non è disponibile o si è verificato un errore nell'URL. Controlla l'URL e riprova. ",
|
||||
"forgot.password.confirmation.message": "Abbiamo inviato un'email a {email} con le istruzioni per reimpostare la password. Se non ricevi un messaggio di reimpostazione della password dopo 1 minuto, verifica di aver inserito l'indirizzo e-mail corretto o controlla la cartella spam. Se hai bisogno di ulteriore assistenza, {supportLink}.",
|
||||
"forgot.password.page.title": "Dimenticato la password | {siteName}",
|
||||
"forgot.password.page.heading": "Resetta la password",
|
||||
"forgot.password.page.instructions": "Inserisci il tuo indirizzo e-mail qui sotto e ti invieremo un'e-mail con le istruzioni su come reimpostare la tua password.",
|
||||
"forgot.password.page.invalid.email.message": "Inserisci un indirizzo email valido",
|
||||
"forgot.password.page.email.field.label": "Email",
|
||||
"forgot.password.page.submit.button": "Invia",
|
||||
"forgot.password.error.alert.title.": "Non siamo stati in grado di contattarti.",
|
||||
"forgot.password.error.message.title": "Si è verificato un errore. ",
|
||||
"forgot.password.request.in.progress.message": "La tua richiesta precedente è in corso di elaborazione, riprova tra qualche istante. ",
|
||||
"forgot.password.empty.email.field.error": "Inserisci il tuo indirizzo email",
|
||||
"forgot.password.invalid.email.message": "L'indirizzo email che hai fornito non è formattato correttamente. ",
|
||||
"forgot.password.email.help.text": "L'indirizzo email che hai utilizzato per registrarti con {platformName}",
|
||||
"confirmation.message.title": "Controlla la tua casella di posta",
|
||||
"confirmation.support.link": "contatta il supporto tecnico",
|
||||
"need.help.sign.in.text": "Hai bisogno di aiuto per l'accesso? ",
|
||||
"additional.help.text": "Per ulteriore assistenza, contattare l'assistenza {platformName} all'indirizzo",
|
||||
"sign.in.text": "Accedi",
|
||||
"extend.field.errors": "{emailError} di seguito.",
|
||||
"invalid.token.heading": "Link di ripristino della password non valido",
|
||||
"invalid.token.error.message": "Questo link per reimpostare la password non è valido. Potrebbe essere stato già utilizzato. Inserisci la tua email qui sotto per ricevere un nuovo link.",
|
||||
"token.validation.rate.limit.error.heading": "Troppe richieste",
|
||||
"token.validation.rate.limit.error": "Si è verificato un errore dovuto alle troppe richieste. Prova di nuovo più tardi.",
|
||||
"token.validation.internal.sever.error.heading": "Errore di convalida del token",
|
||||
"token.validation.internal.sever.error": "Si è verificato un errore. Prova ad aggiornare la pagina oppure verifica la connessione internet.",
|
||||
"internal.server.error": "Si è verificato un errore. Prova ad aggiornare la pagina oppure verifica la connessione internet.",
|
||||
"rate.limit.error": "Si è verificato un errore dovuto alle troppe richieste. Prova di nuovo più tardi.",
|
||||
"account.activation.error.message": "Si è verificato un errore, seleziona {supportLink} per risolvere il problema. ",
|
||||
"login.inactive.user.error": "Per accedere, devi attivare il tuo account.{lineBreak} {lineBreak}Abbiamo appena inviato un link di attivazione a {email}. Se non ricevi un'email, controlla la cartella della posta indesiderata oppure seleziona {supportLink}.",
|
||||
"allowed.domain.login.error": "As {allowedDomain} user, You must login with your {allowedDomain} {tpaLink}.",
|
||||
"login.incorrect.credentials.error.attempts.text.1": "Il nome utente, l'e-mail o la password che hai inserito non sono corretti. Hai {remainingAttempts} più tentativi di accesso prima che il tuo account venga temporaneamente bloccato.",
|
||||
"login.incorrect.credentials.error.attempts.text.2": "Se hai dimenticato la password, {resetLink}",
|
||||
"account.locked.out.message.2": "Per sicurezza, puoi {resetLink} prima di riprovare.",
|
||||
"login.incorrect.credentials.error.with.reset.link": "Il nome utente, l'e-mail o la password inseriti non sono corretti. Riprova o {resetLink}.",
|
||||
"login.page.title": "Accesso | {siteName}",
|
||||
"login.user.identity.label": "Nome utente o email ",
|
||||
"login.password.label": "Password",
|
||||
"sign.in.button": "Accedi",
|
||||
"sign.in.btn.pending.state": "Caricamento",
|
||||
"need.help.signing.in.collapsible.menu": "Hai bisogno di aiuto per l'accesso?",
|
||||
"forgot.password.link": "Ho dimenticato la mia password",
|
||||
"forgot.password": "Password dimenticata",
|
||||
"other.sign.in.issues": "Altri problemi legati all'accesso",
|
||||
"need.other.help.signing.in.collapsible.menu": "Hai bisogno di ulteriore aiuto per l'accesso?",
|
||||
"institution.login.button": "Credenziali dell'istituto/campus",
|
||||
"institution.login.page.title": "Accedi con le credenziali dell'istituzione/campus",
|
||||
"institution.login.page.back.button": "Torna all'accesso",
|
||||
"create.an.account": "Crea un account",
|
||||
"login.other.options.heading": "Oppure accedi con:",
|
||||
"non.compliant.password.title": "Abbiamo di recente modificato i requisiti per la password ",
|
||||
"non.compliant.password.message": "La tua password attuale non soddisfa i nuovi requisiti di sicurezza. Abbiamo appena inviato un messaggio di reimpostazione della password all'indirizzo e-mail associato a questo account. Grazie per averci aiutato a mantenere i tuoi dati al sicuro.",
|
||||
"account.locked.out.message.1": "Per proteggere il tuo account, è stato temporaneamente bloccato. Riprova tra 30 minuti.",
|
||||
"first.time.here": "È la prima volta che ci visiti?",
|
||||
"email.help.message": "L'indirizzo email che hai utilizzato per registrarti con edX.",
|
||||
"enterprise.login.btn.text": "Credenziali aziendali o scolastiche",
|
||||
"email.format.validation.message": "L'indirizzo email che hai fornito non è formattato correttamente. ",
|
||||
"username.or.email.format.validation.less.chars.message": "Il nome utente o l'e-mail deve contenere almeno 3 caratteri.",
|
||||
"email.validation.message": "Inserisci il tuo nome utente o e-mail",
|
||||
"password.validation.message": "I criteri della password non sono stati soddisfatti",
|
||||
"register.link": "Crea un account",
|
||||
"sign.in.heading": "Accedi",
|
||||
"account.activation.success.message.title": "Completato correttamente! Hai attivato il tuo account. ",
|
||||
"account.activation.success.message": "A breve ti invieremo avvisi e aggiornamenti via email relativi al corso a cui ti sei iscritto. Accedi per proseguire.",
|
||||
"account.activation.info.message": "Questo account è già stato attivato.",
|
||||
"account.activation.error.message.title": "Impossibile attivare il tuo account.",
|
||||
"account.activation.support.link": "contatta il supporto",
|
||||
"tpa.account.link": "{provider} account",
|
||||
"account.confirmation.success.message.title": "Successo! Hai confermato la tua email.",
|
||||
"account.confirmation.success.message": "Accedi per continuare.",
|
||||
"account.confirmation.info.message": "Questa email è già stata confermata.",
|
||||
"account.confirmation.error.message.title": "Impossibile confermare la tua email",
|
||||
"login.rate.limit.reached.message": "Troppi tentativi di login falliti. Riprova più tardi.",
|
||||
"login.failure.header.title": "Impossibile autorizzare il tuo accesso.",
|
||||
"contact.support.link": "contatta il supporto {platformName} ",
|
||||
"login.incorrect.credentials.error": "Il nome utente, l'e-mail o la password inseriti non sono corretti. Per favore riprova.",
|
||||
"login.failed.attempt.error": "Hai a disposizione altri {remainingAttempts} tentativi di accesso prima che il tuo account venga temporaneamente bloccato.",
|
||||
"login.locked.out.error.message": "Il tuo account è stato temporaneamente bloccato per motivi di sicurezza. Riprova tra {lockedOutPeriod} minuti.",
|
||||
"login.form.invalid.error.message": "Si prega di compilare i campi sottostanti.",
|
||||
"login.incorrect.credentials.error.reset.link.text": "reimposta la tua password",
|
||||
"login.incorrect.credentials.error.before.account.blocked.text": "clicca qui per ripristinarlo.",
|
||||
"password.security.nudge.title": "Sicurezza della password",
|
||||
"password.security.block.title": "È richiesta la modifica della password",
|
||||
"password.security.nudge.body": "Il nostro sistema ha rilevato che la tua password è vulnerabile. Ti consigliamo di cambiarlo in modo che il tuo account rimanga sicuro.",
|
||||
"password.security.block.body": "Il nostro sistema ha rilevato che la tua password è vulnerabile. Cambia la tua password in modo che il tuo account rimanga sicuro.",
|
||||
"password.security.close.button": "Chiudi",
|
||||
"password.security.redirect.to.reset.password.button": "Ripristina la tua password",
|
||||
"progressive.profiling.page.title": "Campi facoltativi | {siteName}",
|
||||
"progressive.profiling.page.heading": "Alcune domande per te ci aiuteranno a diventare più intelligenti.",
|
||||
"optional.fields.information.link": "Ulteriori informazioni su come utilizziamo queste informazioni.",
|
||||
"optional.fields.submit.button": "Invia",
|
||||
"optional.fields.skip.button": "Salta per ora",
|
||||
"optional.fields.next.button": "Next",
|
||||
"continue.to.platform": "Continua con {platformName}",
|
||||
"modal.title": "Grazie per averci fatto sapere.",
|
||||
"modal.description": "Puoi completare il tuo profilo nelle impostazioni in qualsiasi momento se cambi idea.",
|
||||
"welcome.page.error.heading": "Impossibile aggiornare il tuo profilo",
|
||||
"welcome.page.error.message": "Si è verificato un errore. Puoi completare il tuo profilo nelle impostazioni in qualsiasi momento.",
|
||||
"recommendation.page.title": "Recommendations| {siteName}",
|
||||
"recommendation.page.heading": "We have a few recommendations to get you started.",
|
||||
"recommendation.skip.button": "Skip for now",
|
||||
"register.page.title": "Registrazione | {siteName}",
|
||||
"registration.fullname.label": "Nome e Cognome",
|
||||
"registration.email.label": "Email",
|
||||
"registration.username.label": "Nome utente pubblico",
|
||||
"registration.password.label": "Password",
|
||||
"registration.country.label": "Paese/regione",
|
||||
"registration.opt.in.label": "Accetto che {siteName} possa inviarmi messaggi di marketing.",
|
||||
"help.text.name": "Questo nome verrà utilizzato per tutti i certificati conseguiti.",
|
||||
"help.text.username.1": "Il nome che ti identificherà nei tuoi corsi.",
|
||||
"help.text.username.2": "Questo non può essere modificato in seguito.",
|
||||
"help.text.email": "Per l'attivazione dell'account e aggiornamenti importanti",
|
||||
"create.account.for.free.button": "Crea un account gratis",
|
||||
"create.an.account.btn.pending.state": "Caricamento",
|
||||
"registration.other.options.heading": "Oppure registrati con:",
|
||||
"register.institution.login.button": "Credenziali dell'istituto/campus",
|
||||
"register.institution.login.page.title": "Registrati con le credenziali dell'istituzione/campus",
|
||||
"empty.name.field.error": "Inserisci il tuo nome e cognome",
|
||||
"empty.email.field.error": "Inserisci il tuo indirizzo email",
|
||||
"email.do.not.match": "Gli indirizzi email non corrispondono.",
|
||||
"empty.username.field.error": "Il nome utente deve essere compreso tra 2 e 30 caratteri",
|
||||
"empty.password.field.error": "I criteri della password non sono stati soddisfatti",
|
||||
"empty.country.field.error": "Seleziona il tuo paese o regione di residenza",
|
||||
"email.invalid.format.error": "Inserisci un indirizzo email valido",
|
||||
"email.ratelimit.less.chars.validation.message": "Email deve avere 3 caratteri.",
|
||||
"username.validation.message": "Il nome utente deve essere compreso tra 2 e 30 caratteri",
|
||||
"name.validation.message": "Inserisci un nome valido",
|
||||
"username.format.validation.message": "I nomi utente possono contenere solo lettere (AZ, az), numeri (0-9), trattini bassi (_) e trattini (-). I nomi utente non possono contenere spazi",
|
||||
"support.education.research": "Supportare la ricerca del livello di istruzione fornendo informazioni aggiuntive. (Facoltativo)",
|
||||
"registration.request.failure.header": "Impossibile creare il tuo account.",
|
||||
"registration.empty.form.submission.error": "Controlla le tue risposte e riprova.",
|
||||
"registration.request.server.error": "Si è verificato un errore. Prova ad aggiornare la pagina oppure verifica la connessione internet.",
|
||||
"registration.rate.limit.error": "Troppi tentativi di registrazione non riusciti. Prova di nuovo più tardi.",
|
||||
"registration.tpa.session.expired": "La registrazione mediante {provider} è andata in timeout.",
|
||||
"terms.of.service.and.honor.code": "Termini e Condizioni del Servizio",
|
||||
"privacy.policy": "Informativa sulla privacy",
|
||||
"honor.code": "Codice d'Onore",
|
||||
"terms.of.service": "Termini di Servizio",
|
||||
"registration.year.of.birth.label": "Anno di nascita (facoltativo)",
|
||||
"registration.field.gender.options.label": "Genere (facoltativo)",
|
||||
"registration.goals.label": "Dicci perché sei interessato a edX (facoltativo)",
|
||||
"registration.field.gender.options.f": "Femmina",
|
||||
"registration.field.gender.options.m": "Maschio",
|
||||
"registration.field.gender.options.o": "Altro/Preferisco non dire",
|
||||
"registration.field.education.levels.label": "Livello di istruzione più elevato raggiunto (opzionale) ",
|
||||
"registration.field.education.levels.p": "Dottorato",
|
||||
"registration.field.education.levels.m": "Laurea magistrale o titolo accademico professionale",
|
||||
"registration.field.education.levels.b": "Laurea di primo livello ",
|
||||
"registration.field.education.levels.a": "Diploma Professionale",
|
||||
"registration.field.education.levels.hs": "Scuola Superiore/Liceo",
|
||||
"registration.field.education.levels.jhs": "Scuola Media",
|
||||
"registration.field.education.levels.el": "Scuola Primaria/Elementare",
|
||||
"registration.field.education.levels.none": "Nessun livello educativo formale",
|
||||
"registration.field.education.levels.other": "Altro tipo di formazione",
|
||||
"registration.username.suggestion.label": "Suggerito:",
|
||||
"registration.using.tpa.form.heading": "Completa la creazione del tuo account",
|
||||
"did.you.mean.alert.text": "Intendevi",
|
||||
"register.page.terms.of.service": "Accetto il {platformName} {termsOfService}",
|
||||
"sign.in": "Accedi",
|
||||
"reset.password.page.title": "Ripristina password | {siteName}",
|
||||
"reset.password": "Resetta la password",
|
||||
"reset.password.page.instructions": "Immettere e confermare la nuova password. ",
|
||||
"new.password.label": "Nuova password",
|
||||
"confirm.password.label": "Conferma password",
|
||||
"passwords.do.not.match": "le passwords non corrispondono",
|
||||
"confirm.your.password": "Conferma la tua password",
|
||||
"forgot.password.confirmation.sign.in.link": "accedi",
|
||||
"reset.password.request.forgot.password.text": "Dimenticato la password",
|
||||
"reset.password.request.invalid.token.header": "Link di ripristino della password non valido",
|
||||
"reset.password.empty.new.password.field.error": "Immetti la nuova password.",
|
||||
"reset.password.failure.heading": "Impossibile ripristinare la tua password.",
|
||||
"reset.password.form.submission.error": "Controlla le tue risposte e riprova.",
|
||||
"reset.password.request.server.error": "Ripristino della password non riuscito",
|
||||
"reset.password.token.validation.sever.error": "Errore di convalida del token",
|
||||
"reset.server.rate.limit.error": "Troppe richieste.",
|
||||
"reset.password.success.heading": "Ripristino della password completato.",
|
||||
"reset.password.success": "La tua password è stata resettata. Accedi al tuo account.",
|
||||
"progressive.profiling.page.title": "Campi facoltativi | {siteName}",
|
||||
"progressive.profiling.page.heading": "Alcune domande per te ci aiuteranno a diventare più intelligenti.",
|
||||
"gender.options.label": "Genere (facoltativo)",
|
||||
"gender.options.f": "Femmina",
|
||||
"gender.options.m": "Maschio",
|
||||
"gender.options.o": "Altro/Preferisco non dire",
|
||||
"education.levels.label": "Livello di istruzione più elevato raggiunto (opzionale) ",
|
||||
"education.levels.p": "Dottorato",
|
||||
"education.levels.m": "Laurea magistrale o titolo accademico professionale",
|
||||
"education.levels.b": "Laurea di primo livello ",
|
||||
"education.levels.a": "Diploma Professionale",
|
||||
"education.levels.hs": "Scuola Superiore/Liceo",
|
||||
"education.levels.jhs": "Scuola Media",
|
||||
"education.levels.el": "Scuola Primaria/Elementare",
|
||||
"education.levels.none": "Nessun livello educativo formale",
|
||||
"education.levels.other": "Altro livello educativo",
|
||||
"year.of.birth.label": "Anno di nascita (facoltativo)",
|
||||
"optional.fields.information.link": "Ulteriori informazioni su come utilizziamo queste informazioni.",
|
||||
"optional.fields.submit.button": "Invia",
|
||||
"optional.fields.skip.button": "Salta per ora",
|
||||
"continue.to.platform": "Continua con {platformName}",
|
||||
"modal.title": "Grazie per averci fatto sapere.",
|
||||
"modal.description": "Puoi completare il tuo profilo nelle impostazioni in qualsiasi momento se cambi idea.",
|
||||
"welcome.page.error.heading": "Impossibile aggiornare il tuo profilo",
|
||||
"welcome.page.error.message": "Si è verificato un errore. Puoi completare il tuo profilo nelle impostazioni in qualsiasi momento."
|
||||
}
|
||||
231
src/i18n/messages/pt_PT.json
Normal file
231
src/i18n/messages/pt_PT.json
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"start.learning": "Começar a aprender",
|
||||
"with.site.name": "with {siteName}",
|
||||
"complete.your.profile.1": "Concluído",
|
||||
"complete.your.profile.2": "o seu perfil",
|
||||
"welcome.to.platform": "Bem vindo a {siteName}, {username}!",
|
||||
"institution.login.page.sub.heading": "Choose your institution from the list below",
|
||||
"forgot.password.confirmation.title": "Verifique o seu email",
|
||||
"forgot.password.confirmation.support.link": "contacto o suporte técnico",
|
||||
"forgot.password.confirmation.info": "Se não receber uma mensagem para alterar a palavra-passe após 1 minuto, verifique se introduziu o endereço de correio electrónico correcto, ou verifique a sua pasta de spam.",
|
||||
"logistration.sign.in": "Iniciar sessão",
|
||||
"logistration.register": "Registe-se",
|
||||
"internal.server.error.message": "Ocorreu um erro. Tente actualizar a página, ou verifique a sua ligação à Internet.",
|
||||
"server.ratelimit.error.message": "Ocorreu um erro devido a demasiados pedidos. Por favor, tente novamente após algum tempo.",
|
||||
"enterprisetpa.title.heading": "Gostaria de iniciar sessão usando as suas {providerName} credenciais?",
|
||||
"enterprisetpa.sso.button.title": "Inicie a sessão utilizando {providerName}",
|
||||
"enterprisetpa.login.button.text": "Mostre-me outras formas de iniciar sessão ou registar-se",
|
||||
"sso.sign.in.with": "Inicie sessão com {providerName}",
|
||||
"sso.create.account.using": "Criar conta usando {providerName}",
|
||||
"show.password": "Show password",
|
||||
"hide.password": "Hide password",
|
||||
"one.letter": "1 letter",
|
||||
"one.number": "1 number",
|
||||
"eight.characters": "8 characters",
|
||||
"password.sr.only.helping.text": "Password must contain at least 8 characters, at least one letter, and at least one number",
|
||||
"tpa.alert.heading": "Almost done!",
|
||||
"login.third.party.auth.account.not.linked": "Iniciou sessão com sucesso em {currentProvider}, mas a sua conta {currentProvider} não está vinculada a uma conta {platformName}. Para vincular as suas contas, inicie sessão através da sua palavra-passe em {platformName}.",
|
||||
"register.third.party.auth.account.not.linked": "You've successfully signed into {currentProvider}! We just need a little more information before you start learning with {platformName}.",
|
||||
"error.notfound.message": "A página que procura não está disponível ou há um erro no URL. Por favor, verifique o URL e tente novamente.",
|
||||
"forgot.password.confirmation.message": "We sent an email to {email} with instructions to reset your password.\n If you do not receive a password reset message after 1 minute, verify that you entered\n the correct email address, or check your spam folder. If you need further assistance, {supportLink}.",
|
||||
"forgot.password.page.title": "Esqueceu a Senha | {siteName}",
|
||||
"forgot.password.page.heading": "Reset password",
|
||||
"forgot.password.page.instructions": "Please enter your email address below and we will send you an email with instructions on how to reset your password.",
|
||||
"forgot.password.page.invalid.email.message": "Introduzir um endereço de correio electrónico válido",
|
||||
"forgot.password.page.email.field.label": "Email",
|
||||
"forgot.password.page.submit.button": "Submeter",
|
||||
"forgot.password.error.alert.title.": "We were unable to contact you.",
|
||||
"forgot.password.error.message.title": "Ocorreu um erro.",
|
||||
"forgot.password.request.in.progress.message": "O seu pedido anterior está a ser processado, por favor tente novamente dentro de momentos.",
|
||||
"forgot.password.empty.email.field.error": "Enter your email",
|
||||
"forgot.password.invalid.email.message": "O endereço de email fornecido não está formatado correctamente.",
|
||||
"forgot.password.email.help.text": "O endereço de e-mail que usou para se registar em {platformName}",
|
||||
"confirmation.message.title": "Verifique o seu email",
|
||||
"confirmation.support.link": "contact technical support",
|
||||
"need.help.sign.in.text": "Need help signing in?",
|
||||
"additional.help.text": "For additional help, contact {platformName} support at ",
|
||||
"sign.in.text": "Sign in",
|
||||
"extend.field.errors": "{emailError} below.",
|
||||
"invalid.token.heading": "Invalid password reset link",
|
||||
"invalid.token.error.message": "This password reset link is invalid. It may have been used already. Enter your email below to receive a new link.",
|
||||
"token.validation.rate.limit.error.heading": "Too many requests",
|
||||
"token.validation.rate.limit.error": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"token.validation.internal.sever.error.heading": "Token validation failure",
|
||||
"token.validation.internal.sever.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"internal.server.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"rate.limit.error": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"account.activation.error.message": "Alguma coisa correu mal, siga {supportLink} para resolver esta questão.",
|
||||
"login.inactive.user.error": "Para iniciar sessão, precisa ativar a sua conta. {lineBreak}\n {lineBreak} Acabámos de enviar um link de ativação para {email}. Se não receber um e-mail,\n verifique as suas pastas de spam ou {supportLink}.",
|
||||
"allowed.domain.login.error": "As {allowedDomain} user, You must login with your {allowedDomain} {tpaLink}.",
|
||||
"login.incorrect.credentials.error.attempts.text.1": "The username, email or password you entered is incorrect. You have {remainingAttempts} more sign in\n attempts before your account is temporarily locked.",
|
||||
"login.incorrect.credentials.error.attempts.text.2": "If you've forgotten your password, {resetLink}",
|
||||
"account.locked.out.message.2": "To be on the safe side, you can {resetLink} before trying again.",
|
||||
"login.incorrect.credentials.error.with.reset.link": "The username, email, or password you entered is incorrect. Please try again or {resetLink}.",
|
||||
"login.page.title": "Iniciar sessão | {siteName}",
|
||||
"login.user.identity.label": "Username or email",
|
||||
"login.password.label": "Password",
|
||||
"sign.in.button": "Iniciar Sessão",
|
||||
"sign.in.btn.pending.state": "Loading",
|
||||
"need.help.signing.in.collapsible.menu": "Precisa de ajuda para entrar?",
|
||||
"forgot.password.link": "Esqueci-me da minha palavra-passe",
|
||||
"forgot.password": "Forgot password",
|
||||
"other.sign.in.issues": "Outros problemas de inicio de sessão",
|
||||
"need.other.help.signing.in.collapsible.menu": "Precisa de outra ajuda para entrar?",
|
||||
"institution.login.button": "Institution/campus credentials",
|
||||
"institution.login.page.title": "Inicie sessão com credenciais de instituição/campus",
|
||||
"institution.login.page.back.button": "Voltar para iniciar sessão",
|
||||
"create.an.account": "Criar uma conta",
|
||||
"login.other.options.heading": "Or sign in with:",
|
||||
"non.compliant.password.title": "Recentemente mudámos os nossos requisitos de palavra-passe",
|
||||
"non.compliant.password.message": "Your current password does not meet the new security requirements. We just sent a password-reset message to the email address associated with this account. Thank you for helping us keep your data safe.",
|
||||
"account.locked.out.message.1": "To protect your account, it's been temporarily locked. Try again in 30 minutes.",
|
||||
"first.time.here": "Está a entrar pela primeira vez?",
|
||||
"email.help.message": "O endereço de e-mail que usou para se registrar no edX.",
|
||||
"enterprise.login.btn.text": "Company or school credentials",
|
||||
"email.format.validation.message": "O endereço de e-mail fornecido não está formatado correctamente.",
|
||||
"username.or.email.format.validation.less.chars.message": "Username or email must have at least 3 characters.",
|
||||
"email.validation.message": "Enter your username or email",
|
||||
"password.validation.message": "Password criteria has not been met",
|
||||
"register.link": "Criar uma conta",
|
||||
"sign.in.heading": "Iniciar Sessão",
|
||||
"account.activation.success.message.title": "Sucesso! Você ativou a sua conta.",
|
||||
"account.activation.success.message": "Receberá agora actualizações por e-mail e alertas nossos relacionados com os cursos em que está inscrito. Inicie a sessão para continuar.",
|
||||
"account.activation.info.message": "This account has already been activated.",
|
||||
"account.activation.error.message.title": "A sua conta não pôde ser ativada",
|
||||
"account.activation.support.link": "contato de suporte",
|
||||
"tpa.account.link": "{provider} account",
|
||||
"account.confirmation.success.message.title": "Success! You have confirmed your email.",
|
||||
"account.confirmation.success.message": "Sign in to continue.",
|
||||
"account.confirmation.info.message": "This email has already been confirmed.",
|
||||
"account.confirmation.error.message.title": "Your email could not be confirmed",
|
||||
"login.rate.limit.reached.message": "Muitas tentativas de login sem sucesso. Tente novamente mais tarde.",
|
||||
"login.failure.header.title": "O seu acesso não foi possível.",
|
||||
"contact.support.link": "contactar o suporte {platformName}",
|
||||
"login.incorrect.credentials.error": "The username, email, or password you entered is incorrect. Please try again.",
|
||||
"login.failed.attempt.error": "Tem mais {remainingAttempts} tentativas de inicio sessão antes que a sua conta seja temporariamente bloqueada.",
|
||||
"login.locked.out.error.message": "Para proteger a sua conta, esta foi temporariamente bloqueada. Tente novamente em {lockedOutPeriod} minutos.",
|
||||
"login.form.invalid.error.message": "Please fill in the fields below.",
|
||||
"login.incorrect.credentials.error.reset.link.text": "reset your password",
|
||||
"login.incorrect.credentials.error.before.account.blocked.text": "click here to reset it.",
|
||||
"password.security.nudge.title": "Password security",
|
||||
"password.security.block.title": "Password change required",
|
||||
"password.security.nudge.body": "Our system detected that your password is vulnerable. We recommend you change it so that your account stays secure.",
|
||||
"password.security.block.body": "Our system detected that your password is vulnerable. Change your password so that your account stays secure.",
|
||||
"password.security.close.button": "Close",
|
||||
"password.security.redirect.to.reset.password.button": "Reset your password",
|
||||
"progressive.profiling.page.title": "Optional Fields | {siteName}",
|
||||
"progressive.profiling.page.heading": "A few questions for you will help us get smarter.",
|
||||
"optional.fields.information.link": "Learn more about how we use this information.",
|
||||
"optional.fields.submit.button": "Submit",
|
||||
"optional.fields.skip.button": "Skip for now",
|
||||
"optional.fields.next.button": "Next",
|
||||
"continue.to.platform": "Continue to {platformName}",
|
||||
"modal.title": "Thanks for letting us know.",
|
||||
"modal.description": "You can complete your profile in settings at any time if you change your mind.",
|
||||
"welcome.page.error.heading": "We couldn't update your profile",
|
||||
"welcome.page.error.message": "An error occurred. You can complete your profile in settings at any time.",
|
||||
"recommendation.page.title": "Recommendations| {siteName}",
|
||||
"recommendation.page.heading": "We have a few recommendations to get you started.",
|
||||
"recommendation.skip.button": "Skip for now",
|
||||
"register.page.title": "Registar | {siteName}",
|
||||
"registration.fullname.label": "Full name",
|
||||
"registration.email.label": "Email",
|
||||
"registration.username.label": "Public username",
|
||||
"registration.password.label": "Password",
|
||||
"registration.country.label": "Country/Region",
|
||||
"registration.opt.in.label": "I agree that {siteName} may send me marketing messages.",
|
||||
"help.text.name": "This name will be used by any certificates that you earn.",
|
||||
"help.text.username.1": "The name that will identify you in your courses.",
|
||||
"help.text.username.2": "This can not be changed later.",
|
||||
"help.text.email": "For account activation and important updates",
|
||||
"create.account.for.free.button": "Create an account for free",
|
||||
"create.an.account.btn.pending.state": "Loading",
|
||||
"registration.other.options.heading": "Or register with:",
|
||||
"register.institution.login.button": "Institution/campus credentials",
|
||||
"register.institution.login.page.title": "Registo com credenciais da instituição/campus",
|
||||
"empty.name.field.error": "Enter your full name",
|
||||
"empty.email.field.error": "Enter your email",
|
||||
"email.do.not.match": "The email addresses do not match.",
|
||||
"empty.username.field.error": "Username must be between 2 and 30 characters",
|
||||
"empty.password.field.error": "Password criteria has not been met",
|
||||
"empty.country.field.error": "Select your country or region of residence",
|
||||
"email.invalid.format.error": "Enter a valid email address",
|
||||
"email.ratelimit.less.chars.validation.message": "O e-mail deve ter 3 carateres.",
|
||||
"username.validation.message": "Username must be between 2 and 30 characters",
|
||||
"name.validation.message": "Enter a valid name",
|
||||
"username.format.validation.message": "Usernames can only contain letters (A-Z, a-z), numerals (0-9), underscores (_), and hyphens (-). Usernames cannot contain spaces",
|
||||
"support.education.research": "Apoie a pesquisa em educação fornecendo informações adicionais. (Opcional)",
|
||||
"registration.request.failure.header": "Não foi possível criar a sua conta.",
|
||||
"registration.empty.form.submission.error": "Please check your responses and try again.",
|
||||
"registration.request.server.error": "Ocorreu um erro. Tente actualizar a página, ou verifique a sua ligação à Internet.",
|
||||
"registration.rate.limit.error": "Too many failed registration attempts. Try again later.",
|
||||
"registration.tpa.session.expired": "Registration using {provider} has timed out.",
|
||||
"terms.of.service.and.honor.code": "Termos de Serviço e Código de Honra",
|
||||
"privacy.policy": "Política de Privacidade",
|
||||
"honor.code": "Honor Code",
|
||||
"terms.of.service": "Terms of Service",
|
||||
"registration.year.of.birth.label": "Ano de Nascimento (opcional)",
|
||||
"registration.field.gender.options.label": "Género (opcional)",
|
||||
"registration.goals.label": "Diga-nos porque está interessado no edX (opcional)",
|
||||
"registration.field.gender.options.f": "Feminino",
|
||||
"registration.field.gender.options.m": "Masculino",
|
||||
"registration.field.gender.options.o": "Outros/Prefere não dizer",
|
||||
"registration.field.education.levels.label": "Nível mais elevado de escolaridade concluído (opcional)",
|
||||
"registration.field.education.levels.p": "Doutoramento",
|
||||
"registration.field.education.levels.m": "Mestrado ou Grau Profissional",
|
||||
"registration.field.education.levels.b": "Licenciatura",
|
||||
"registration.field.education.levels.a": "Pós-graduação",
|
||||
"registration.field.education.levels.hs": "Secundário",
|
||||
"registration.field.education.levels.jhs": "2ªciclo/3ºciclo",
|
||||
"registration.field.education.levels.el": "Primária",
|
||||
"registration.field.education.levels.none": "Sem estudos",
|
||||
"registration.field.education.levels.other": "Outra educação",
|
||||
"registration.username.suggestion.label": "Suggested:",
|
||||
"registration.using.tpa.form.heading": "Finish creating your account",
|
||||
"did.you.mean.alert.text": "Did you mean",
|
||||
"register.page.terms.of.service": "I agree to the {platformName} {termsOfService}",
|
||||
"sign.in": "Sign in",
|
||||
"reset.password.page.title": "Redefinir Palavra-passe | {siteName}",
|
||||
"reset.password": "Reset password",
|
||||
"reset.password.page.instructions": "Insira e confirme a sua nova palavra-passe.",
|
||||
"new.password.label": "New password",
|
||||
"confirm.password.label": "Confirm password",
|
||||
"passwords.do.not.match": "Passwords do not match",
|
||||
"confirm.your.password": "Confirm your password",
|
||||
"forgot.password.confirmation.sign.in.link": "inicie a sessão",
|
||||
"reset.password.request.forgot.password.text": "Esqueci-me da palavra-passe",
|
||||
"reset.password.request.invalid.token.header": "Link para Redefinir Palavra-passe inválido",
|
||||
"reset.password.empty.new.password.field.error": "Por favor, introduza a sua nova palavra-passe.",
|
||||
"reset.password.failure.heading": "We couldn't reset your password.",
|
||||
"reset.password.form.submission.error": "Please check your responses and try again.",
|
||||
"reset.password.request.server.error": "Falha na redefinição da palavra-passe",
|
||||
"reset.password.token.validation.sever.error": "Falha na validação do Token",
|
||||
"reset.server.rate.limit.error": "Too many requests.",
|
||||
"reset.password.success.heading": "Password reset complete.",
|
||||
"reset.password.success": "Your password has been reset. Sign in to your account.",
|
||||
"progressive.profiling.page.title": "Optional Fields | {siteName}",
|
||||
"progressive.profiling.page.heading": "A few questions for you will help us get smarter.",
|
||||
"gender.options.label": "Gender (optional)",
|
||||
"gender.options.f": "Female",
|
||||
"gender.options.m": "Male",
|
||||
"gender.options.o": "Other/Prefer not to say",
|
||||
"education.levels.label": "Highest level of education completed (optional)",
|
||||
"education.levels.p": "Doctorate",
|
||||
"education.levels.m": "Master's or professional degree",
|
||||
"education.levels.b": "Bachelor's degree",
|
||||
"education.levels.a": "Associate's degree",
|
||||
"education.levels.hs": "Secondary/high school",
|
||||
"education.levels.jhs": "Junior secondary/junior high/middle school",
|
||||
"education.levels.el": "Elementary/primary school",
|
||||
"education.levels.none": "No formal education",
|
||||
"education.levels.other": "Other education",
|
||||
"year.of.birth.label": "Year of birth (optional)",
|
||||
"optional.fields.information.link": "Learn more about how we use this information.",
|
||||
"optional.fields.submit.button": "Submit",
|
||||
"optional.fields.skip.button": "Skip for now",
|
||||
"continue.to.platform": "Continue to {platformName}",
|
||||
"modal.title": "Thanks for letting us know.",
|
||||
"modal.description": "You can complete your profile in settings at any time if you change your mind.",
|
||||
"welcome.page.error.heading": "We couldn't update your profile",
|
||||
"welcome.page.error.message": "An error occurred. You can complete your profile in settings at any time."
|
||||
}
|
||||
@@ -1 +1,231 @@
|
||||
{}
|
||||
{
|
||||
"start.learning": "Start learning",
|
||||
"with.site.name": "with {siteName}",
|
||||
"complete.your.profile.1": "Complete",
|
||||
"complete.your.profile.2": "your profile",
|
||||
"welcome.to.platform": "Welcome to {siteName}, {username}!",
|
||||
"institution.login.page.sub.heading": "Choose your institution from the list below",
|
||||
"forgot.password.confirmation.title": "Check your email",
|
||||
"forgot.password.confirmation.support.link": "contact technical support",
|
||||
"forgot.password.confirmation.info": "If you do not receive a password reset message after 1 minute, verify that you entered the correct email address, or check your spam folder.",
|
||||
"logistration.sign.in": "Sign in",
|
||||
"logistration.register": "Register",
|
||||
"internal.server.error.message": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"server.ratelimit.error.message": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"enterprisetpa.title.heading": "Would you like to sign in using your {providerName} credentials?",
|
||||
"enterprisetpa.sso.button.title": "Sign in using {providerName}",
|
||||
"enterprisetpa.login.button.text": "Show me other ways to sign in or register",
|
||||
"sso.sign.in.with": "Sign in with {providerName}",
|
||||
"sso.create.account.using": "Create account using {providerName}",
|
||||
"show.password": "Show password",
|
||||
"hide.password": "Hide password",
|
||||
"one.letter": "1 letter",
|
||||
"one.number": "1 number",
|
||||
"eight.characters": "8 characters",
|
||||
"password.sr.only.helping.text": "Password must contain at least 8 characters, at least one letter, and at least one number",
|
||||
"tpa.alert.heading": "Almost done!",
|
||||
"login.third.party.auth.account.not.linked": "You have successfully signed into {currentProvider}, but your {currentProvider} account does not have a linked {platformName} account. To link your accounts, sign in now using your {platformName} password.",
|
||||
"register.third.party.auth.account.not.linked": "You've successfully signed into {currentProvider}! We just need a little more information before you start learning with {platformName}.",
|
||||
"error.notfound.message": "The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again.",
|
||||
"forgot.password.confirmation.message": "We sent an email to {email} with instructions to reset your password.\n If you do not receive a password reset message after 1 minute, verify that you entered\n the correct email address, or check your spam folder. If you need further assistance, {supportLink}.",
|
||||
"forgot.password.page.title": "Forgot Password | {siteName}",
|
||||
"forgot.password.page.heading": "Reset password",
|
||||
"forgot.password.page.instructions": "Please enter your email address below and we will send you an email with instructions on how to reset your password.",
|
||||
"forgot.password.page.invalid.email.message": "Enter a valid email address",
|
||||
"forgot.password.page.email.field.label": "Email",
|
||||
"forgot.password.page.submit.button": "Submit",
|
||||
"forgot.password.error.alert.title.": "We were unable to contact you.",
|
||||
"forgot.password.error.message.title": "An error occurred.",
|
||||
"forgot.password.request.in.progress.message": "Your previous request is in progress, please try again in a few moments.",
|
||||
"forgot.password.empty.email.field.error": "Enter your email",
|
||||
"forgot.password.invalid.email.message": "The email address you've provided isn't formatted correctly.",
|
||||
"forgot.password.email.help.text": "The email address you used to register with {platformName}",
|
||||
"confirmation.message.title": "Check your email",
|
||||
"confirmation.support.link": "contact technical support",
|
||||
"need.help.sign.in.text": "Need help signing in?",
|
||||
"additional.help.text": "For additional help, contact {platformName} support at ",
|
||||
"sign.in.text": "Sign in",
|
||||
"extend.field.errors": "{emailError} below.",
|
||||
"invalid.token.heading": "Invalid password reset link",
|
||||
"invalid.token.error.message": "This password reset link is invalid. It may have been used already. Enter your email below to receive a new link.",
|
||||
"token.validation.rate.limit.error.heading": "Too many requests",
|
||||
"token.validation.rate.limit.error": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"token.validation.internal.sever.error.heading": "Token validation failure",
|
||||
"token.validation.internal.sever.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"internal.server.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"rate.limit.error": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"account.activation.error.message": "Something went wrong, please {supportLink} to resolve this issue.",
|
||||
"login.inactive.user.error": "In order to sign in, you need to activate your account.{lineBreak}\n {lineBreak}We just sent an activation link to {email}. If you do not receive an email,\n check your spam folders or {supportLink}.",
|
||||
"allowed.domain.login.error": "As {allowedDomain} user, You must login with your {allowedDomain} {tpaLink}.",
|
||||
"login.incorrect.credentials.error.attempts.text.1": "The username, email or password you entered is incorrect. You have {remainingAttempts} more sign in\n attempts before your account is temporarily locked.",
|
||||
"login.incorrect.credentials.error.attempts.text.2": "If you've forgotten your password, {resetLink}",
|
||||
"account.locked.out.message.2": "To be on the safe side, you can {resetLink} before trying again.",
|
||||
"login.incorrect.credentials.error.with.reset.link": "The username, email, or password you entered is incorrect. Please try again or {resetLink}.",
|
||||
"login.page.title": "Login | {siteName}",
|
||||
"login.user.identity.label": "Username or email",
|
||||
"login.password.label": "Password",
|
||||
"sign.in.button": "Sign in",
|
||||
"sign.in.btn.pending.state": "Loading",
|
||||
"need.help.signing.in.collapsible.menu": "Need help signing in?",
|
||||
"forgot.password.link": "Forgot my password",
|
||||
"forgot.password": "Forgot password",
|
||||
"other.sign.in.issues": "Other sign in issues",
|
||||
"need.other.help.signing.in.collapsible.menu": "Need other help signing in?",
|
||||
"institution.login.button": "Institution/campus credentials",
|
||||
"institution.login.page.title": "Sign in with institution/campus credentials",
|
||||
"institution.login.page.back.button": "Back to sign in",
|
||||
"create.an.account": "Create an account",
|
||||
"login.other.options.heading": "Or sign in with:",
|
||||
"non.compliant.password.title": "We recently changed our password requirements",
|
||||
"non.compliant.password.message": "Your current password does not meet the new security requirements. We just sent a password-reset message to the email address associated with this account. Thank you for helping us keep your data safe.",
|
||||
"account.locked.out.message.1": "To protect your account, it's been temporarily locked. Try again in 30 minutes.",
|
||||
"first.time.here": "First time here?",
|
||||
"email.help.message": "The email address you used to register with edX.",
|
||||
"enterprise.login.btn.text": "Company or school credentials",
|
||||
"email.format.validation.message": "The email address you've provided isn't formatted correctly.",
|
||||
"username.or.email.format.validation.less.chars.message": "Username or email must have at least 3 characters.",
|
||||
"email.validation.message": "Enter your username or email",
|
||||
"password.validation.message": "Password criteria has not been met",
|
||||
"register.link": "Create an account",
|
||||
"sign.in.heading": "Sign in",
|
||||
"account.activation.success.message.title": "Success! You have activated your account.",
|
||||
"account.activation.success.message": "You will now receive email updates and alerts from us related to the courses you are enrolled in. Sign in to continue.",
|
||||
"account.activation.info.message": "This account has already been activated.",
|
||||
"account.activation.error.message.title": "Your account could not be activated",
|
||||
"account.activation.support.link": "contact support",
|
||||
"tpa.account.link": "{provider} account",
|
||||
"account.confirmation.success.message.title": "Success! You have confirmed your email.",
|
||||
"account.confirmation.success.message": "Sign in to continue.",
|
||||
"account.confirmation.info.message": "This email has already been confirmed.",
|
||||
"account.confirmation.error.message.title": "Your email could not be confirmed",
|
||||
"login.rate.limit.reached.message": "Too many failed login attempts. Try again later.",
|
||||
"login.failure.header.title": "We couldn't sign you in.",
|
||||
"contact.support.link": "contact {platformName} support",
|
||||
"login.incorrect.credentials.error": "The username, email, or password you entered is incorrect. Please try again.",
|
||||
"login.failed.attempt.error": "You have {remainingAttempts} more sign in attempts before your account is temporarily locked.",
|
||||
"login.locked.out.error.message": "To protect your account, it’s been temporarily locked. Try again in {lockedOutPeriod} minutes.",
|
||||
"login.form.invalid.error.message": "Please fill in the fields below.",
|
||||
"login.incorrect.credentials.error.reset.link.text": "reset your password",
|
||||
"login.incorrect.credentials.error.before.account.blocked.text": "click here to reset it.",
|
||||
"password.security.nudge.title": "Password security",
|
||||
"password.security.block.title": "Password change required",
|
||||
"password.security.nudge.body": "Our system detected that your password is vulnerable. We recommend you change it so that your account stays secure.",
|
||||
"password.security.block.body": "Our system detected that your password is vulnerable. Change your password so that your account stays secure.",
|
||||
"password.security.close.button": "Close",
|
||||
"password.security.redirect.to.reset.password.button": "Reset your password",
|
||||
"progressive.profiling.page.title": "Optional Fields | {siteName}",
|
||||
"progressive.profiling.page.heading": "A few questions for you will help us get smarter.",
|
||||
"optional.fields.information.link": "Learn more about how we use this information.",
|
||||
"optional.fields.submit.button": "Submit",
|
||||
"optional.fields.skip.button": "Skip for now",
|
||||
"optional.fields.next.button": "Next",
|
||||
"continue.to.platform": "Continue to {platformName}",
|
||||
"modal.title": "Thanks for letting us know.",
|
||||
"modal.description": "You can complete your profile in settings at any time if you change your mind.",
|
||||
"welcome.page.error.heading": "We couldn't update your profile",
|
||||
"welcome.page.error.message": "An error occurred. You can complete your profile in settings at any time.",
|
||||
"recommendation.page.title": "Recommendations| {siteName}",
|
||||
"recommendation.page.heading": "We have a few recommendations to get you started.",
|
||||
"recommendation.skip.button": "Skip for now",
|
||||
"register.page.title": "Register | {siteName}",
|
||||
"registration.fullname.label": "Full name",
|
||||
"registration.email.label": "Email",
|
||||
"registration.username.label": "Public username",
|
||||
"registration.password.label": "Password",
|
||||
"registration.country.label": "Country/Region",
|
||||
"registration.opt.in.label": "I agree that {siteName} may send me marketing messages.",
|
||||
"help.text.name": "This name will be used by any certificates that you earn.",
|
||||
"help.text.username.1": "The name that will identify you in your courses.",
|
||||
"help.text.username.2": "This can not be changed later.",
|
||||
"help.text.email": "For account activation and important updates",
|
||||
"create.account.for.free.button": "Create an account for free",
|
||||
"create.an.account.btn.pending.state": "Loading",
|
||||
"registration.other.options.heading": "Or register with:",
|
||||
"register.institution.login.button": "Institution/campus credentials",
|
||||
"register.institution.login.page.title": "Register with institution/campus credentials",
|
||||
"empty.name.field.error": "Enter your full name",
|
||||
"empty.email.field.error": "Enter your email",
|
||||
"email.do.not.match": "The email addresses do not match.",
|
||||
"empty.username.field.error": "Username must be between 2 and 30 characters",
|
||||
"empty.password.field.error": "Password criteria has not been met",
|
||||
"empty.country.field.error": "Select your country or region of residence",
|
||||
"email.invalid.format.error": "Enter a valid email address",
|
||||
"email.ratelimit.less.chars.validation.message": "Email must have 3 characters.",
|
||||
"username.validation.message": "Username must be between 2 and 30 characters",
|
||||
"name.validation.message": "Enter a valid name",
|
||||
"username.format.validation.message": "Usernames can only contain letters (A-Z, a-z), numerals (0-9), underscores (_), and hyphens (-). Usernames cannot contain spaces",
|
||||
"support.education.research": "Support education research by providing additional information. (Optional)",
|
||||
"registration.request.failure.header": "We couldn't create your account.",
|
||||
"registration.empty.form.submission.error": "Please check your responses and try again.",
|
||||
"registration.request.server.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"registration.rate.limit.error": "Too many failed registration attempts. Try again later.",
|
||||
"registration.tpa.session.expired": "Registration using {provider} has timed out.",
|
||||
"terms.of.service.and.honor.code": "Terms of Service and Honor Code",
|
||||
"privacy.policy": "Privacy Policy",
|
||||
"honor.code": "Honor Code",
|
||||
"terms.of.service": "Terms of Service",
|
||||
"registration.year.of.birth.label": "Year of birth (optional)",
|
||||
"registration.field.gender.options.label": "Gender (optional)",
|
||||
"registration.goals.label": "Tell us why you're interested in edX (optional)",
|
||||
"registration.field.gender.options.f": "Female",
|
||||
"registration.field.gender.options.m": "Male",
|
||||
"registration.field.gender.options.o": "Other/Prefer not to say",
|
||||
"registration.field.education.levels.label": "Highest level of education completed (optional)",
|
||||
"registration.field.education.levels.p": "Doctorate",
|
||||
"registration.field.education.levels.m": "Master's or professional degree",
|
||||
"registration.field.education.levels.b": "Bachelor's degree",
|
||||
"registration.field.education.levels.a": "Associate's degree",
|
||||
"registration.field.education.levels.hs": "Secondary/high school",
|
||||
"registration.field.education.levels.jhs": "Junior secondary/junior high/middle school",
|
||||
"registration.field.education.levels.el": "Elementary/primary school",
|
||||
"registration.field.education.levels.none": "No formal education",
|
||||
"registration.field.education.levels.other": "Other education",
|
||||
"registration.username.suggestion.label": "Suggested:",
|
||||
"registration.using.tpa.form.heading": "Finish creating your account",
|
||||
"did.you.mean.alert.text": "Did you mean",
|
||||
"register.page.terms.of.service": "I agree to the {platformName} {termsOfService}",
|
||||
"sign.in": "Sign in",
|
||||
"reset.password.page.title": "Reset Password | {siteName}",
|
||||
"reset.password": "Reset password",
|
||||
"reset.password.page.instructions": "Enter and confirm your new password.",
|
||||
"new.password.label": "New password",
|
||||
"confirm.password.label": "Confirm password",
|
||||
"passwords.do.not.match": "Passwords do not match",
|
||||
"confirm.your.password": "Confirm your password",
|
||||
"forgot.password.confirmation.sign.in.link": "sign in",
|
||||
"reset.password.request.forgot.password.text": "Forgot password",
|
||||
"reset.password.request.invalid.token.header": "Invalid password reset link",
|
||||
"reset.password.empty.new.password.field.error": "Please enter your new password.",
|
||||
"reset.password.failure.heading": "We couldn't reset your password.",
|
||||
"reset.password.form.submission.error": "Please check your responses and try again.",
|
||||
"reset.password.request.server.error": "Failed to reset password",
|
||||
"reset.password.token.validation.sever.error": "Token validation failure",
|
||||
"reset.server.rate.limit.error": "Too many requests.",
|
||||
"reset.password.success.heading": "Password reset complete.",
|
||||
"reset.password.success": "Your password has been reset. Sign in to your account.",
|
||||
"progressive.profiling.page.title": "Optional Fields | {siteName}",
|
||||
"progressive.profiling.page.heading": "A few questions for you will help us get smarter.",
|
||||
"gender.options.label": "Gender (optional)",
|
||||
"gender.options.f": "Female",
|
||||
"gender.options.m": "Male",
|
||||
"gender.options.o": "Other/Prefer not to say",
|
||||
"education.levels.label": "Highest level of education completed (optional)",
|
||||
"education.levels.p": "Doctorate",
|
||||
"education.levels.m": "Master's or professional degree",
|
||||
"education.levels.b": "Bachelor's degree",
|
||||
"education.levels.a": "Associate's degree",
|
||||
"education.levels.hs": "Secondary/high school",
|
||||
"education.levels.jhs": "Junior secondary/junior high/middle school",
|
||||
"education.levels.el": "Elementary/primary school",
|
||||
"education.levels.none": "No formal education",
|
||||
"education.levels.other": "Other education",
|
||||
"year.of.birth.label": "Year of birth (optional)",
|
||||
"optional.fields.information.link": "Learn more about how we use this information.",
|
||||
"optional.fields.submit.button": "Submit",
|
||||
"optional.fields.skip.button": "Skip for now",
|
||||
"continue.to.platform": "Continue to {platformName}",
|
||||
"modal.title": "Thanks for letting us know.",
|
||||
"modal.description": "You can complete your profile in settings at any time if you change your mind.",
|
||||
"welcome.page.error.heading": "We couldn't update your profile",
|
||||
"welcome.page.error.message": "An error occurred. You can complete your profile in settings at any time."
|
||||
}
|
||||
@@ -1 +1,231 @@
|
||||
{}
|
||||
{
|
||||
"start.learning": "Start learning",
|
||||
"with.site.name": "with {siteName}",
|
||||
"complete.your.profile.1": "Complete",
|
||||
"complete.your.profile.2": "your profile",
|
||||
"welcome.to.platform": "Welcome to {siteName}, {username}!",
|
||||
"institution.login.page.sub.heading": "Choose your institution from the list below",
|
||||
"forgot.password.confirmation.title": "Check your email",
|
||||
"forgot.password.confirmation.support.link": "contact technical support",
|
||||
"forgot.password.confirmation.info": "If you do not receive a password reset message after 1 minute, verify that you entered the correct email address, or check your spam folder.",
|
||||
"logistration.sign.in": "Sign in",
|
||||
"logistration.register": "Register",
|
||||
"internal.server.error.message": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"server.ratelimit.error.message": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"enterprisetpa.title.heading": "Would you like to sign in using your {providerName} credentials?",
|
||||
"enterprisetpa.sso.button.title": "Sign in using {providerName}",
|
||||
"enterprisetpa.login.button.text": "Show me other ways to sign in or register",
|
||||
"sso.sign.in.with": "Sign in with {providerName}",
|
||||
"sso.create.account.using": "Create account using {providerName}",
|
||||
"show.password": "Show password",
|
||||
"hide.password": "Hide password",
|
||||
"one.letter": "1 letter",
|
||||
"one.number": "1 number",
|
||||
"eight.characters": "8 characters",
|
||||
"password.sr.only.helping.text": "Password must contain at least 8 characters, at least one letter, and at least one number",
|
||||
"tpa.alert.heading": "Almost done!",
|
||||
"login.third.party.auth.account.not.linked": "You have successfully signed into {currentProvider}, but your {currentProvider} account does not have a linked {platformName} account. To link your accounts, sign in now using your {platformName} password.",
|
||||
"register.third.party.auth.account.not.linked": "You've successfully signed into {currentProvider}! We just need a little more information before you start learning with {platformName}.",
|
||||
"error.notfound.message": "The page you're looking for is unavailable or there's an error in the URL. Please check the URL and try again.",
|
||||
"forgot.password.confirmation.message": "We sent an email to {email} with instructions to reset your password.\n If you do not receive a password reset message after 1 minute, verify that you entered\n the correct email address, or check your spam folder. If you need further assistance, {supportLink}.",
|
||||
"forgot.password.page.title": "Forgot Password | {siteName}",
|
||||
"forgot.password.page.heading": "Reset password",
|
||||
"forgot.password.page.instructions": "Please enter your email address below and we will send you an email with instructions on how to reset your password.",
|
||||
"forgot.password.page.invalid.email.message": "Enter a valid email address",
|
||||
"forgot.password.page.email.field.label": "Email",
|
||||
"forgot.password.page.submit.button": "Submit",
|
||||
"forgot.password.error.alert.title.": "We were unable to contact you.",
|
||||
"forgot.password.error.message.title": "An error occurred.",
|
||||
"forgot.password.request.in.progress.message": "Your previous request is in progress, please try again in a few moments.",
|
||||
"forgot.password.empty.email.field.error": "Enter your email",
|
||||
"forgot.password.invalid.email.message": "The email address you've provided isn't formatted correctly.",
|
||||
"forgot.password.email.help.text": "The email address you used to register with {platformName}",
|
||||
"confirmation.message.title": "Check your email",
|
||||
"confirmation.support.link": "contact technical support",
|
||||
"need.help.sign.in.text": "Need help signing in?",
|
||||
"additional.help.text": "For additional help, contact {platformName} support at ",
|
||||
"sign.in.text": "Sign in",
|
||||
"extend.field.errors": "{emailError} below.",
|
||||
"invalid.token.heading": "Invalid password reset link",
|
||||
"invalid.token.error.message": "This password reset link is invalid. It may have been used already. Enter your email below to receive a new link.",
|
||||
"token.validation.rate.limit.error.heading": "Too many requests",
|
||||
"token.validation.rate.limit.error": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"token.validation.internal.sever.error.heading": "Token validation failure",
|
||||
"token.validation.internal.sever.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"internal.server.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"rate.limit.error": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"account.activation.error.message": "Something went wrong, please {supportLink} to resolve this issue.",
|
||||
"login.inactive.user.error": "In order to sign in, you need to activate your account.{lineBreak}\n {lineBreak}We just sent an activation link to {email}. If you do not receive an email,\n check your spam folders or {supportLink}.",
|
||||
"allowed.domain.login.error": "As {allowedDomain} user, You must login with your {allowedDomain} {tpaLink}.",
|
||||
"login.incorrect.credentials.error.attempts.text.1": "The username, email or password you entered is incorrect. You have {remainingAttempts} more sign in\n attempts before your account is temporarily locked.",
|
||||
"login.incorrect.credentials.error.attempts.text.2": "If you've forgotten your password, {resetLink}",
|
||||
"account.locked.out.message.2": "To be on the safe side, you can {resetLink} before trying again.",
|
||||
"login.incorrect.credentials.error.with.reset.link": "The username, email, or password you entered is incorrect. Please try again or {resetLink}.",
|
||||
"login.page.title": "Login | {siteName}",
|
||||
"login.user.identity.label": "Username or email",
|
||||
"login.password.label": "Password",
|
||||
"sign.in.button": "Sign in",
|
||||
"sign.in.btn.pending.state": "Loading",
|
||||
"need.help.signing.in.collapsible.menu": "Need help signing in?",
|
||||
"forgot.password.link": "Forgot my password",
|
||||
"forgot.password": "Forgot password",
|
||||
"other.sign.in.issues": "Other sign in issues",
|
||||
"need.other.help.signing.in.collapsible.menu": "Need other help signing in?",
|
||||
"institution.login.button": "Institution/campus credentials",
|
||||
"institution.login.page.title": "Sign in with institution/campus credentials",
|
||||
"institution.login.page.back.button": "Back to sign in",
|
||||
"create.an.account": "Create an account",
|
||||
"login.other.options.heading": "Or sign in with:",
|
||||
"non.compliant.password.title": "We recently changed our password requirements",
|
||||
"non.compliant.password.message": "Your current password does not meet the new security requirements. We just sent a password-reset message to the email address associated with this account. Thank you for helping us keep your data safe.",
|
||||
"account.locked.out.message.1": "To protect your account, it's been temporarily locked. Try again in 30 minutes.",
|
||||
"first.time.here": "First time here?",
|
||||
"email.help.message": "The email address you used to register with edX.",
|
||||
"enterprise.login.btn.text": "Company or school credentials",
|
||||
"email.format.validation.message": "The email address you've provided isn't formatted correctly.",
|
||||
"username.or.email.format.validation.less.chars.message": "Username or email must have at least 3 characters.",
|
||||
"email.validation.message": "Enter your username or email",
|
||||
"password.validation.message": "Password criteria has not been met",
|
||||
"register.link": "Create an account",
|
||||
"sign.in.heading": "Sign in",
|
||||
"account.activation.success.message.title": "Success! You have activated your account.",
|
||||
"account.activation.success.message": "You will now receive email updates and alerts from us related to the courses you are enrolled in. Sign in to continue.",
|
||||
"account.activation.info.message": "This account has already been activated.",
|
||||
"account.activation.error.message.title": "Your account could not be activated",
|
||||
"account.activation.support.link": "contact support",
|
||||
"tpa.account.link": "{provider} account",
|
||||
"account.confirmation.success.message.title": "Success! You have confirmed your email.",
|
||||
"account.confirmation.success.message": "Sign in to continue.",
|
||||
"account.confirmation.info.message": "This email has already been confirmed.",
|
||||
"account.confirmation.error.message.title": "Your email could not be confirmed",
|
||||
"login.rate.limit.reached.message": "Too many failed login attempts. Try again later.",
|
||||
"login.failure.header.title": "We couldn't sign you in.",
|
||||
"contact.support.link": "contact {platformName} support",
|
||||
"login.incorrect.credentials.error": "The username, email, or password you entered is incorrect. Please try again.",
|
||||
"login.failed.attempt.error": "You have {remainingAttempts} more sign in attempts before your account is temporarily locked.",
|
||||
"login.locked.out.error.message": "To protect your account, it’s been temporarily locked. Try again in {lockedOutPeriod} minutes.",
|
||||
"login.form.invalid.error.message": "Please fill in the fields below.",
|
||||
"login.incorrect.credentials.error.reset.link.text": "reset your password",
|
||||
"login.incorrect.credentials.error.before.account.blocked.text": "click here to reset it.",
|
||||
"password.security.nudge.title": "Password security",
|
||||
"password.security.block.title": "Password change required",
|
||||
"password.security.nudge.body": "Our system detected that your password is vulnerable. We recommend you change it so that your account stays secure.",
|
||||
"password.security.block.body": "Our system detected that your password is vulnerable. Change your password so that your account stays secure.",
|
||||
"password.security.close.button": "Close",
|
||||
"password.security.redirect.to.reset.password.button": "Reset your password",
|
||||
"progressive.profiling.page.title": "Optional Fields | {siteName}",
|
||||
"progressive.profiling.page.heading": "A few questions for you will help us get smarter.",
|
||||
"optional.fields.information.link": "Learn more about how we use this information.",
|
||||
"optional.fields.submit.button": "Submit",
|
||||
"optional.fields.skip.button": "Skip for now",
|
||||
"optional.fields.next.button": "Next",
|
||||
"continue.to.platform": "Continue to {platformName}",
|
||||
"modal.title": "Thanks for letting us know.",
|
||||
"modal.description": "You can complete your profile in settings at any time if you change your mind.",
|
||||
"welcome.page.error.heading": "We couldn't update your profile",
|
||||
"welcome.page.error.message": "An error occurred. You can complete your profile in settings at any time.",
|
||||
"recommendation.page.title": "Recommendations| {siteName}",
|
||||
"recommendation.page.heading": "We have a few recommendations to get you started.",
|
||||
"recommendation.skip.button": "Skip for now",
|
||||
"register.page.title": "Register | {siteName}",
|
||||
"registration.fullname.label": "Full name",
|
||||
"registration.email.label": "Email",
|
||||
"registration.username.label": "Public username",
|
||||
"registration.password.label": "Password",
|
||||
"registration.country.label": "Country/Region",
|
||||
"registration.opt.in.label": "I agree that {siteName} may send me marketing messages.",
|
||||
"help.text.name": "This name will be used by any certificates that you earn.",
|
||||
"help.text.username.1": "The name that will identify you in your courses.",
|
||||
"help.text.username.2": "This can not be changed later.",
|
||||
"help.text.email": "For account activation and important updates",
|
||||
"create.account.for.free.button": "Create an account for free",
|
||||
"create.an.account.btn.pending.state": "Loading",
|
||||
"registration.other.options.heading": "Or register with:",
|
||||
"register.institution.login.button": "Institution/campus credentials",
|
||||
"register.institution.login.page.title": "Register with institution/campus credentials",
|
||||
"empty.name.field.error": "Enter your full name",
|
||||
"empty.email.field.error": "Enter your email",
|
||||
"email.do.not.match": "The email addresses do not match.",
|
||||
"empty.username.field.error": "Username must be between 2 and 30 characters",
|
||||
"empty.password.field.error": "Password criteria has not been met",
|
||||
"empty.country.field.error": "Select your country or region of residence",
|
||||
"email.invalid.format.error": "Enter a valid email address",
|
||||
"email.ratelimit.less.chars.validation.message": "Email must have 3 characters.",
|
||||
"username.validation.message": "Username must be between 2 and 30 characters",
|
||||
"name.validation.message": "Enter a valid name",
|
||||
"username.format.validation.message": "Usernames can only contain letters (A-Z, a-z), numerals (0-9), underscores (_), and hyphens (-). Usernames cannot contain spaces",
|
||||
"support.education.research": "Support education research by providing additional information. (Optional)",
|
||||
"registration.request.failure.header": "We couldn't create your account.",
|
||||
"registration.empty.form.submission.error": "Please check your responses and try again.",
|
||||
"registration.request.server.error": "An error has occurred. Try refreshing the page, or check your internet connection.",
|
||||
"registration.rate.limit.error": "Too many failed registration attempts. Try again later.",
|
||||
"registration.tpa.session.expired": "Registration using {provider} has timed out.",
|
||||
"terms.of.service.and.honor.code": "Terms of Service and Honor Code",
|
||||
"privacy.policy": "Privacy Policy",
|
||||
"honor.code": "Honor Code",
|
||||
"terms.of.service": "Terms of Service",
|
||||
"registration.year.of.birth.label": "Year of birth (optional)",
|
||||
"registration.field.gender.options.label": "Gender (optional)",
|
||||
"registration.goals.label": "Tell us why you're interested in edX (optional)",
|
||||
"registration.field.gender.options.f": "Female",
|
||||
"registration.field.gender.options.m": "Male",
|
||||
"registration.field.gender.options.o": "Other/Prefer not to say",
|
||||
"registration.field.education.levels.label": "Highest level of education completed (optional)",
|
||||
"registration.field.education.levels.p": "Doctorate",
|
||||
"registration.field.education.levels.m": "Master's or professional degree",
|
||||
"registration.field.education.levels.b": "Bachelor's degree",
|
||||
"registration.field.education.levels.a": "Associate's degree",
|
||||
"registration.field.education.levels.hs": "Secondary/high school",
|
||||
"registration.field.education.levels.jhs": "Junior secondary/junior high/middle school",
|
||||
"registration.field.education.levels.el": "Elementary/primary school",
|
||||
"registration.field.education.levels.none": "No formal education",
|
||||
"registration.field.education.levels.other": "Other education",
|
||||
"registration.username.suggestion.label": "Suggested:",
|
||||
"registration.using.tpa.form.heading": "Finish creating your account",
|
||||
"did.you.mean.alert.text": "Did you mean",
|
||||
"register.page.terms.of.service": "I agree to the {platformName} {termsOfService}",
|
||||
"sign.in": "Sign in",
|
||||
"reset.password.page.title": "Reset Password | {siteName}",
|
||||
"reset.password": "Reset password",
|
||||
"reset.password.page.instructions": "Enter and confirm your new password.",
|
||||
"new.password.label": "New password",
|
||||
"confirm.password.label": "Confirm password",
|
||||
"passwords.do.not.match": "Passwords do not match",
|
||||
"confirm.your.password": "Confirm your password",
|
||||
"forgot.password.confirmation.sign.in.link": "sign in",
|
||||
"reset.password.request.forgot.password.text": "Forgot password",
|
||||
"reset.password.request.invalid.token.header": "Invalid password reset link",
|
||||
"reset.password.empty.new.password.field.error": "Please enter your new password.",
|
||||
"reset.password.failure.heading": "We couldn't reset your password.",
|
||||
"reset.password.form.submission.error": "Please check your responses and try again.",
|
||||
"reset.password.request.server.error": "Failed to reset password",
|
||||
"reset.password.token.validation.sever.error": "Token validation failure",
|
||||
"reset.server.rate.limit.error": "Too many requests.",
|
||||
"reset.password.success.heading": "Password reset complete.",
|
||||
"reset.password.success": "Your password has been reset. Sign in to your account.",
|
||||
"progressive.profiling.page.title": "Optional Fields | {siteName}",
|
||||
"progressive.profiling.page.heading": "A few questions for you will help us get smarter.",
|
||||
"gender.options.label": "Gender (optional)",
|
||||
"gender.options.f": "Female",
|
||||
"gender.options.m": "Male",
|
||||
"gender.options.o": "Other/Prefer not to say",
|
||||
"education.levels.label": "Highest level of education completed (optional)",
|
||||
"education.levels.p": "Doctorate",
|
||||
"education.levels.m": "Master's or professional degree",
|
||||
"education.levels.b": "Bachelor's degree",
|
||||
"education.levels.a": "Associate's degree",
|
||||
"education.levels.hs": "Secondary/high school",
|
||||
"education.levels.jhs": "Junior secondary/junior high/middle school",
|
||||
"education.levels.el": "Elementary/primary school",
|
||||
"education.levels.none": "No formal education",
|
||||
"education.levels.other": "Other education",
|
||||
"year.of.birth.label": "Year of birth (optional)",
|
||||
"optional.fields.information.link": "Learn more about how we use this information.",
|
||||
"optional.fields.submit.button": "Submit",
|
||||
"optional.fields.skip.button": "Skip for now",
|
||||
"continue.to.platform": "Continue to {platformName}",
|
||||
"modal.title": "Thanks for letting us know.",
|
||||
"modal.description": "You can complete your profile in settings at any time if you change your mind.",
|
||||
"welcome.page.error.heading": "We couldn't update your profile",
|
||||
"welcome.page.error.message": "An error occurred. You can complete your profile in settings at any time."
|
||||
}
|
||||
@@ -19,9 +19,9 @@
|
||||
"sso.create.account.using": "Create account using {providerName}",
|
||||
"show.password": "Show password",
|
||||
"hide.password": "Hide password",
|
||||
"one.letter": "1 Letter",
|
||||
"one.number": "1 Number",
|
||||
"eight.characters": "8 Characters",
|
||||
"one.letter": "1 letter",
|
||||
"one.number": "1 number",
|
||||
"eight.characters": "8 characters",
|
||||
"password.sr.only.helping.text": "Password must contain at least 8 characters, at least one letter, and at least one number",
|
||||
"tpa.alert.heading": "Almost done!",
|
||||
"login.third.party.auth.account.not.linked": "You have successfully signed into {currentProvider}, but your {currentProvider} account does not have a linked {platformName} account. To link your accounts, sign in now using your {platformName} password.",
|
||||
@@ -38,13 +38,12 @@
|
||||
"forgot.password.error.message.title": "An error occurred.",
|
||||
"forgot.password.request.in.progress.message": "Your previous request is in progress, please try again in a few moments.",
|
||||
"forgot.password.empty.email.field.error": "Enter your email",
|
||||
"forgot.password.invalid.email": "An error occurred.",
|
||||
"forgot.password.invalid.email.message": "The email address you've provided isn't formatted correctly.",
|
||||
"forgot.password.email.help.text": "The email address you used to register with {platformName}",
|
||||
"confirmation.message.title": "Check your email",
|
||||
"confirmation.support.link": "contact technical support",
|
||||
"need.help.sign.in.text": "Need help signing in?",
|
||||
"additional.help.text": "For additional help, contact edX support at ",
|
||||
"additional.help.text": "For additional help, contact {platformName} support at ",
|
||||
"sign.in.text": "Sign in",
|
||||
"extend.field.errors": "{emailError} below.",
|
||||
"invalid.token.heading": "Invalid password reset link",
|
||||
@@ -57,6 +56,7 @@
|
||||
"rate.limit.error": "An error has occurred because of too many requests. Please try again after some time.",
|
||||
"account.activation.error.message": "Something went wrong, please {supportLink} to resolve this issue.",
|
||||
"login.inactive.user.error": "In order to sign in, you need to activate your account.{lineBreak}\n {lineBreak}We just sent an activation link to {email}. If you do not receive an email,\n check your spam folders or {supportLink}.",
|
||||
"allowed.domain.login.error": "As {allowedDomain} user, You must login with your {allowedDomain} {tpaLink}.",
|
||||
"login.incorrect.credentials.error.attempts.text.1": "The username, email or password you entered is incorrect. You have {remainingAttempts} more sign in\n attempts before your account is temporarily locked.",
|
||||
"login.incorrect.credentials.error.attempts.text.2": "If you've forgotten your password, {resetLink}",
|
||||
"account.locked.out.message.2": "To be on the safe side, you can {resetLink} before trying again.",
|
||||
@@ -90,9 +90,14 @@
|
||||
"sign.in.heading": "Sign in",
|
||||
"account.activation.success.message.title": "Success! You have activated your account.",
|
||||
"account.activation.success.message": "You will now receive email updates and alerts from us related to the courses you are enrolled in. Sign in to continue.",
|
||||
"account.already.activated.message": "This account has already been activated.",
|
||||
"account.activation.info.message": "This account has already been activated.",
|
||||
"account.activation.error.message.title": "Your account could not be activated",
|
||||
"account.activation.support.link": "contact support",
|
||||
"tpa.account.link": "{provider} account",
|
||||
"account.confirmation.success.message.title": "Success! You have confirmed your email.",
|
||||
"account.confirmation.success.message": "Sign in to continue.",
|
||||
"account.confirmation.info.message": "This email has already been confirmed.",
|
||||
"account.confirmation.error.message.title": "Your email could not be confirmed",
|
||||
"login.rate.limit.reached.message": "Too many failed login attempts. Try again later.",
|
||||
"login.failure.header.title": "We couldn't sign you in.",
|
||||
"contact.support.link": "contact {platformName} support",
|
||||
@@ -102,28 +107,53 @@
|
||||
"login.form.invalid.error.message": "Please fill in the fields below.",
|
||||
"login.incorrect.credentials.error.reset.link.text": "reset your password",
|
||||
"login.incorrect.credentials.error.before.account.blocked.text": "click here to reset it.",
|
||||
"password.security.nudge.title": "Password security",
|
||||
"password.security.block.title": "Password change required",
|
||||
"password.security.nudge.body": "Our system detected that your password is vulnerable. We recommend you change it so that your account stays secure.",
|
||||
"password.security.block.body": "Our system detected that your password is vulnerable. Change your password so that your account stays secure.",
|
||||
"password.security.close.button": "Close",
|
||||
"password.security.redirect.to.reset.password.button": "Reset your password",
|
||||
"progressive.profiling.page.title": "Optional Fields | {siteName}",
|
||||
"progressive.profiling.page.heading": "A few questions for you will help us get smarter.",
|
||||
"optional.fields.information.link": "Learn more about how we use this information.",
|
||||
"optional.fields.submit.button": "Submit",
|
||||
"optional.fields.skip.button": "Skip for now",
|
||||
"optional.fields.next.button": "Next",
|
||||
"continue.to.platform": "Continue to {platformName}",
|
||||
"modal.title": "Thanks for letting us know.",
|
||||
"modal.description": "You can complete your profile in settings at any time if you change your mind.",
|
||||
"welcome.page.error.heading": "We couldn't update your profile",
|
||||
"welcome.page.error.message": "An error occurred. You can complete your profile in settings at any time.",
|
||||
"recommendation.page.title": "Recommendations| {siteName}",
|
||||
"recommendation.page.heading": "We have a few recommendations to get you started.",
|
||||
"recommendation.skip.button": "Skip for now",
|
||||
"register.page.title": "Register | {siteName}",
|
||||
"registration.fullname.label": "Full name",
|
||||
"registration.email.label": "Email",
|
||||
"registration.username.label": "Public username",
|
||||
"registration.password.label": "Password",
|
||||
"registration.country.label": "Country/Region",
|
||||
"registration.opt.in.label": "I agree that {siteName} may send me marketing messages.",
|
||||
"help.text.name": "This name will be used by any certificates that you earn.",
|
||||
"help.text.username.1": "The name that will identify you in your courses.",
|
||||
"help.text.username.2": "This can not be changed later.",
|
||||
"help.text.email": "For account activation and important updates",
|
||||
"create.account.button": "Create an account",
|
||||
"create.account.for.free.button": "Create an account for free",
|
||||
"create.an.account.btn.pending.state": "Loading",
|
||||
"registration.other.options.heading": "Or register with:",
|
||||
"register.institution.login.button": "Institution/campus credentials",
|
||||
"register.institution.login.page.title": "Register with institution/campus credentials",
|
||||
"empty.name.field.error": "Enter your full name",
|
||||
"empty.email.field.error": "Enter your email",
|
||||
"email.do.not.match": "The email addresses do not match.",
|
||||
"empty.username.field.error": "Username must be between 2 and 30 characters",
|
||||
"empty.password.field.error": "Password criteria has not been met",
|
||||
"empty.country.field.error": "Select your country or region of residence",
|
||||
"email.invalid.format.error": "Enter a valid email address",
|
||||
"email.ratelimit.less.chars.validation.message": "Email must have 3 characters.",
|
||||
"username.validation.message": "Username must be between 2 and 30 characters",
|
||||
"username.format.validation.message": "Usernames can only contain letters (A-Z, a-z), numerals (0-9), underscores (_), and hyphens (-).",
|
||||
"name.validation.message": "Enter a valid name",
|
||||
"username.format.validation.message": "Usernames can only contain letters (A-Z, a-z), numerals (0-9), underscores (_), and hyphens (-). Usernames cannot contain spaces",
|
||||
"support.education.research": "Support education research by providing additional information. (Optional)",
|
||||
"registration.request.failure.header": "We couldn't create your account.",
|
||||
"registration.empty.form.submission.error": "Please check your responses and try again.",
|
||||
@@ -132,6 +162,8 @@
|
||||
"registration.tpa.session.expired": "Registration using {provider} has timed out.",
|
||||
"terms.of.service.and.honor.code": "Terms of Service and Honor Code",
|
||||
"privacy.policy": "Privacy Policy",
|
||||
"honor.code": "Honor Code",
|
||||
"terms.of.service": "Terms of Service",
|
||||
"registration.year.of.birth.label": "Year of birth (optional)",
|
||||
"registration.field.gender.options.label": "Gender (optional)",
|
||||
"registration.goals.label": "Tell us why you're interested in edX (optional)",
|
||||
@@ -148,10 +180,10 @@
|
||||
"registration.field.education.levels.el": "Elementary/primary school",
|
||||
"registration.field.education.levels.none": "No formal education",
|
||||
"registration.field.education.levels.other": "Other education",
|
||||
"registration.username.suggestion.label": "Available:",
|
||||
"registration.username.suggestion.label": "Suggested:",
|
||||
"registration.using.tpa.form.heading": "Finish creating your account",
|
||||
"did.you.mean.alert.text": "Did you mean",
|
||||
"register.page.terms.of.service.and.honor.code": "By creating an account, you agree to the {tosAndHonorCode} and you acknowledge that {platformName} and each\n Member process your personal data in accordance with the {privacyPolicy}.",
|
||||
"register.page.terms.of.service": "I agree to the {platformName} {termsOfService}",
|
||||
"sign.in": "Sign in",
|
||||
"reset.password.page.title": "Reset Password | {siteName}",
|
||||
"reset.password": "Reset password",
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import 'core-js/stable';
|
||||
import 'regenerator-runtime/runtime';
|
||||
|
||||
import {
|
||||
APP_INIT_ERROR, APP_READY, subscribe, initialize, mergeConfig,
|
||||
} from '@edx/frontend-platform';
|
||||
import { ErrorPage } from '@edx/frontend-platform/react';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import {
|
||||
APP_INIT_ERROR, APP_READY, initialize, mergeConfig, subscribe,
|
||||
} from '@edx/frontend-platform';
|
||||
import { ErrorPage } from '@edx/frontend-platform/react';
|
||||
import { messages as paragonMessages } from '@edx/paragon';
|
||||
|
||||
import appMessages from './i18n';
|
||||
import MainApp from './MainApp';
|
||||
import messages from './i18n';
|
||||
|
||||
subscribe(APP_READY, () => {
|
||||
ReactDOM.render(
|
||||
@@ -30,8 +32,8 @@ initialize({
|
||||
ACTIVATION_EMAIL_SUPPORT_LINK: process.env.ACTIVATION_EMAIL_SUPPORT_LINK || null,
|
||||
PASSWORD_RESET_SUPPORT_LINK: process.env.PASSWORD_RESET_SUPPORT_LINK || null,
|
||||
TOS_AND_HONOR_CODE: process.env.TOS_AND_HONOR_CODE || null,
|
||||
TOS_LINK: process.env.TOS_LINK || null,
|
||||
PRIVACY_POLICY: process.env.PRIVACY_POLICY || null,
|
||||
REGISTRATION_OPTIONAL_FIELDS: process.env.REGISTRATION_OPTIONAL_FIELDS || '',
|
||||
USER_SURVEY_COOKIE_NAME: process.env.USER_SURVEY_COOKIE_NAME || null,
|
||||
COOKIE_DOMAIN: process.env.COOKIE_DOMAIN,
|
||||
WELCOME_PAGE_SUPPORT_LINK: process.env.WELCOME_PAGE_SUPPORT_LINK || null,
|
||||
@@ -39,10 +41,15 @@ initialize({
|
||||
INFO_EMAIL: process.env.INFO_EMAIL || '',
|
||||
REGISTER_CONVERSION_COOKIE_NAME: process.env.REGISTER_CONVERSION_COOKIE_NAME || null,
|
||||
ENABLE_PROGRESSIVE_PROFILING: process.env.ENABLE_PROGRESSIVE_PROFILING || false,
|
||||
MARKETING_EMAILS_OPT_IN: process.env.MARKETING_EMAILS_OPT_IN || '',
|
||||
ENABLE_COPPA_COMPLIANCE: process.env.ENABLE_COPPA_COMPLIANCE || '',
|
||||
ENABLE_DYNAMIC_REGISTRATION_FIELDS: process.env.ENABLE_DYNAMIC_REGISTRATION_FIELDS || false,
|
||||
ENABLE_COOKIE_POLICY_BANNER: process.env.ENABLE_COOKIE_POLICY_BANNER || false,
|
||||
});
|
||||
},
|
||||
},
|
||||
messages: [
|
||||
messages,
|
||||
appMessages,
|
||||
paragonMessages,
|
||||
],
|
||||
});
|
||||
|
||||
@@ -3,6 +3,5 @@
|
||||
@import "~@edx/paragon/scss/core/core";
|
||||
@import "~@edx/brand/paragon/overrides";
|
||||
|
||||
@import '@edx/frontend-component-cookie-policy-banner/build/_cookie-policy-banner';
|
||||
|
||||
@import "./style";
|
||||
@import "@edx/frontend-component-cookie-policy-banner/build/_cookie-policy-banner";
|
||||
@import "sass/style";
|
||||
|
||||
@@ -13,6 +13,8 @@ const AccountActivationMessage = (props) => {
|
||||
const { intl, messageType } = props;
|
||||
const variant = messageType === ACCOUNT_ACTIVATION_MESSAGE.ERROR ? 'danger' : messageType;
|
||||
|
||||
const activationOrVerification = getConfig().MARKETING_EMAILS_OPT_IN ? 'confirmation' : 'activation';
|
||||
|
||||
let activationMessage;
|
||||
let heading;
|
||||
|
||||
@@ -23,12 +25,12 @@ const AccountActivationMessage = (props) => {
|
||||
|
||||
switch (messageType) {
|
||||
case ACCOUNT_ACTIVATION_MESSAGE.SUCCESS: {
|
||||
heading = intl.formatMessage(messages['account.activation.success.message.title']);
|
||||
activationMessage = intl.formatMessage(messages['account.activation.success.message']);
|
||||
heading = intl.formatMessage(messages[`account.${activationOrVerification}.success.message.title`]);
|
||||
activationMessage = <span>{intl.formatMessage(messages[`account.${activationOrVerification}.success.message`])}</span>;
|
||||
break;
|
||||
}
|
||||
case ACCOUNT_ACTIVATION_MESSAGE.INFO: {
|
||||
activationMessage = intl.formatMessage(messages['account.already.activated.message']);
|
||||
activationMessage = intl.formatMessage(messages[`account.${activationOrVerification}.info.message`]);
|
||||
break;
|
||||
}
|
||||
case ACCOUNT_ACTIVATION_MESSAGE.ERROR: {
|
||||
@@ -38,7 +40,7 @@ const AccountActivationMessage = (props) => {
|
||||
</Alert.Link>
|
||||
);
|
||||
|
||||
heading = intl.formatMessage(messages['account.activation.error.message.title']);
|
||||
heading = intl.formatMessage(messages[`account.${activationOrVerification}.error.message.title`]);
|
||||
activationMessage = (
|
||||
<FormattedMessage
|
||||
id="account.activation.error.message"
|
||||
|
||||
88
src/login/ChangePasswordPrompt.jsx
Normal file
88
src/login/ChangePasswordPrompt.jsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
ActionRow, ModalDialog, useToggle,
|
||||
} from '@edx/paragon';
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link, Redirect } from 'react-router-dom';
|
||||
|
||||
import { DEFAULT_REDIRECT_URL, RESET_PAGE } from '../data/constants';
|
||||
import { updatePathWithQueryParams } from '../data/utils';
|
||||
import useMobileResponsive from '../data/utils/useMobileResponsive';
|
||||
import messages from './messages';
|
||||
|
||||
const ChangePasswordPrompt = ({ intl, variant, redirectUrl }) => {
|
||||
const isMobileView = useMobileResponsive();
|
||||
const [redirectToResetPasswordPage, setRedirectToResetPasswordPage] = useState(false);
|
||||
const handlers = {
|
||||
handleToggleOff: () => {
|
||||
if (variant === 'block') {
|
||||
setRedirectToResetPasswordPage(true);
|
||||
} else {
|
||||
window.location.href = redirectUrl || getConfig().LMS_BASE_URL.concat(DEFAULT_REDIRECT_URL);
|
||||
}
|
||||
},
|
||||
};
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const [isOpen, open, close] = useToggle(true, handlers);
|
||||
|
||||
if (redirectToResetPasswordPage) {
|
||||
return <Redirect to={updatePathWithQueryParams(RESET_PAGE)} />;
|
||||
}
|
||||
return (
|
||||
<ModalDialog
|
||||
title="Password security"
|
||||
isOpen={isOpen}
|
||||
onClose={close}
|
||||
size={isMobileView ? 'sm' : 'md'}
|
||||
hasCloseButton={false}
|
||||
>
|
||||
<ModalDialog.Header>
|
||||
<ModalDialog.Title>
|
||||
{intl.formatMessage(messages[`password.security.${variant}.title`])}
|
||||
</ModalDialog.Title>
|
||||
</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
{intl.formatMessage(messages[`password.security.${variant}.body`])}
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer>
|
||||
<ActionRow className={classNames(
|
||||
{ 'd-flex flex-column': isMobileView },
|
||||
)}
|
||||
>
|
||||
{variant === 'nudge' ? (
|
||||
<ModalDialog.CloseButton id="password-security-close" variant="tertiary">
|
||||
{intl.formatMessage(messages['password.security.close.button'])}
|
||||
</ModalDialog.CloseButton>
|
||||
) : null}
|
||||
<Link
|
||||
id="password-security-reset-password"
|
||||
className={classNames(
|
||||
'btn btn-primary',
|
||||
{ 'w-100': isMobileView },
|
||||
)}
|
||||
to={updatePathWithQueryParams(RESET_PAGE)}
|
||||
>
|
||||
{intl.formatMessage(messages['password.security.redirect.to.reset.password.button'])}
|
||||
</Link>
|
||||
</ActionRow>
|
||||
</ModalDialog.Footer>
|
||||
</ModalDialog>
|
||||
);
|
||||
};
|
||||
|
||||
ChangePasswordPrompt.defaultProps = {
|
||||
variant: 'block',
|
||||
redirectUrl: null,
|
||||
};
|
||||
|
||||
ChangePasswordPrompt.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
variant: PropTypes.oneOf(['nudge', 'block']),
|
||||
redirectUrl: PropTypes.string,
|
||||
};
|
||||
|
||||
export default injectIntl(ChangePasswordPrompt);
|
||||
@@ -1,13 +1,16 @@
|
||||
import React from 'react';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { getAuthService } from '@edx/frontend-platform/auth';
|
||||
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Alert, Hyperlink } from '@edx/paragon';
|
||||
import { Error } from '@edx/paragon/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import processLink from '../data/utils';
|
||||
import ChangePasswordPrompt from './ChangePasswordPrompt';
|
||||
import {
|
||||
ACCOUNT_LOCKED_OUT,
|
||||
ALLOWED_DOMAIN_LOGIN_ERROR,
|
||||
FAILED_LOGIN_ATTEMPT,
|
||||
FORBIDDEN_REQUEST,
|
||||
INACTIVE_USER,
|
||||
@@ -15,16 +18,18 @@ import {
|
||||
INTERNAL_SERVER_ERROR,
|
||||
INVALID_FORM,
|
||||
NON_COMPLIANT_PASSWORD_EXCEPTION,
|
||||
NUDGE_PASSWORD_CHANGE,
|
||||
REQUIRE_PASSWORD_CHANGE,
|
||||
} from './data/constants';
|
||||
import messages from './messages';
|
||||
|
||||
const LoginFailureMessage = (props) => {
|
||||
const { intl } = props;
|
||||
const { context, errorCode, value } = props.loginError;
|
||||
const { context, errorCode } = props.loginError;
|
||||
const authService = getAuthService();
|
||||
let errorList;
|
||||
let link;
|
||||
let resetLink = (
|
||||
<Hyperlink destination="/reset" isInline>
|
||||
<Hyperlink destination="reset" isInline>
|
||||
{intl.formatMessage(messages['login.incorrect.credentials.error.reset.link.text'])}
|
||||
</Hyperlink>
|
||||
);
|
||||
@@ -65,15 +70,31 @@ const LoginFailureMessage = (props) => {
|
||||
);
|
||||
break;
|
||||
}
|
||||
case INTERNAL_SERVER_ERROR:
|
||||
errorList = <p>{intl.formatMessage(messages['internal.server.error.message'])}</p>;
|
||||
case ALLOWED_DOMAIN_LOGIN_ERROR: {
|
||||
const url = `${getConfig().LMS_BASE_URL}/dashboard/?tpa_hint=${context.tpaHint}`;
|
||||
const tpaLink = (
|
||||
<a href={url}>
|
||||
{intl.formatMessage(messages['tpa.account.link'], { provider: context.provider })}
|
||||
</a>
|
||||
);
|
||||
errorList = (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="allowed.domain.login.error"
|
||||
description="Display this error message when staff user try to login through password"
|
||||
defaultMessage="As {allowedDomain} user, You must login with your {allowedDomain} {tpaLink}."
|
||||
values={{ allowedDomain: context.allowedDomain, tpaLink }}
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
break;
|
||||
}
|
||||
case INVALID_FORM:
|
||||
errorList = <p>{intl.formatMessage(messages['login.form.invalid.error.message'])}</p>;
|
||||
break;
|
||||
case FAILED_LOGIN_ATTEMPT: {
|
||||
resetLink = (
|
||||
<Hyperlink destination="/reset" isInline>
|
||||
<Hyperlink destination="reset" isInline>
|
||||
{intl.formatMessage(messages['login.incorrect.credentials.error.before.account.blocked.text'])}
|
||||
</Hyperlink>
|
||||
);
|
||||
@@ -118,7 +139,7 @@ const LoginFailureMessage = (props) => {
|
||||
}
|
||||
case INCORRECT_EMAIL_PASSWORD:
|
||||
if (context.failureCount <= 1) {
|
||||
errorList = intl.formatMessage(messages['login.incorrect.credentials.error']);
|
||||
errorList = <p>{intl.formatMessage(messages['login.incorrect.credentials.error'])}</p>;
|
||||
} else if (context.failureCount === 2) {
|
||||
errorList = (
|
||||
<p>
|
||||
@@ -131,28 +152,23 @@ const LoginFailureMessage = (props) => {
|
||||
);
|
||||
}
|
||||
break;
|
||||
case NUDGE_PASSWORD_CHANGE:
|
||||
// Need to clear the CSRF token here to fetch a new one because token is already rotated after successful login.
|
||||
if (authService) {
|
||||
authService.getCsrfTokenService().clearCsrfTokenCache();
|
||||
}
|
||||
return (
|
||||
<ChangePasswordPrompt
|
||||
redirectUrl={props.loginError.redirectUrl}
|
||||
variant="nudge"
|
||||
/>
|
||||
);
|
||||
case REQUIRE_PASSWORD_CHANGE:
|
||||
return <ChangePasswordPrompt />;
|
||||
case INTERNAL_SERVER_ERROR:
|
||||
default:
|
||||
// TODO: use errorCode instead of processing error messages on frontend
|
||||
errorList = value.trim().split('\n');
|
||||
errorList = errorList.map((error) => {
|
||||
let matches;
|
||||
if (error.includes('a href')) {
|
||||
matches = processLink(error);
|
||||
const [beforeLink, href, linkText, afterLink] = matches;
|
||||
link = href;
|
||||
if (href.indexOf('/dashboard?tpa_hint') === 0) {
|
||||
link = `/login?next=${href}`;
|
||||
}
|
||||
return (
|
||||
<p key={error}>
|
||||
{beforeLink}
|
||||
<a href={link}>{linkText}</a>
|
||||
{afterLink}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
return <p key={error}>{error}</p>;
|
||||
});
|
||||
errorList = <p>{intl.formatMessage(messages['internal.server.error.message'])}</p>;
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -165,8 +181,8 @@ const LoginFailureMessage = (props) => {
|
||||
|
||||
LoginFailureMessage.defaultProps = {
|
||||
loginError: {
|
||||
redirectUrl: null,
|
||||
errorCode: null,
|
||||
value: '',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -175,7 +191,7 @@ LoginFailureMessage.propTypes = {
|
||||
context: PropTypes.object,
|
||||
email: PropTypes.string,
|
||||
errorCode: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
redirectUrl: PropTypes.string,
|
||||
}),
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
import { connect } from 'react-redux';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { sendPageEvent, sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
@@ -13,17 +8,14 @@ import {
|
||||
Form, Hyperlink, Icon, StatefulButton,
|
||||
} from '@edx/paragon';
|
||||
import { Institution } from '@edx/paragon/icons';
|
||||
|
||||
import AccountActivationMessage from './AccountActivationMessage';
|
||||
import { loginRequest, loginRequestFailure, loginRequestReset } from './data/actions';
|
||||
import { INVALID_FORM } from './data/constants';
|
||||
import { loginErrorSelector, loginRequestSelector } from './data/selectors';
|
||||
import LoginFailureMessage from './LoginFailure';
|
||||
import messages from './messages';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
RedirectLogistration, SocialAuthProviders, ThirdPartyAuthAlert, RenderInstitutionButton,
|
||||
InstitutionLogistration, FormGroup, PasswordField,
|
||||
FormGroup, InstitutionLogistration, PasswordField, RedirectLogistration,
|
||||
RenderInstitutionButton, SocialAuthProviders, ThirdPartyAuthAlert,
|
||||
} from '../common-components';
|
||||
import { getThirdPartyAuthContext } from '../common-components/data/actions';
|
||||
import { thirdPartyAuthContextSelector } from '../common-components/data/selectors';
|
||||
@@ -32,28 +24,33 @@ import {
|
||||
DEFAULT_STATE, ENTERPRISE_LOGIN_URL, PENDING_STATE, RESET_PAGE,
|
||||
} from '../data/constants';
|
||||
import {
|
||||
getTpaHint,
|
||||
getTpaProvider,
|
||||
windowScrollTo,
|
||||
setSurveyCookie,
|
||||
getActivationStatus,
|
||||
getAllPossibleQueryParam,
|
||||
getTpaHint,
|
||||
getTpaProvider,
|
||||
setSurveyCookie,
|
||||
updatePathWithQueryParams,
|
||||
windowScrollTo,
|
||||
} from '../data/utils';
|
||||
import { forgotPasswordResultSelector } from '../forgot-password';
|
||||
import ResetPasswordSuccess from '../reset-password/ResetPasswordSuccess';
|
||||
import AccountActivationMessage from './AccountActivationMessage';
|
||||
import {
|
||||
loginRemovePasswordResetBanner, loginRequest, loginRequestFailure, loginRequestReset, setLoginFormData,
|
||||
} from './data/actions';
|
||||
import { INVALID_FORM } from './data/constants';
|
||||
import { loginErrorSelector, loginFormDataSelector, loginRequestSelector } from './data/selectors';
|
||||
import LoginFailureMessage from './LoginFailure';
|
||||
import messages from './messages';
|
||||
|
||||
class LoginPage extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
sendPageEvent('login_and_registration', 'login');
|
||||
this.state = {
|
||||
password: '',
|
||||
emailOrUsername: '',
|
||||
password: this.props.loginFormData.password,
|
||||
emailOrUsername: this.props.loginFormData.emailOrUsername,
|
||||
errors: {
|
||||
emailOrUsername: '',
|
||||
password: '',
|
||||
emailOrUsername: this.props.loginFormData.errors.emailOrUsername,
|
||||
password: this.props.loginFormData.errors.password,
|
||||
},
|
||||
isSubmitted: false,
|
||||
};
|
||||
@@ -62,6 +59,7 @@ class LoginPage extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
sendPageEvent('login_and_registration', 'login');
|
||||
const payload = { ...this.queryParams };
|
||||
|
||||
if (this.tpaHint) {
|
||||
@@ -71,19 +69,49 @@ class LoginPage extends React.Component {
|
||||
this.props.loginRequestReset();
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
if (nextProps.loginFormData && this.props.loginFormData !== nextProps.loginFormData) {
|
||||
// Ensuring browser's autofill user credentials get filled and their state persists in the redux store.
|
||||
const nextState = {
|
||||
emailOrUsername: nextProps.loginFormData.emailOrUsername || this.state.emailOrUsername,
|
||||
password: nextProps.loginFormData.password || this.state.password,
|
||||
};
|
||||
this.setState({
|
||||
...nextProps.loginFormData,
|
||||
...nextState,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.props.resetPassword) {
|
||||
this.props.loginRemovePasswordResetBanner();
|
||||
}
|
||||
}
|
||||
|
||||
getEnterPriseLoginURL() {
|
||||
return getConfig().LMS_BASE_URL + ENTERPRISE_LOGIN_URL;
|
||||
}
|
||||
|
||||
handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
if (this.props.resetPassword) {
|
||||
this.props.loginRemovePasswordResetBanner();
|
||||
}
|
||||
this.setState({ isSubmitted: true });
|
||||
|
||||
const { emailOrUsername, password } = this.state;
|
||||
const emailValidationError = this.validateEmail(emailOrUsername);
|
||||
const passwordValidationError = this.validatePassword(password);
|
||||
|
||||
if (emailValidationError !== '' || passwordValidationError !== '') {
|
||||
this.props.setLoginFormData({
|
||||
errors: {
|
||||
emailOrUsername: emailValidationError,
|
||||
password: passwordValidationError,
|
||||
},
|
||||
});
|
||||
this.props.loginRequestFailure({
|
||||
errorCode: INVALID_FORM,
|
||||
});
|
||||
@@ -99,7 +127,16 @@ class LoginPage extends React.Component {
|
||||
handleOnFocus = (e) => {
|
||||
const { errors } = this.state;
|
||||
errors[e.target.name] = '';
|
||||
this.setState({ errors });
|
||||
this.props.setLoginFormData({
|
||||
errors,
|
||||
});
|
||||
}
|
||||
|
||||
handleOnBlur = (e) => {
|
||||
const payload = {
|
||||
[e.target.name]: e.target.value,
|
||||
};
|
||||
this.props.setLoginFormData(payload);
|
||||
}
|
||||
|
||||
handleForgotPasswordLinkClickEvent = () => {
|
||||
@@ -116,7 +153,6 @@ class LoginPage extends React.Component {
|
||||
} else {
|
||||
errors.emailOrUsername = '';
|
||||
}
|
||||
this.setState({ errors });
|
||||
return errors.emailOrUsername;
|
||||
}
|
||||
|
||||
@@ -124,7 +160,6 @@ class LoginPage extends React.Component {
|
||||
const { errors } = this.state;
|
||||
errors.password = password.length > 0 ? '' : this.props.intl.formatMessage(messages['password.validation.message']);
|
||||
|
||||
this.setState({ errors });
|
||||
return errors.password;
|
||||
}
|
||||
|
||||
@@ -132,24 +167,25 @@ class LoginPage extends React.Component {
|
||||
const isInstitutionAuthActive = !!secondaryProviders.length && !currentProvider;
|
||||
const isSocialAuthActive = !!providers.length && !currentProvider;
|
||||
const isEnterpriseLoginDisabled = getConfig().DISABLE_ENTERPRISE_LOGIN;
|
||||
const isThirdPartyAuthActive = isSocialAuthActive || (isEnterpriseLoginDisabled && isInstitutionAuthActive);
|
||||
|
||||
return (
|
||||
<>
|
||||
{(!isEnterpriseLoginDisabled || ((isEnterpriseLoginDisabled && isInstitutionAuthActive) || isSocialAuthActive))
|
||||
&& (
|
||||
<div className="mt-4 mb-3 h4">
|
||||
{intl.formatMessage(messages['login.other.options.heading'])}
|
||||
</div>
|
||||
)}
|
||||
{(isSocialAuthActive || (isEnterpriseLoginDisabled && isInstitutionAuthActive))
|
||||
&& (
|
||||
<div className="mt-4 mb-3 h4">
|
||||
{intl.formatMessage(messages['login.other.options.heading'])}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isEnterpriseLoginDisabled && (
|
||||
{(!isEnterpriseLoginDisabled && isSocialAuthActive) && (
|
||||
<Hyperlink className="btn btn-link btn-sm text-body p-0 mb-4" destination={this.getEnterPriseLoginURL()}>
|
||||
<Icon src={Institution} className="institute-icon" />
|
||||
{intl.formatMessage(messages['enterprise.login.btn.text'])}
|
||||
</Hyperlink>
|
||||
)}
|
||||
|
||||
{thirdPartyAuthApiStatus === PENDING_STATE ? (
|
||||
{thirdPartyAuthApiStatus === PENDING_STATE && isThirdPartyAuthActive ? (
|
||||
<Skeleton className="tpa-skeleton mb-3" height={30} count={2} />
|
||||
) : (
|
||||
<>
|
||||
@@ -224,25 +260,31 @@ class LoginPage extends React.Component {
|
||||
{submitState === DEFAULT_STATE && this.state.isSubmitted ? windowScrollTo({ left: 0, top: 0, behavior: 'smooth' }) : null}
|
||||
{activationMsgType && <AccountActivationMessage messageType={activationMsgType} />}
|
||||
{this.props.resetPassword && !this.props.loginError ? <ResetPasswordSuccess /> : null}
|
||||
<Form>
|
||||
<Form name="sign-in-form" id="sign-in-form">
|
||||
<FormGroup
|
||||
name="emailOrUsername"
|
||||
value={this.state.emailOrUsername}
|
||||
autoComplete="on"
|
||||
handleChange={(e) => this.setState({ emailOrUsername: e.target.value, isSubmitted: false })}
|
||||
handleFocus={this.handleOnFocus}
|
||||
handleBlur={this.handleOnBlur}
|
||||
errorMessage={this.state.errors.emailOrUsername}
|
||||
floatingLabel={intl.formatMessage(messages['login.user.identity.label'])}
|
||||
/>
|
||||
<PasswordField
|
||||
name="password"
|
||||
value={this.state.password}
|
||||
autoComplete="off"
|
||||
showRequirements={false}
|
||||
handleChange={(e) => this.setState({ password: e.target.value, isSubmitted: false })}
|
||||
handleFocus={this.handleOnFocus}
|
||||
handleBlur={this.handleOnBlur}
|
||||
errorMessage={this.state.errors.password}
|
||||
floatingLabel={intl.formatMessage(messages['login.password.label'])}
|
||||
/>
|
||||
<StatefulButton
|
||||
name="sign-in"
|
||||
id="sign-in"
|
||||
type="submit"
|
||||
variant="brand"
|
||||
className="login-button-width"
|
||||
@@ -256,6 +298,7 @@ class LoginPage extends React.Component {
|
||||
/>
|
||||
<Link
|
||||
id="forgot-password"
|
||||
name="forgot-password"
|
||||
className="btn btn-link font-weight-500 text-body"
|
||||
to={updatePathWithQueryParams(RESET_PAGE)}
|
||||
onClick={this.handleForgotPasswordLinkClickEvent}
|
||||
@@ -307,9 +350,16 @@ class LoginPage extends React.Component {
|
||||
}
|
||||
|
||||
LoginPage.defaultProps = {
|
||||
forgotPassword: null,
|
||||
loginResult: null,
|
||||
loginError: null,
|
||||
loginFormData: {
|
||||
emailOrUsername: '',
|
||||
password: '',
|
||||
errors: {
|
||||
emailOrUsername: '',
|
||||
password: '',
|
||||
},
|
||||
},
|
||||
resetPassword: false,
|
||||
submitState: DEFAULT_STATE,
|
||||
thirdPartyAuthApiStatus: 'pending',
|
||||
@@ -322,20 +372,26 @@ LoginPage.defaultProps = {
|
||||
};
|
||||
|
||||
LoginPage.propTypes = {
|
||||
forgotPassword: PropTypes.shape({
|
||||
email: PropTypes.string,
|
||||
status: PropTypes.string,
|
||||
}),
|
||||
getThirdPartyAuthContext: PropTypes.func.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
loginError: PropTypes.objectOf(PropTypes.any),
|
||||
loginRequest: PropTypes.func.isRequired,
|
||||
loginRequestFailure: PropTypes.func.isRequired,
|
||||
loginRequestReset: PropTypes.func.isRequired,
|
||||
setLoginFormData: PropTypes.func.isRequired,
|
||||
loginRemovePasswordResetBanner: PropTypes.func.isRequired,
|
||||
loginResult: PropTypes.shape({
|
||||
redirectUrl: PropTypes.string,
|
||||
success: PropTypes.bool,
|
||||
}),
|
||||
loginFormData: PropTypes.shape({
|
||||
emailOrUsername: PropTypes.string,
|
||||
password: PropTypes.string,
|
||||
errors: PropTypes.shape({
|
||||
emailOrUsername: PropTypes.string,
|
||||
password: PropTypes.string,
|
||||
}),
|
||||
}),
|
||||
resetPassword: PropTypes.bool,
|
||||
submitState: PropTypes.string,
|
||||
thirdPartyAuthApiStatus: PropTypes.string,
|
||||
@@ -351,17 +407,17 @@ LoginPage.propTypes = {
|
||||
};
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const forgotPassword = forgotPasswordResultSelector(state);
|
||||
const loginResult = loginRequestSelector(state);
|
||||
const thirdPartyAuthContext = thirdPartyAuthContextSelector(state);
|
||||
const loginError = loginErrorSelector(state);
|
||||
const loginFormData = loginFormDataSelector(state);
|
||||
return {
|
||||
submitState: state.login.submitState,
|
||||
thirdPartyAuthApiStatus: state.commonComponents.thirdPartyAuthApiStatus,
|
||||
forgotPassword,
|
||||
loginError,
|
||||
loginResult,
|
||||
thirdPartyAuthContext,
|
||||
loginFormData,
|
||||
resetPassword: state.login.resetPassword,
|
||||
};
|
||||
};
|
||||
@@ -373,5 +429,7 @@ export default connect(
|
||||
loginRequest,
|
||||
loginRequestFailure,
|
||||
loginRequestReset,
|
||||
setLoginFormData,
|
||||
loginRemovePasswordResetBanner,
|
||||
},
|
||||
)(injectIntl(LoginPage));
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { AsyncActionType } from '../../data/utils';
|
||||
|
||||
export const LOGIN_REQUEST = new AsyncActionType('LOGIN', 'REQUEST');
|
||||
export const LOGIN_PERSIST_FORM_DATA = 'LOGIN_PERSIST_FORM_DATA';
|
||||
export const LOGIN_REMOVE_PASSWORD_RESET_BANNER = 'LOGIN_REMOVE_PASSWORD_RESET_BANNER';
|
||||
|
||||
// Login
|
||||
export const loginRequest = creds => ({
|
||||
@@ -25,3 +27,12 @@ export const loginRequestFailure = (loginError) => ({
|
||||
export const loginRequestReset = () => ({
|
||||
type: LOGIN_REQUEST.RESET,
|
||||
});
|
||||
|
||||
export const setLoginFormData = (formData) => ({
|
||||
type: LOGIN_PERSIST_FORM_DATA,
|
||||
payload: { formData },
|
||||
});
|
||||
|
||||
export const loginRemovePasswordResetBanner = () => ({
|
||||
type: LOGIN_REMOVE_PASSWORD_RESET_BANNER,
|
||||
});
|
||||
|
||||
@@ -7,6 +7,9 @@ export const FORBIDDEN_REQUEST = 'forbidden-request';
|
||||
export const FAILED_LOGIN_ATTEMPT = 'failed-login-attempt';
|
||||
export const ACCOUNT_LOCKED_OUT = 'account-locked-out';
|
||||
export const INCORRECT_EMAIL_PASSWORD = 'incorrect-email-or-password';
|
||||
export const NUDGE_PASSWORD_CHANGE = 'nudge-password-change';
|
||||
export const REQUIRE_PASSWORD_CHANGE = 'require-password-change';
|
||||
export const ALLOWED_DOMAIN_LOGIN_ERROR = 'allowed-domain-login-error';
|
||||
|
||||
// Account Activation Message
|
||||
export const ACCOUNT_ACTIVATION_MESSAGE = {
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { LOGIN_REQUEST } from './actions';
|
||||
|
||||
import { DEFAULT_STATE, PENDING_STATE } from '../../data/constants';
|
||||
import { RESET_PASSWORD } from '../../reset-password';
|
||||
import { LOGIN_PERSIST_FORM_DATA, LOGIN_REMOVE_PASSWORD_RESET_BANNER, LOGIN_REQUEST } from './actions';
|
||||
|
||||
export const defaultState = {
|
||||
loginError: null,
|
||||
loginResult: {},
|
||||
resetPassword: false,
|
||||
loginFormData: {
|
||||
password: '',
|
||||
emailOrUsername: '',
|
||||
errors: {
|
||||
emailOrUsername: '',
|
||||
password: '',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const reducer = (state = defaultState, action) => {
|
||||
@@ -38,6 +45,22 @@ const reducer = (state = defaultState, action) => {
|
||||
...state,
|
||||
resetPassword: true,
|
||||
};
|
||||
case LOGIN_PERSIST_FORM_DATA: {
|
||||
const { formData } = action.payload;
|
||||
return {
|
||||
...state,
|
||||
loginFormData: {
|
||||
...state.loginFormData,
|
||||
...formData,
|
||||
},
|
||||
};
|
||||
}
|
||||
case LOGIN_REMOVE_PASSWORD_RESET_BANNER: {
|
||||
return {
|
||||
...state,
|
||||
resetPassword: false,
|
||||
};
|
||||
}
|
||||
default:
|
||||
return {
|
||||
...state,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user