Skip to content

Commit f72bfeb

Browse files
committed
Add support for all languages that dayjs supports
This partially fixes issue like #96. It will "only" translate the days of the week and month names. But with other customizations, you can get pretty close to a fully translated generated calendar. The UI for the configuration will be still in English, though. Still, makes sense to unlock this feature, cause it will allow folks to generate calendars in any language they want, including ones that are usually very neglected or marginalized.
1 parent f598b41 commit f72bfeb

File tree

6 files changed

+64
-27
lines changed

6 files changed

+64
-27
lines changed

src/config/i18n.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
import dayjs from 'dayjs';
2+
import dayjsLocales from 'dayjs/locale.json';
3+
14
export function i18nConfiguration( namespaces ) {
25
return {
36
debug: process.env.NODE_ENV === 'development',
47
fallbackLng: 'en',
58
load: 'currentOnly',
6-
supportedLngs: getSupportedLocales(),
9+
supportedLngs: dayjsLocales.map( ( ( { key } ) => key ) ),
710
ns: namespaces,
11+
lowerCaseLng: true,
812
interpolation: {
913
escapeValue: false, // not needed for react as it escapes by default
1014
},
@@ -14,7 +18,11 @@ export function i18nConfiguration( namespaces ) {
1418
export const webpackBackend = {
1519
type: 'backend',
1620
read: ( language, namespace, callback ) => {
17-
import( '../locales/' + language + '/' + namespace + '.json' )
21+
const languageToLoad =
22+
getFullySupportedLocales().includes( language )
23+
? language
24+
: 'en';
25+
import( '../locales/' + languageToLoad + '/' + namespace + '.json' )
1826
.then( ( resources ) => {
1927
callback( null, resources );
2028
} )
@@ -24,7 +32,7 @@ export const webpackBackend = {
2432
},
2533
};
2634

27-
export function getSupportedLocales() {
35+
export function getFullySupportedLocales() {
2836
const locales = require
2937
.context( '../locales', true, /app\.json$/ )
3038
.keys()
@@ -37,3 +45,18 @@ export function getSupportedLocales() {
3745
uniqueLocales.unshift( 'en' );
3846
return uniqueLocales;
3947
}
48+
49+
export function getPartiallySupportedLocales() {
50+
const fullySupportedLocales = getFullySupportedLocales();
51+
return dayjsLocales
52+
.filter( ( { key } ) => ! fullySupportedLocales.includes( key ) )
53+
.sort( ( languageA, languageB ) => languageA.name.localeCompare( languageB.name ) );
54+
}
55+
56+
export function handleLanguageChange( newLanguage, firstDayOfWeek = 1 ) {
57+
require( `dayjs/locale/${newLanguage}.js` );
58+
dayjs.locale( newLanguage );
59+
dayjs.updateLocale( newLanguage, {
60+
weekStart: firstDayOfWeek,
61+
} );
62+
}

src/configuration.jsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ class Configuration extends React.PureComponent {
5252
this.pdfWorker.onmessage = this.handlePdfWorkerMessage;
5353
}
5454

55+
componentDidMount() {
56+
i18n.on( 'languageChanged', this.handleLanguageChange );
57+
}
58+
59+
componentWillUnmount() {
60+
i18n.off( 'languageChanged', this.handleLanguageChange );
61+
}
62+
5563
componentDidUpdate( prevProps, prevState ) {
5664
if ( prevState.blobUrl && prevState.blobUrl !== this.state.blobUrl ) {
5765
// Each refresh generates a new blob - and it will be kept in the memory
@@ -66,6 +74,12 @@ class Configuration extends React.PureComponent {
6674
this.setState( { ...hydrateFromObject( newConfig ) } );
6775
};
6876

77+
handleLanguageChange = () => {
78+
dayjs.updateLocale( i18n.language, {
79+
weekStart: this.state.firstDayOfWeek,
80+
} );
81+
};
82+
6983
handleFieldChange = ( event ) => {
7084
const value =
7185
event.target.type !== 'checkbox'

src/index.js

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import dayjs from 'dayjs';
21
import i18n from 'i18next';
32
import LanguageDetector from 'i18next-browser-languagedetector';
43
import React, { Suspense } from 'react';
@@ -9,7 +8,7 @@ import { initReactI18next } from 'react-i18next';
98
import './index.css';
109

1110
import 'config/dayjs';
12-
import { i18nConfiguration, webpackBackend } from 'config/i18n';
11+
import { handleLanguageChange, i18nConfiguration, webpackBackend } from 'config/i18n';
1312
import Loader from 'loader';
1413

1514
// eslint-disable-next-line import/no-named-as-default-member
@@ -22,14 +21,7 @@ i18n
2221
} );
2322

2423
i18n.on( 'languageChanged', ( newLanguage ) => {
25-
// This is needed for locales like pt-BR. i18next expects pt-BR,
26-
// while dayjs expects pt-br.
27-
const dayjsLanguage = newLanguage.toLowerCase();
28-
require( 'dayjs/locale/' + dayjsLanguage + '.js' );
29-
dayjs.locale( dayjsLanguage );
30-
dayjs.updateLocale( dayjsLanguage, {
31-
weekStart: 1, // Week starts on Monday
32-
} );
24+
handleLanguageChange( newLanguage );
3325
} );
3426

3527
const loadingComponent = (

src/locales/en/app.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
},
1010
"language": {
1111
"label": "Language",
12+
"full": "Fully translated languages",
13+
"partial": "Only days of the week and months",
1214
"en": "English",
1315
"cs": "Čeština",
1416
"da": "Dansk",

src/navigation.jsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Navbar from 'react-bootstrap/Navbar';
88
import Stack from 'react-bootstrap/Stack';
99
import { withTranslation } from 'react-i18next';
1010

11-
import { getSupportedLocales } from 'config/i18n';
11+
import { getFullySupportedLocales, getPartiallySupportedLocales } from 'config/i18n';
1212
import {
1313
HOME_PATH,
1414
CONFIGURATOR_PATH,
@@ -46,6 +46,14 @@ class Navigation extends React.Component {
4646
);
4747
};
4848

49+
renderPartialLanguageOption = ( { key, name } ) => {
50+
return (
51+
<option key={ key } value={ key }>
52+
{name}
53+
</option>
54+
);
55+
};
56+
4957
render() {
5058
const { t } = this.props;
5159
return (
@@ -86,7 +94,13 @@ class Navigation extends React.Component {
8694
value={ this.state.language }
8795
onChange={ this.handleLanguageSelection }
8896
>
89-
{getSupportedLocales().map( this.renderLanguageOption )}
97+
<optgroup label={ t( 'language.full' ) }>
98+
{getFullySupportedLocales().map( this.renderLanguageOption )}
99+
</optgroup>
100+
<optgroup label={ t( 'language.partial' ) }>
101+
{getPartiallySupportedLocales().map(
102+
this.renderPartialLanguageOption )}
103+
</optgroup>
90104
</Form.Select>
91105
</Stack>
92106
</Navbar.Collapse>

src/worker/pdf.worker.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
/* eslint-disable no-restricted-globals */
2-
import dayjs from 'dayjs';
32
import i18n, { changeLanguage } from 'i18next';
43
import LanguageDetector from 'i18next-browser-languagedetector';
54
import React from 'react';
65
import { initReactI18next } from 'react-i18next';
76

87
import {
8+
getFullySupportedLocales,
9+
handleLanguageChange,
910
i18nConfiguration,
1011
webpackBackend,
11-
getSupportedLocales,
1212
} from 'config/i18n';
1313
import { utf8ToBase64 } from 'lib/base64';
1414
import { Font, pdf } from 'lib/pdf';
@@ -28,7 +28,7 @@ i18n
2828
.use( initReactI18next )
2929
.init( {
3030
...i18nConfiguration( [ 'pdf', 'config' ] ),
31-
preload: getSupportedLocales(),
31+
preload: getFullySupportedLocales(),
3232
react: {
3333
useSuspense: false,
3434
},
@@ -55,15 +55,7 @@ self.onmessage = ( { data } ) => {
5555
const { firstDayOfWeek, language, isPreview } = data;
5656

5757
changeLanguage( language );
58-
59-
// This is needed for locales like pt-BR. i18next expects pt-BR,
60-
// while dayjs expects pt-br.
61-
const dayjsLanguage = language.toLowerCase();
62-
require( `dayjs/locale/${dayjsLanguage}.js` );
63-
dayjs.locale( dayjsLanguage );
64-
dayjs.updateLocale( dayjsLanguage, {
65-
weekStart: firstDayOfWeek,
66-
} );
58+
handleLanguageChange( language, firstDayOfWeek );
6759

6860
Font.registerHyphenationCallback( hyphenationCallback );
6961
Font.register( getFontDefinition( config.fontFamily ) );

0 commit comments

Comments
 (0)