Skip to content

Commit 5d49f93

Browse files
authored
feat: localization #48 (#49)
1 parent 3f29f01 commit 5d49f93

19 files changed

+340
-71
lines changed

.storybook/frenchTheme.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { createMuiTheme } from "@material-ui/core/styles";
2+
import { frFR } from '@material-ui/core/locale';
3+
4+
const frenchTheme = createMuiTheme({
5+
name: 'Dark French Theme',
6+
palette: {
7+
type: 'dark',
8+
},
9+
}, frFR);
10+
11+
export default frenchTheme;

.storybook/preview.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import { withThemesProvider } from 'storybook-addon-styled-component-theme';
77
import ThemeProvider from './ThemeProvider';
88
import lightTheme from './lightTheme';
99
import darkTheme from './darkTheme';
10+
import frenchTheme from './frenchTheme';
1011

11-
const themes = [lightTheme, darkTheme];
12+
const themes = [lightTheme, darkTheme, frenchTheme];
1213
addDecorator(withThemesProvider(themes, ThemeProvider));
1314
addDecorator(withKnobs);
1415
addDecorator(storyFn => <div style={{ padding: '48px' }}>{storyFn()}</div>);

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ const palette = {
146146
black: 'black',
147147
white: 'white',
148148
pink: 'pink',
149-
darkBlue: 'darkBlue',
149+
darkblue: 'darkblue',
150150
};
151151

