@atlassian/i18n-properties-loader 0.0.0-snapshot.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +149 -0
- package/CODE_OF_CONDUCT.md +73 -0
- package/LICENSE +13 -0
- package/README.md +127 -0
- package/index.js +221 -0
- package/package.json +57 -0
- package/rx.js +36 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
## 0.0.0-snapshot.0 (2024-12-12)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @atlassian/i18n-properties-loader
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### [1.0.13](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@1.0.13..@atlassian/i18n-properties-loader@1.0.12) (2024-06-25)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* **soy-loader:** [SPFE-1067](https://ecosystem.atlassian.net/browse/SPFE-1067) - ensure soy-loader accepts webpack 4 as a peer dependency and add system-level tests for working with all supported webpack versions ([3d8fe4e](https://bitbucket.org/atlassianlabs/fe-server/commits/3d8fe4e97c7af231c32dacf860b4fa54e08053fa))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### [1.0.12](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@1.0.12..@atlassian/i18n-properties-loader@1.0.11) (2024-05-28)
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
### [1.0.11](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@1.0.11..@atlassian/i18n-properties-loader@1.0.10) (2024-05-13)
|
|
28
|
+
|
|
29
|
+
**Note:** Version bump only for package @atlassian/i18n-properties-loader
|
|
30
|
+
|
|
31
|
+
### 1.0.10 (2024-04-05)
|
|
32
|
+
|
|
33
|
+
**Note:** Version bump only for package @atlassian/i18n-properties-loader
|
|
34
|
+
|
|
35
|
+
### 1.0.9 (2022-02-10)
|
|
36
|
+
|
|
37
|
+
**Note:** Version bump only for package @atlassian/i18n-properties-loader
|
|
38
|
+
|
|
39
|
+
### [1.0.8](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@1.0.8..@atlassian/i18n-properties-loader@1.0.7) (2021-11-17)
|
|
40
|
+
|
|
41
|
+
### Bug Fixes
|
|
42
|
+
|
|
43
|
+
- Update webpack depndency ([00fc73e](https://bitbucket.org/atlassianlabs/fe-server/commits/00fc73e95ad4a2f89ee4fd3561ab3fb60d1b9516))
|
|
44
|
+
|
|
45
|
+
### [1.0.7](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@1.0.7..@atlassian/i18n-properties-loader@1.0.6) (2021-10-26)
|
|
46
|
+
|
|
47
|
+
**Note:** Version bump only for package @atlassian/i18n-properties-loader
|
|
48
|
+
|
|
49
|
+
### [1.0.6](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@1.0.6..@atlassian/i18n-properties-loader@1.0.5) (2021-10-22)
|
|
50
|
+
|
|
51
|
+
### Bug Fixes
|
|
52
|
+
|
|
53
|
+
- **ci:** update webpack versions when running integration tests ([009dd61](https://bitbucket.org/atlassianlabs/fe-server/commits/009dd61f36a784d3fef7b6d6fa7214c5cc16b8b8))
|
|
54
|
+
|
|
55
|
+
### [1.0.5](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@1.0.5..@atlassian/i18n-properties-loader@1.0.4) (2021-10-14)
|
|
56
|
+
|
|
57
|
+
**Note:** Version bump only for package @atlassian/i18n-properties-loader
|
|
58
|
+
|
|
59
|
+
### [1.0.4](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@1.0.4..@atlassian/i18n-properties-loader@1.0.3) (2021-10-08)
|
|
60
|
+
|
|
61
|
+
**Note:** Version bump only for package @atlassian/i18n-properties-loader
|
|
62
|
+
|
|
63
|
+
### [1.0.3](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@1.0.3..@atlassian/i18n-properties-loader@1.0.2) (2021-09-24)
|
|
64
|
+
|
|
65
|
+
**Note:** Version bump only for package @atlassian/i18n-properties-loader
|
|
66
|
+
|
|
67
|
+
### [1.0.2](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@1.0.2..@atlassian/i18n-properties-loader@1.0.1) (2021-09-22)
|
|
68
|
+
|
|
69
|
+
- Update internal dependencies
|
|
70
|
+
|
|
71
|
+
### Bug Fixes
|
|
72
|
+
|
|
73
|
+
- rename configuration passed to schema validation util ([bb4b6a2](https://bitbucket.org/atlassianlabs/fe-server/commits/bb4b6a2791672a36b019ed7c99915cc8f77e308e))
|
|
74
|
+
- **release:** fix release script for the wrm package ([482efe2](https://bitbucket.org/atlassianlabs/fe-server/commits/482efe2d2262209926a775e56da3df6a89c54f95))
|
|
75
|
+
|
|
76
|
+
### [1.0.1](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@1.0.1..@atlassian/i18n-properties-loader@1.0.0) (2021-08-26)
|
|
77
|
+
|
|
78
|
+
**Note:** We updated internal dependencies
|
|
79
|
+
|
|
80
|
+
## [1.0.0](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@1.0.0..@atlassian/i18n-properties-loader@0.10.1) (2021-07-01)
|
|
81
|
+
|
|
82
|
+
### ⚠ BREAKING CHANGES
|
|
83
|
+
|
|
84
|
+
- We removed support for Node 10. The minimum required version is Node 12 now.
|
|
85
|
+
|
|
86
|
+
### Features
|
|
87
|
+
|
|
88
|
+
- drop support for Node 10 ([2ef1e83](https://bitbucket.org/atlassianlabs/fe-server/commits/2ef1e831cc30f0ec78884d72815d773ae401cc7e))
|
|
89
|
+
|
|
90
|
+
### [0.10.1](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@0.10.1..@atlassian/i18n-properties-loader@0.10.0) (2021-03-08)
|
|
91
|
+
|
|
92
|
+
### Bug Fixes
|
|
93
|
+
|
|
94
|
+
- **deps:** remove webpack cli dependency ([c957fb3](https://bitbucket.org/atlassianlabs/fe-server/commits/c957fb3741348478c885d4af443b14717ea02c95))
|
|
95
|
+
- **deps:** SPFE-346 Update ajv to fix vulnerabilities ([10cba18](https://bitbucket.org/atlassianlabs/fe-server/commits/10cba18c82fd7d4c368b8bb7cfab7d8eada56cf7))
|
|
96
|
+
- **deps:** update dependency schema-utils to v3 ([ce193c2](https://bitbucket.org/atlassianlabs/fe-server/commits/ce193c298dc28abf175939b8a1f86124e0e5f4cc))
|
|
97
|
+
- **deps:** Update Node version ([1dadcca](https://bitbucket.org/atlassianlabs/fe-server/commits/1dadcca42ac461410dabd8e844249cdf80e516a9))
|
|
98
|
+
|
|
99
|
+
## 0.10.0 (2021-01-18)
|
|
100
|
+
|
|
101
|
+
- feat: SPFE-275 Add support for webpack 5 to soy-loader ([edc7190](https://bitbucket.org/atlassianlabs/fe-server/commits/edc7190))
|
|
102
|
+
|
|
103
|
+
## 0.10.0-alpha.0 (2021-01-13)
|
|
104
|
+
|
|
105
|
+
- feat: SPFE-268 Add support for webpack 5 ([5a8b215](https://bitbucket.org/atlassianlabs/fe-server/commits/5a8b215))
|
|
106
|
+
|
|
107
|
+
## 0.9.0 (2020-06-25)
|
|
108
|
+
|
|
109
|
+
- chore: mark the exported RegExp as internals ([b487105](https://bitbucket.org/atlassianlabs/fe-server/commits/b487105))
|
|
110
|
+
- chore: migrate soy-loader tests to jest ([148dbef](https://bitbucket.org/atlassianlabs/fe-server/commits/148dbef))
|
|
111
|
+
- chore: run all tests with jest ([bd4f4e2](https://bitbucket.org/atlassianlabs/fe-server/commits/bd4f4e2))
|
|
112
|
+
- chore: update script commands ([d717342](https://bitbucket.org/atlassianlabs/fe-server/commits/d717342))
|
|
113
|
+
- fix(issue #4): add test cases that prove the quotations doesn't work well ([1012d1b](https://bitbucket.org/atlassianlabs/fe-server/commits/1012d1b)), closes [#4](https://bitbucket.org/atlassianlabs/fe-server/issue/4)
|
|
114
|
+
- fix(issue #4): Fix the message quotation that was inconsistent with Java MessageFormat spec https:// ([1572341](https://bitbucket.org/atlassianlabs/fe-server/commits/1572341))
|
|
115
|
+
- chore: update dependencies ([38f5a33](https://bitbucket.org/atlassianlabs/fe-server/commits/38f5a33))
|
|
116
|
+
|
|
117
|
+
## 0.8.0 (2020-05-11)
|
|
118
|
+
|
|
119
|
+
- chore: Add note about minimal requirements ([ee38cec](https://bitbucket.org/atlassianlabs/fe-server/commits/ee38cec))
|
|
120
|
+
- chore: downgrade to Node version 10 ([9fc7bab](https://bitbucket.org/atlassianlabs/fe-server/commits/9fc7bab))
|
|
121
|
+
- chore: Update minimal Node version to version 12 so we can support 'String.proptotype.matchall' ([cb0ed25](https://bitbucket.org/atlassianlabs/fe-server/commits/cb0ed25))
|
|
122
|
+
|
|
123
|
+
## [0.7.4](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@0.7.4..@atlassian/i18n-properties-loader@0.7.3) (2020-04-21)
|
|
124
|
+
|
|
125
|
+
**Note:** Version bump only for package @atlassian/i18n-properties-loader
|
|
126
|
+
|
|
127
|
+
## [0.7.3](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@0.7.3..@atlassian/i18n-properties-loader@0.7.1) (2020-02-07)
|
|
128
|
+
|
|
129
|
+
### Bug Fixes
|
|
130
|
+
|
|
131
|
+
- remove the console.log ([3d92754](https://bitbucket.org/atlassianlabs/fe-server/commits/3d9275465820339e6b8330ad3b6ec6cac023f34e))
|
|
132
|
+
|
|
133
|
+
## [0.7.2](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@0.7.2..@atlassian/i18n-properties-loader@0.7.1) (2020-01-28)
|
|
134
|
+
|
|
135
|
+
### Bug Fixes
|
|
136
|
+
|
|
137
|
+
- remove the console.log ([3d92754](https://bitbucket.org/atlassianlabs/fe-server/commits/3d9275465820339e6b8330ad3b6ec6cac023f34e))
|
|
138
|
+
|
|
139
|
+
## [0.7.1](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@0.7.1..@atlassian/i18n-properties-loader@0.7.0) (2020-01-27)
|
|
140
|
+
|
|
141
|
+
**Note:** Version bump only for package @atlassian/i18n-properties-loader
|
|
142
|
+
|
|
143
|
+
# [0.7.0](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@0.7.0..@atlassian/i18n-properties-loader@0.5.0) (2020-01-25)
|
|
144
|
+
|
|
145
|
+
### Features
|
|
146
|
+
|
|
147
|
+
- **webpack:** Add missing compatibility for native ESM and ts-loader ([afa4a1f](https://bitbucket.org/atlassianlabs/fe-server/commits/afa4a1f95ee74d6491a63699469bb54b3c515b55))
|
|
148
|
+
|
|
149
|
+
# [0.6.0](https://bitbucket.org/atlassianlabs/fe-server/branches/compare/@atlassian/i18n-properties-loader@0.6.0..@atlassian/i18n-properties-loader@0.5.0) (2020-01-25)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
|
10
|
+
orientation.
|
|
11
|
+
|
|
12
|
+
## Our Standards
|
|
13
|
+
|
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
|
15
|
+
include:
|
|
16
|
+
|
|
17
|
+
- Using welcoming and inclusive language
|
|
18
|
+
- Being respectful of differing viewpoints and experiences
|
|
19
|
+
- Gracefully accepting constructive criticism
|
|
20
|
+
- Focusing on what is best for the community
|
|
21
|
+
- Showing empathy towards other community members
|
|
22
|
+
|
|
23
|
+
Examples of unacceptable behavior by participants include:
|
|
24
|
+
|
|
25
|
+
- The use of sexualized language or imagery and unwelcome sexual attention or
|
|
26
|
+
advances
|
|
27
|
+
- Trolling, insulting/derogatory comments, and personal or political attacks
|
|
28
|
+
- Public or private harassment
|
|
29
|
+
- Publishing others' private information, such as a physical or electronic
|
|
30
|
+
address, without explicit permission
|
|
31
|
+
- Other conduct which could reasonably be considered inappropriate in a
|
|
32
|
+
professional setting
|
|
33
|
+
|
|
34
|
+
## Our Responsibilities
|
|
35
|
+
|
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
|
38
|
+
response to any instances of unacceptable behavior.
|
|
39
|
+
|
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
|
44
|
+
threatening, offensive, or harmful.
|
|
45
|
+
|
|
46
|
+
## Scope
|
|
47
|
+
|
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
|
49
|
+
when an individual is representing the project or its community. Examples of
|
|
50
|
+
representing a project or community include using an official project e-mail
|
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
|
53
|
+
further defined and clarified by project maintainers.
|
|
54
|
+
|
|
55
|
+
## Enforcement
|
|
56
|
+
|
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported
|
|
58
|
+
by contacting a project maintainer. Complaints will result in a response and be
|
|
59
|
+
reviewed and investigated in a way that is deemed necessary and appropriate to the
|
|
60
|
+
circumstances. Maintainers are obligated to maintain confidentiality with regard to the
|
|
61
|
+
reporter of an incident.
|
|
62
|
+
|
|
63
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
64
|
+
faith may face temporary or permanent repercussions as determined by other
|
|
65
|
+
members of the project's leadership.
|
|
66
|
+
|
|
67
|
+
## Attribution
|
|
68
|
+
|
|
69
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
70
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
|
71
|
+
|
|
72
|
+
[homepage]: http://contributor-covenant.org
|
|
73
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright @ 2019 Atlassian Pty Ltd
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# @atlassian/i18n-properties-loader
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
A webpack loader for i18n `*.properties` files that can be used in Atlassian Server products and plugins.
|
|
8
|
+
|
|
9
|
+
## Motivation
|
|
10
|
+
|
|
11
|
+
If your work with the modern Front-End Server code there is a good chance you are already using the
|
|
12
|
+
[Atlassian Web-Resource webpack Plugin](https://www.npmjs.com/package/atlassian-webresource-webpack-plugin).
|
|
13
|
+
If you did configure your webpack to use development server you might be missing displaying translation phrases right
|
|
14
|
+
now.
|
|
15
|
+
|
|
16
|
+
The `@atlassian/i18n-properties-loader` can help you with solving that problem. It's a webpack loader that allows you
|
|
17
|
+
displaying translation phrases during your development workflow and at the same time uses the WRM.
|
|
18
|
+
|
|
19
|
+
For more information about the translations system check the Atlassian Development documentation page:
|
|
20
|
+
|
|
21
|
+
- [Internationalising your plugin](https://developer.atlassian.com/server/framework/atlassian-sdk/internationalising-your-plugin/)
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
npm install @atlassian/i18n-properties-loader --save-dev
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage example
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
// webpack.config.js
|
|
33
|
+
|
|
34
|
+
const myI18nFiles = [
|
|
35
|
+
'foo/i18n/my-translation-file.properties',
|
|
36
|
+
'foo/bar/i18n/my-other-translation-file.properties',
|
|
37
|
+
'bar/i18n/some-translation-file.properties',
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
module: {
|
|
42
|
+
rules: [
|
|
43
|
+
{
|
|
44
|
+
test: /\.jsx?$/,
|
|
45
|
+
include: ['src'],
|
|
46
|
+
|
|
47
|
+
use: [
|
|
48
|
+
{
|
|
49
|
+
loader: '@atlassian/i18n-properties-loader',
|
|
50
|
+
options: {
|
|
51
|
+
i18nFiles: myI18nFiles,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
{
|
|
56
|
+
loader: 'babel-loader',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Options
|
|
66
|
+
|
|
67
|
+
- `i18nFiles` list of paths to your `*.properties` files (required)
|
|
68
|
+
- `disabled` disables the loader; can we used to disabled in production bundle (optional, default `false`)
|
|
69
|
+
|
|
70
|
+
### Creating production bundle
|
|
71
|
+
|
|
72
|
+
The loader is required only in development mode. You should remember to disable it when you are creaing production bundle.
|
|
73
|
+
|
|
74
|
+
With webpack and its [`mode` configuration](https://webpack.js.org/configuration/mode/) you can intercept the currently selected mode inside your webpack configuration and disable the loader accoridngly:
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
// webpack.config.js
|
|
78
|
+
|
|
79
|
+
module.exports = (env, argv) => {
|
|
80
|
+
const isDevelopmentMode = argv.mode === 'development'; // 1. Check if we are running webpack in "development" mode
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
module: {
|
|
84
|
+
rules: [
|
|
85
|
+
{
|
|
86
|
+
test: /\.jsx?$/,
|
|
87
|
+
include: ['src'],
|
|
88
|
+
|
|
89
|
+
use: [
|
|
90
|
+
{
|
|
91
|
+
loader: '@atlassian/i18n-properties-loader',
|
|
92
|
+
options: {
|
|
93
|
+
i18nFiles,
|
|
94
|
+
disabled: !isDevelopmentMode, // 2. Skip and disable loader when webpack is running in "production" mode
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
{
|
|
99
|
+
loader: 'babel-loader',
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## React i18n helper
|
|
110
|
+
|
|
111
|
+
This package plays nice with the [`@atlassian/wrm-react-i18n`](https://www.npmjs.com/package/@atlassian/wrm-react-i18n)
|
|
112
|
+
when you want to use `I18n.getText()` translation helper with React components.
|
|
113
|
+
|
|
114
|
+
You can check the package description for more details and learn how to integrate it with your webpack configuration.
|
|
115
|
+
|
|
116
|
+
## Additional links
|
|
117
|
+
|
|
118
|
+
- [https://www.npmjs.com/package/@atlassian/i18n-properties-loader](https://www.npmjs.com/package/@atlassian/i18n-properties-loader)
|
|
119
|
+
- [https://www.npmjs.com/package/@atlassian/wrm-react-i18n](https://www.npmjs.com/package/@atlassian/wrm-react-i18n)
|
|
120
|
+
- [https://www.npmjs.com/package/atlassian-webresource-webpack-plugin](https://www.npmjs.com/package/atlassian-webresource-webpack-plugin)
|
|
121
|
+
|
|
122
|
+
## Minimum requirements
|
|
123
|
+
|
|
124
|
+
This plugin is compatible with:
|
|
125
|
+
|
|
126
|
+
- webpack 4.0+ and 5.0+
|
|
127
|
+
- Node 12+
|
package/index.js
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/* eslint-env node */
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const debounce = require('lodash.debounce');
|
|
4
|
+
const { PropertiesFile } = require('java-properties');
|
|
5
|
+
const { getOptions } = require('loader-utils');
|
|
6
|
+
const { validate } = require('schema-utils');
|
|
7
|
+
const rx = require('./rx');
|
|
8
|
+
|
|
9
|
+
const optionsSchema = {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
i18nFiles: {
|
|
13
|
+
type: 'array',
|
|
14
|
+
description: 'A list of i18n *.properties files',
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
disabled: {
|
|
18
|
+
type: 'boolean',
|
|
19
|
+
description: 'Should the loader be disabled. By default false',
|
|
20
|
+
default: false,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
additionalProperties: false,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// See RegExp in atlassian-plugins-webresource-plugin
|
|
27
|
+
// https://bitbucket.org/atlassian/atlassian-plugins-webresource/src/master/atlassian-plugins-webresource-plugin/src/main/java/com/atlassian/webresource/plugin/i18n/JsI18nTransformer.java#lines-48:63
|
|
28
|
+
const i18nRegExp = rx('g')`
|
|
29
|
+
(?:
|
|
30
|
+
# Optional module identifier
|
|
31
|
+
(?:
|
|
32
|
+
# Optional namespace identifier
|
|
33
|
+
|
|
34
|
+
(?<namespace>
|
|
35
|
+
# "identifiers can contain only alphanumeric characters (or "$" or "_"), and may not start
|
|
36
|
+
# with a digit" https://developer.mozilla.org/en-US/docs/Glossary/Identifier
|
|
37
|
+
(?:[A-Za-z$_][0-9A-Za-z$_]{0,1000})?
|
|
38
|
+
|
|
39
|
+
# optional ["default"] or ['default'] for babel 5, see PLUGWEB-306
|
|
40
|
+
(?:\[["']default["']])?
|
|
41
|
+
|
|
42
|
+
# optional .default for babel 6
|
|
43
|
+
(?:\.default)?
|
|
44
|
+
|
|
45
|
+
) # end namespace identifier
|
|
46
|
+
|
|
47
|
+
# Babel 6 and Babel 7 + Webpack 4
|
|
48
|
+
(?:\.I18n|\[['"]I18n['"]])
|
|
49
|
+
|
|
50
|
+
) # end optional module identifier
|
|
51
|
+
|
|
52
|
+
# A call without a module identifier with a required word boundary
|
|
53
|
+
|(?:\bI18n)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# call to getText function
|
|
57
|
+
\.getText
|
|
58
|
+
|
|
59
|
+
# start parenthesis
|
|
60
|
+
\(\s*
|
|
61
|
+
|
|
62
|
+
# single or double quote world
|
|
63
|
+
["'](?<key>[\w\.\-\s]+)["']
|
|
64
|
+
|
|
65
|
+
# end parenthesis, or start-of-args
|
|
66
|
+
\s*(?<endParam>[,|\)])
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
const namedEsmImportRegexp = rx('gm')`
|
|
70
|
+
^\s? # possible white-spaces at the beginning
|
|
71
|
+
|
|
72
|
+
import\s+
|
|
73
|
+
|
|
74
|
+
\{\s*I18n\s*\}\s+ # The named ESM import
|
|
75
|
+
|
|
76
|
+
from\s+
|
|
77
|
+
['"\`]
|
|
78
|
+
|
|
79
|
+
(?<module> # List of supported modules
|
|
80
|
+
(?:
|
|
81
|
+
# NPM package "@atlassian/wrm-react-i18n"
|
|
82
|
+
@atlassian\/wrm-react-i18n
|
|
83
|
+
|
|
|
84
|
+
# Built-in WRM module
|
|
85
|
+
wrm\/i18n
|
|
86
|
+
)
|
|
87
|
+
)
|
|
88
|
+
['"\`]
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
let i18nCache = new Map();
|
|
92
|
+
|
|
93
|
+
// small enough that i18n file changes are propagated. Large enough for cache hits.
|
|
94
|
+
const accessThreshold = 1000;
|
|
95
|
+
|
|
96
|
+
const clearCacheWhenIdle = debounce(() => {
|
|
97
|
+
i18nCache = new Map();
|
|
98
|
+
}, accessThreshold);
|
|
99
|
+
|
|
100
|
+
function processI18nFiles(i18nFiles) {
|
|
101
|
+
clearCacheWhenIdle();
|
|
102
|
+
|
|
103
|
+
if (i18nCache.has(i18nFiles)) {
|
|
104
|
+
return i18nCache.get(i18nFiles);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const missingFiles = i18nFiles.filter((file) => !fs.existsSync(file) || !fs.statSync(file).isFile());
|
|
108
|
+
|
|
109
|
+
if (missingFiles.length) {
|
|
110
|
+
const err = new Error('I18n Loader: i18n files are missing\n\t' + missingFiles.join('\n\t'));
|
|
111
|
+
err.missingFiles = missingFiles;
|
|
112
|
+
|
|
113
|
+
throw err;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const properties = new PropertiesFile();
|
|
117
|
+
i18nFiles.forEach((file) => properties.addFile(file));
|
|
118
|
+
|
|
119
|
+
i18nCache.set(i18nFiles, properties);
|
|
120
|
+
|
|
121
|
+
return properties;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = function (source, map) {
|
|
125
|
+
const options = getOptions(this);
|
|
126
|
+
validate(optionsSchema, options, { name: 'i18n-properties-loader' });
|
|
127
|
+
|
|
128
|
+
const { i18nFiles = [], disabled = false } = options;
|
|
129
|
+
|
|
130
|
+
// Skip loader when e.g. we are not running webpack in dev mode
|
|
131
|
+
if (disabled) {
|
|
132
|
+
return this.callback(null, source, map);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
i18nFiles.forEach((file) => this.addDependency(file));
|
|
136
|
+
|
|
137
|
+
const callback = this.async();
|
|
138
|
+
|
|
139
|
+
const isNamedEsmImport = Boolean(source.match(namedEsmImportRegexp));
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
let esmFormatFunctionName = 'format';
|
|
143
|
+
|
|
144
|
+
// Replace the named ESM import of "getText" call to "format"
|
|
145
|
+
if (isNamedEsmImport) {
|
|
146
|
+
esmFormatFunctionName = '__format__';
|
|
147
|
+
|
|
148
|
+
source = source.replace(namedEsmImportRegexp, (match, module) => {
|
|
149
|
+
return `\nimport { format as ${esmFormatFunctionName} } from "${module}"`;
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Replace "I18n.getText('some.translation.key', [param1], [paramN])" with the real translation string
|
|
154
|
+
const properties = processI18nFiles(i18nFiles);
|
|
155
|
+
const newSource = source.replace(i18nRegExp, (...args) => {
|
|
156
|
+
const { namespace, key, endParam } = args.pop();
|
|
157
|
+
const escapedKey = key.replace(/\s/g, '\\ ');
|
|
158
|
+
|
|
159
|
+
let message = properties.get(escapedKey);
|
|
160
|
+
|
|
161
|
+
if (message === undefined) {
|
|
162
|
+
this.emitWarning(`I18n Loader: Can not find "${key}" phrase ID in your *.properties files`);
|
|
163
|
+
|
|
164
|
+
// Fallback to value of "key" so we can avoid breaking JavaScript syntax when
|
|
165
|
+
// we have additional parameters we need to substitute
|
|
166
|
+
message = key;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const formatFunctionCall = isNamedEsmImport ? esmFormatFunctionName : `${namespace}.format`;
|
|
170
|
+
|
|
171
|
+
// Output string
|
|
172
|
+
const escapedMessage = JSON.stringify(message);
|
|
173
|
+
|
|
174
|
+
if (endParam === ',') {
|
|
175
|
+
// We don't need to unquote the string since the WRM.format function has all the logic to do that
|
|
176
|
+
return `${formatFunctionCall}(${escapedMessage},`;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return unquoteMessage(escapedMessage);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
callback(null, newSource, map);
|
|
183
|
+
} catch (error) {
|
|
184
|
+
if (error.missingFiles) {
|
|
185
|
+
error.missingFiles.forEach((file) => this.emitError(`I18n Loader: File ${file} does not exists`));
|
|
186
|
+
} else {
|
|
187
|
+
this.emitError(error);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
callback(error);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// https://docs.oracle.com/javase/8/docs/api/java/text/MessageFormat.html
|
|
195
|
+
function unquoteMessage(input) {
|
|
196
|
+
const match = input.match(/'/g);
|
|
197
|
+
|
|
198
|
+
if (!match) {
|
|
199
|
+
return input;
|
|
200
|
+
}
|
|
201
|
+
// Edge-cases: If there is an only single quote character this means that the message is misformatted.
|
|
202
|
+
// The ' char should be used in pairs to quote values.
|
|
203
|
+
if (match.length === 1) {
|
|
204
|
+
return input.replace("'", '');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
input = input
|
|
208
|
+
// Unquote any quoted values
|
|
209
|
+
// Within a String, a pair of single quotes can be used to quote any arbitrary characters except single quotes.
|
|
210
|
+
.replace(/'([^']+)'/g, '$1')
|
|
211
|
+
|
|
212
|
+
// Unquote remaining single quotes
|
|
213
|
+
// A single quote itself must be represented by doubled single quotes '' throughout a String
|
|
214
|
+
.replace("''", "'");
|
|
215
|
+
|
|
216
|
+
return input;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** @visibleForTesting */
|
|
220
|
+
module.exports._i18nRegExp = i18nRegExp;
|
|
221
|
+
module.exports._namedEsmImportRegexp = namedEsmImportRegexp;
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atlassian/i18n-properties-loader",
|
|
3
|
+
"version": "0.0.0-snapshot.0",
|
|
4
|
+
"description": "A webpack loader for i18n *.properties files that can be used in Atlassian Server products",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+ssh://git@bitbucket.org/atlassianlabs/fe-server.git",
|
|
9
|
+
"directory": "packages/i18n-properties-loader"
|
|
10
|
+
},
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"registry": "https://registry.npmjs.org/"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"test": "jest --verbose",
|
|
16
|
+
"test:watch": "jest --watch --verbose",
|
|
17
|
+
"test:ci": "jest --ci --silent=false"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"react",
|
|
21
|
+
"i18n",
|
|
22
|
+
"frontend",
|
|
23
|
+
"server",
|
|
24
|
+
"atlassian",
|
|
25
|
+
"dc",
|
|
26
|
+
"front-end",
|
|
27
|
+
"bitbucket",
|
|
28
|
+
"jira",
|
|
29
|
+
"confluence",
|
|
30
|
+
"jsd",
|
|
31
|
+
"webpack",
|
|
32
|
+
"loader",
|
|
33
|
+
"wrm"
|
|
34
|
+
],
|
|
35
|
+
"author": "Atlassian Pty Ltd.",
|
|
36
|
+
"license": "Apache-2.0",
|
|
37
|
+
"homepage": "https://bitbucket.org/atlassianlabs/fe-server",
|
|
38
|
+
"bugs": "https://ecosystem.atlassian.net/jira/software/c/projects/SPFE/issues/",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"java-properties": "^1.0.2",
|
|
41
|
+
"loader-utils": "2.0.4",
|
|
42
|
+
"lodash.debounce": "^4.0.8",
|
|
43
|
+
"schema-utils": "^3.0.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"webpack": "^5.0.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"atlassian-webresource-webpack-plugin": "^0.0.0-snapshot.0",
|
|
50
|
+
"jest": "27.4.3",
|
|
51
|
+
"webpack": "5.90.3"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=12"
|
|
55
|
+
},
|
|
56
|
+
"gitHead": "c201fc7caf8aeb31df5cfcc4757f129b922d1ea9"
|
|
57
|
+
}
|
package/rx.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates new regex.
|
|
3
|
+
* Source: https://gist.github.com/shannonmoeller/b4f6fbab2ffec56213e7
|
|
4
|
+
*
|
|
5
|
+
* @param flags
|
|
6
|
+
* @return {RegExp}
|
|
7
|
+
*/
|
|
8
|
+
module.exports = function rx(flags) {
|
|
9
|
+
const trailingComments = /\s+#.*$/gm;
|
|
10
|
+
const surroundingWhitespace = /^\s+|\s+$/gm;
|
|
11
|
+
const literalNewlines = /[\r\n]/g;
|
|
12
|
+
|
|
13
|
+
return (strings, ...values) => {
|
|
14
|
+
function toPattern(pattern, rawString, i) {
|
|
15
|
+
let value = values[i];
|
|
16
|
+
|
|
17
|
+
if (value == null) {
|
|
18
|
+
return pattern + rawString;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (value instanceof RegExp) {
|
|
22
|
+
value = value.source;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return pattern + rawString + value;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const compiledPattern = strings.raw
|
|
29
|
+
.reduce(toPattern, '')
|
|
30
|
+
.replace(trailingComments, '')
|
|
31
|
+
.replace(surroundingWhitespace, '')
|
|
32
|
+
.replace(literalNewlines, '');
|
|
33
|
+
|
|
34
|
+
return new RegExp(compiledPattern, flags);
|
|
35
|
+
};
|
|
36
|
+
};
|