152152
export const Container = () => (

src/components/ColorBox/index.jsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ const StyledBox = styled.div`
8484
}
8585
`;
8686

87-
const ColorBox = ({ value, palette, inputFormats, deferred, onChange: _onChange, ...props }) => {
88-
let color = validateColor(value);
87+
const ColorBox = ({ value, palette, inputFormats, deferred, onChange: _onChange, translate, ...props }) => {
88+
let color = validateColor(value, translate);
8989
let onChange = _onChange;
9090
let onDeferredChange;
9191
if (deferred) {
@@ -136,6 +136,7 @@ const ColorBox = ({ value, palette, inputFormats, deferred, onChange: _onChange,
136136
format={input}
137137
className="muicc-colorbox-input"
138138
onChange={handleInputChange}
139+
translate={translate}
139140
/>
140141
))}
141142
</div>
@@ -175,12 +176,12 @@ const ColorBox = ({ value, palette, inputFormats, deferred, onChange: _onChange,
175176
{palette && (
176177
<>
177178
<Divider />
178-
<ColorPalette size={26.65} palette={palette} onSelect={handlePaletteSelection} />
179+
<ColorPalette size={26.65} palette={palette} onSelect={handlePaletteSelection} translate={translate} />
179180
</>
180181
)}
181182
{deferred && (
182183
<div className="muicc-colorbox-controls">
183-
<Button onClick={handleSet}>Set</Button>
184+
<Button onClick={handleSet}>{translate('Set')}</Button>
184185
</div>
185186
)}
186187
</StyledBox>
@@ -194,13 +195,18 @@ ColorBox.propTypes = {
194195
palette: CommonTypes.palette,
195196
inputFormats: CommonTypes.inputFormats,
196197
onChange: PropTypes.func.isRequired,
198+
/**
199+
The localization utils function
200+
*/
201+
translate: PropTypes.func,
197202
};
198203

199204
ColorBox.defaultProps = {
200205
value: undefined,
201206
deferred: false,
202207
palette: undefined,
203208
inputFormats: ['hex', 'rgb'],
209+
translate: v => v,
204210
};
205211

206212
export default uncontrolled(ColorBox);

src/components/ColorButton.jsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ const Styleddiv = styled.div`
4848
- Use a ColorButton to select a predefined color by clicking on this button.
4949
- If the color is not valid or transparent a crossed background is displayed.
5050
*/
51-
const ColorButton = ({ color: c, size, borderWidth, borderColor, forwardRef, tooltip, ...props }) => {
52-
const color = ColorTool.validateColor(c);
51+
const ColorButton = ({ color: c, size, borderWidth, borderColor, forwardRef, tooltip, translate, ...props }) => {
52+
const color = ColorTool.validateColor(c, translate);
53+
const translated = translate(tooltip);
5354
const style = color.css; // || { backgroundColor: ColorTool.getCssColor(color) };
5455
let l = color.hsl[2] - 10;
5556
if (l < 30) l = color.hsl[2] + 50;
@@ -72,7 +73,7 @@ const ColorButton = ({ color: c, size, borderWidth, borderColor, forwardRef, too
7273
);
7374
if (tooltip) {
7475
return (
75-
<Tooltip title={tooltip}>
76+
<Tooltip title={translated}>
7677
<Styleddiv>{component}</Styleddiv>
7778
</Tooltip>
7879
);
@@ -101,6 +102,10 @@ ColorButton.propTypes = {
101102
A tooltip could be added to the button to display the color name or value
102103
*/
103104
tooltip: PropTypes.string,
105+
/**
106+
The localization utils function
107+
*/
108+
translate: PropTypes.func,
104109
/**
105110
Internal usage
106111
*/
@@ -113,6 +118,7 @@ ColorButton.defaultProps = {
113118
borderColor: undefined,
114119
forwardRef: undefined,
115120
tooltip: undefined,
121+
translate: v => v,
116122
};
117123

118124
export default ColorButton;

src/components/ColorInput.jsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ const StyledRoot = styled.div`
3434
}
3535
`;
3636

37-
const ColorInput = ({ value, format, onChange, forwardRef, ...props }) => {
38-
const color = ColorTool.validateColor(value);
37+
const ColorInput = ({ value, format, onChange, forwardRef, translate, ...props }) => {
38+
const color = ColorTool.validateColor(value, translate);
3939
let field;
4040
let components;
4141

@@ -85,7 +85,7 @@ const ColorInput = ({ value, format, onChange, forwardRef, ...props }) => {
8585
if (format === 'plain') {
8686
field = buildInput('color-plain', 'Color', color.raw);
8787
} else {
88-
components = ColorTool.getComponents(color, format);
88+
components = ColorTool.getComponents(color, format, translate);
8989
const names = Object.keys(components);
9090
field = (
9191
<StyledRoot ref={forwardRef}>
@@ -109,12 +109,20 @@ ColorInput.propTypes = {
109109
value: CommonTypes.color,
110110
format: PropTypes.string,
111111
onChange: PropTypes.func.isRequired,
112+
/**
113+
The localization utils function
114+
*/
115+
translate: PropTypes.func,
116+
/**
117+
Internal usage
118+
*/
112119
forwardRef: PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
113120
};
114121

115122
ColorInput.defaultProps = {
116123
value: '',
117124
format: 'plain',
125+
translate: undefined,
118126
forwardRef: undefined,
119127
};
120128

src/components/ColorPalette.jsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const StyledRoot = styled.div`
2424
}
2525
`;
2626

27-
const ColorPalette = ({ size, borderWidth, palette, onSelect }) => {
27+
const ColorPalette = ({ size, borderWidth, palette, translate, onSelect }) => {
2828
const handleSelectColor = name => {
2929
if (onSelect) onSelect(name, palette[name]);
3030
};
@@ -39,6 +39,7 @@ const ColorPalette = ({ size, borderWidth, palette, onSelect }) => {
3939
className="muicc-palette-button"
4040
borderWidth={borderWidth}
4141
tooltip={name}
42+
translate={translate}
4243
onClick={() => handleSelectColor(name)}
4344
/>
4445
))}
@@ -52,13 +53,18 @@ ColorPalette.propTypes = {
5253
palette: CommonTypes.palette.isRequired,
5354
forwardRef: PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
5455
onSelect: PropTypes.func,
56+
/**
57+
The localization utils function
58+
*/
59+
translate: PropTypes.func,
5560
};
5661

5762
ColorPalette.defaultProps = {
5863
borderWidth: 0,
5964
size: 24,
6065
forwardRef: undefined,
6166
onSelect: undefined,
67+
translate: undefined,
6268
};
6369

6470
export default ColorPalette;

src/components/ColorPicker.jsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,11 @@ const ColorPicker = ({
5353
onChange,
5454
onOpen,
5555
doPopup,
56+
translate,
5657
}) => {
5758
const refPicker = React.useRef();
5859
const [open, setOpen] = React.useState(openAtStart);
59-
60-
const color = ColorTool.validateColor(value);
60+
const color = ColorTool.validateColor(value, translate);
6161
const raw = getColorText(color);
6262
const handleClick = () => {
6363
const b = Boolean(refPicker.current);
@@ -88,6 +88,7 @@ const ColorPicker = ({
8888
deferred={deferred}
8989
palette={palette}
9090
inputFormats={inputFormats}
91+
translate={translate}
9192
onChange={handleColorChange}
9293
/>
9394
);
@@ -144,6 +145,10 @@ ColorPicker.propTypes = {
144145
onOpen: PropTypes.func,
145146
openAtStart: PropTypes.bool,
146147
doPopup: PropTypes.func,
148+
/**
149+
The localization utils function
150+
*/
151+
translate: PropTypes.func,
147152
};
148153

149154
ColorPicker.defaultProps = {
@@ -155,6 +160,7 @@ ColorPicker.defaultProps = {
155160
onOpen: undefined,
156161
openAtStart: false,
157162
doPopup: undefined,
163+
translate: undefined,
158164
};
159165

160166
export default uncontrolled(ColorPicker);

src/helpers/colorTool.js

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,11 @@
88
*/
99
import cssColors from './cssColors';
1010

11-
// Inspiration : https://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hexadecimal-in-javascript
12-
/* const getHexa = n => {
13-
let n = _n;
14-
if (n < 0) {
15-
n = 0xffffffff + n + 1;
16-
}
17-
let hexa = `00000000${n.toString(16).toUpperCase()}`.substr(-8);
18-
if (hexa.startsWith('00')) {
19-
hexa = hexa.substring(2);
20-
}
21-
return hexa;
22-
}; */
23-
2411
const getCssHexa = (n, alpha) => {
25-
// let hex = getHexa(n & 0xffffff);
2612
let hex = `00000000${(n & 0xffffff).toString(16).toUpperCase()}`.substr(-6);
2713
if (!Number.isNaN(alpha) && alpha !== undefined) {
2814
let a = alpha.toString(16).toUpperCase();
2915
if (a.length === 1) a = `0${a}`;
30-
/* if (hex.length === 8) {
31-
hex = hex.substring(2) + a;
32-
} else {
33-
hex += a;
34-
} */
3516
hex += a;
3617
}
3718
return hex;
@@ -235,12 +216,6 @@ const getMinMax = rgb => {
235216
};
236217

237218
const getHsl = rgb => {
238-
/* const r = rgb[0] / 255;
239-
const g = rgb[1] / 255;
240-
const b = rgb[2] / 255;
241-
const cmin = Math.min(r, g, b);
242-
const cmax = Math.max(r, g, b);
243-
const delta = cmax - cmin; */
244219
const { cmin, cmax, delta, r, g, b } = getMinMax(rgb);
245220
let h = 0;
246221
let s = 0;
@@ -264,11 +239,6 @@ const getHsl = rgb => {
264239
};
265240

266241
const getHsv = rgb => {
267-
/* const r = rgb[0] / 255;
268-
const g = rgb[1] / 255;
269-
const b = rgb[2] / 255;
270-
const max = Math.max(r, g, b);
271-
const min = Math.min(r, g, b); */
272242
const { cmax, delta, r, g, b } = getMinMax(rgb);
273243
if (delta === 0) return [0, 0, Math.round(cmax * 100)];
274244

@@ -417,31 +387,62 @@ const getCssColor = (color, format, noAlpha) => {
417387
return value;
418388
};
419389

420-
const validateColor = _color => (_color && _color.format && _color.name ? _color : parse(_color));
390+
let cssColorsTranslated;
391+
let language;
392+
393+
const validateColor = (_color, translate) => {
394+
let color = _color;
395+
let isTranslated = false;
396+
if (!(_color && _color.format && _color.name)) {
397+
color = _color;
398+
if (translate && typeof color === 'string') {
399+
if (!cssColorsTranslated || translate('language') !== language) {
400+
language = translate('language');
401+
cssColorsTranslated = {};
402+
Object.keys(cssColors).forEach(name => {
403+
cssColorsTranslated[translate(name)] = name;
404+
});
405+
}
406+
color = cssColorsTranslated[color] || color;
407+
isTranslated = color !== _color;
408+
}
409+
color = parse(color);
410+
if (color.name && translate) {
411+
color.translated = translate(color.name);
412+
if (isTranslated && color.translated) {
413+
color.name = color.translated;
414+
}
415+
if (color.error) color.error = translate(color.error);
416+
}
417+
} else if (color.error && translate) {
418+
color.error = translate(color.error);
419+
}
420+
return color;
421+
};
421422

422-
const getComponents = (_color, format) => {
423-
const color = validateColor(_color);
423+
const getComponents = (_color, format, translate = value => value) => {
424+
const color = validateColor(_color, translate);
424425
const components = {};
425426
if (format === 'rgb') {
426-
components.r = { value: color.rgb[0], format: 'integer', min: 0, max: 255, name: 'R' };
427-
components.g = { value: color.rgb[1], format: 'integer', min: 0, max: 255, name: 'G' };
428-
components.b = { value: color.rgb[2], format: 'integer', min: 0, max: 255, name: 'B' };
427+
components.r = { value: color.rgb[0], format: 'integer', min: 0, max: 255, name: translate('R') };
428+
components.g = { value: color.rgb[1], format: 'integer', min: 0, max: 255, name: translate('G') };
429+
components.b = { value: color.rgb[2], format: 'integer', min: 0, max: 255, name: translate('B') };
429430
} else if (format === 'hsv') {
430-
components.h = { value: color.hsv[0], format: 'integer', min: 0, max: 360, name: 'H', unit: '°' };
431-
components.s = { value: color.hsv[1], format: 'integer', min: 0, max: 100, name: 'S', unit: '%' };
432-
components.v = { value: color.hsv[2], format: 'integer', min: 0, max: 100, name: 'V', unit: '%' };
431+
components.h = { value: color.hsv[0], format: 'integer', min: 0, max: 360, name: translate('H'), unit: '°' };
432+
components.s = { value: color.hsv[1], format: 'integer', min: 0, max: 100, name: translate('S'), unit: '%' };
433+
components.v = { value: color.hsv[2], format: 'integer', min: 0, max: 100, name: translate('V'), unit: '%' };
433434
} else if (format === 'hsl') {
434-
components.h = { value: color.hsl[0], format: 'integer', min: 0, max: 360, name: 'H', unit: '°' };
435-
components.s = { value: color.hsl[1], format: 'integer', min: 0, max: 100, name: 'S', unit: '%' };
436-
components.l = { value: color.hsl[2], format: 'integer', min: 0, max: 100, name: 'L', unit: '%' };
435+
components.h = { value: color.hsl[0], format: 'integer', min: 0, max: 360, name: translate('H'), unit: '°' };
436+
components.s = { value: color.hsl[1], format: 'integer', min: 0, max: 100, name: translate('S'), unit: '%' };
437+
components.l = { value: color.hsl[2], format: 'integer', min: 0, max: 100, name: translate('L'), unit: '%' };
437438
} else if (format === 'hex') {
438439
let { hex } = color;
439440
if (color.raw && typeof color.raw === 'string' && color.raw.startsWith('#')) {
440441
hex = color.raw.substring(1);
441442
}
442-
components.hex = { value: hex, format: 'hex', name: 'HEX', unit: '#' };
443+
components.hex = { value: hex, format: 'hex', name: translate('HEX'), unit: '#' };
443444
} else {
444-
components.value = color.value;
445+
components.value = translate(color.value);
445446
components.format = 'unknown';
446447
}
447448
return components;

stories/ColorBox.stories.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const palette = {
1515
black: 'black',
1616
white: 'white',
1717
pink: 'pink',
18-
darkBlue: 'darkBlue',
18+
darkblue: 'darkblue',
1919
};
2020

2121
export default {

0 commit comments

Comments
 (0)