Commit e50fc675 authored by Matija Obreza's avatar Matija Obreza
Browse files

i18n: Updated i18next configuration for GG-CE languages

- Supported languages are in `workspaces/i18n/src/data/Languages`
- Webpack will keep momentjs languages declared in `webpack-base.config.js`
parent bc2b0bba
const languages = [
{ label: 'English', short: 'en' },
{ label: 'French', short: 'fr' },
{ label: 'Arabic', short: 'ar', rtl: true },
{ label: 'Czech', short: 'cs' },
{ label: 'German', short: 'de' },
{ label: 'Chinese (Taiwan)', short: 'zh-TW' },
// { label: 'Czech', short: 'cs' },
// { label: 'German', short: 'de' },
{ label: 'Spanish', short: 'es' },
{ label: 'Farsi', short: 'fa', rtl: true },
{ label: 'French', short: 'fr' },
{ label: 'Portuguese', short: 'pt' },
// { label: 'Farsi', short: 'fa', rtl: true },
// { label: 'Portuguese', short: 'pt' },
{ label: 'Russian', short: 'ru' },
{ label: 'Chinese', short: 'zh' },
// { label: 'Chinese', short: 'zh' },
];
export default languages;
......@@ -5,15 +5,18 @@ export default function detectLocaleFromPath(virtualPath: string, path: string,
path = path.substring(virtualPath.length);
}
let found = 'en';
const language = path.match(/\/([a-zA-Z-]*)/g);
const language = path.match(/\/([a-zA-Z-]*)/);
console.log(`Path matches ${language}`);
if (language instanceof Array) {
const foundLang = language[index].replace('/', '');
languages.some((item, i, arr) => {
console.log(`Checking ${item.short} === ${foundLang}`);
if (item.short === foundLang) {
found = foundLang;
return true;
}
});
}
console.log(`Found lang=${found}`);
return found;
}
......@@ -25,9 +25,13 @@ const backend = {
console.log(`Locale not mapped for ${url}`);
return null;
}
console.log(`Loading ${localeMapping[url]} for ${url}`);
axios.get(localeMapping[url])
.then((resp) => resp as any)
.then((resp) => callback(JSON.stringify(resp.data), resp))
.then((resp) => {
console.log(`Loaded ${localeMapping[url]} for ${url}`);
callback(JSON.stringify(resp.data), resp);
})
.catch((err) => { console.log(`Failed to load mapped locale ${url}`, err)});
},
// addPath: '/locales/{{lng}}/{{ns}}.missing.json',
......
import languages from './data/Languages';
// console.log('GG-CE Supported Languages: ', languages.map((lang) => lang.short));
const optionsBase = (modules = []) => ({
fallbackLng: 'en',
preload: [ 'en' ],
load: 'languageOnly' as const, // we only provide en, de -> no region specific locals like en-US, de-DE
lowerCaseLng: true, // make sure to use lowercase folder names for 'zh-tw'!
// load: 'languageOnly' as const, // we only provide en, de -> no region specific locals like en-US, de-DE
load: 'all' as const, // 'all' ⇒ ['en-US', 'en', 'dev']; 'currentOnly' ⇒ 'en-US'; 'languageOnly' ⇒ 'en'
supportedLngs: languages.map((lang) => lang.short.toLowerCase()), // [ 'en', 'es', 'ar', 'fr', 'zh-TW' ],
nonExplicitSupportedLngs: false,
fallbackLng: 'en',
// have a common namespace used around the full app
ns: [ ...modules ],
......@@ -9,7 +18,7 @@ const optionsBase = (modules = []) => ({
nsSeparator: ':', // namespace separator
keySeparator: '.', // key separator
saveMissing: false,
debug: false,
// debug: true,
// cache: {
// enabled: true
......
......@@ -216,7 +216,7 @@ module.exports = {
}),*/
// keep only required moment.js locales
new MomentLocalesPlugin({
localesToKeep: [ 'ar', 'es', 'fr' ],
localesToKeep: [ 'en', 'ar', 'es', 'fr', 'zh-tw' ],
}),
// Git revision
......
......@@ -43,7 +43,7 @@ const initialI18nStore = window.initialI18nStore;
// document.baseURI is full URI, we take everything but the trailing slash (for "/" it is "", for "/aa/" or "/aa" it is "/aa")
const virtualPath = document.baseURI.replace(/^(https?:\/\/[^\/]+)?(.*)\/$/, '$2');
const detectedLang = initialLanguage ? initialLanguage : detectLocaleFromPath(virtualPath, window.location.pathname, 0);
const detectedLang: string = initialLanguage ? initialLanguage : detectLocaleFromPath(virtualPath, window.location.pathname);
const historyOptions = { basename: detectedLang !== 'en' ? `${virtualPath}/${detectedLang}` : `${virtualPath}` };
const history = createHistory(historyOptions);
const direction = getDir(detectedLang);
......@@ -57,6 +57,8 @@ const SsrI18nProvider = withSSR()(I18nextProvider) as any;
import { MuiThemeProvider } from '@material-ui/core/styles';
import theme from '_layout/theme/theme';
console.log(`Detected UI language: ${detectedLang}`);
// Configure axios for client
reconfigureServiceAxios({
apiUrl: store.getState().applicationConfig.apiUrl || process.env.API_URL || 'http://localhost:8080',
......@@ -65,7 +67,7 @@ reconfigureServiceAxios({
// moment.js uses en locale as default and don't have separate file for it so import('moment/locale/en') causes error
if (detectedLang !== 'en') {
import(`moment/locale/${detectedLang}`).then(() => moment.locale(detectedLang));
import(`moment/locale/${detectedLang.toLowerCase()}`).then(() => moment.locale(detectedLang.toLowerCase()));
} else {
moment.locale(detectedLang);
}
......
import languages from '@gringlobal-ce/i18n/data/Languages';
export default function detectLocaleFromPath(virtualPath: string, path: string, index: number) {
export default function detectLocaleFromPath(virtualPath: string, path: string) {
if (virtualPath && path.startsWith(virtualPath)) {
path = path.substring(virtualPath.length);
}
let found = 'en';
const language = path.match(/\/([a-zA-Z-]*)/g);
if (language instanceof Array) {
const foundLang = language[index].replace('/', '');
languages.some((item, i, arr) => {
if (item.short === foundLang) {
found = foundLang;
return true;
}
});
let found = languages[0]; // default to first GG-CE language
const language = path.match(/^\/([a-z]{2}(-[a-z]+)?)\//i);
if (language instanceof Array && language.length > 1) {
console.log(`detectLocaleFromPath: virtual=${virtualPath} path=${path}`, language);
const foundLang = language[1];
found = languages.filter((ggceLang) => ggceLang.short === foundLang)[0] || languages[0];
} else {
console.log(`detectLocaleFromPath: No language detected from virtual=${virtualPath} path=${path}`, language);
}
return found;
return found.short;
}
......@@ -65,11 +65,19 @@ const prerenderer = (html, errHtml) => (req, res) => {
const context = {};
function setLocale() {
const locale = detectLocaleFromPath(config.frontendPath, pathname, 0);
// console.log('Detected locale for SSR is', locale);
const locale = detectLocaleFromPath(config.frontendPath, pathname);
console.log('Detected locale for SSR is', locale);
req.i18n.changeLanguage(locale);
if (locale !== 'en') {
import(`moment/locale/${locale}`).then(() => moment.locale(locale));
try {
import(`moment/locale/${locale.toLowerCase()}`).then(() => moment.locale(locale)).catch((err) => {
console.log(`Momentjs is not configured for ${locale}`);
moment.locale(locale);
});
} catch (err) {
console.log('Well, this did not work.', err);
moment.locale(locale);
}
} else {
moment.locale(locale);
}
......@@ -89,7 +97,7 @@ const prerenderer = (html, errHtml) => (req, res) => {
initialI18nStore[defaultLanguage] = req.i18n.services.resourceStore.data[defaultLanguage];
}
const basename = initialLanguage !== defaultLanguage ? `${config.frontendPath}/${initialLanguage}` : `${config.frontendPath}`;
const pathWithoutLang = req.url.substr(initialLanguage !== defaultLanguage ? 3 : 0, req.url.length);
const pathWithoutLang = req.url.substr(basename.length);
console.log(`<StaticRouter location="${pathWithoutLang}" basename="${basename}"`);
const direction = getDir(initialLanguage);
const modules = [];
......@@ -168,8 +176,8 @@ const prerenderer = (html, errHtml) => (req, res) => {
checkAuthToken(req, res, store.dispatch).then(() => {
const language = req.i18n.language;
const pathWithoutLang = pathname.substr(language !== 'en' ? 3 : 0, pathname.length);
console.log(`Rendering ${pathWithoutLang} for ${pathname}`);
const pathWithoutLang = pathname.substr(language !== 'en' ? language.length + 1 : 0, pathname.length); // cut out the /aa-BBC prefix (language.length + 1) when URL is not for 'en'
console.log(`Rendering ${pathWithoutLang} for ${pathname} using language=${language}`);
const branch = matchRoutes(routes, pathWithoutLang);
if (branch && branch.length > 0) {
......
......@@ -7,6 +7,7 @@ import { bindActionCreators, compose } from 'redux';
import MenuItem from '@material-ui/core/MenuItem/MenuItem';
import TextField from '@material-ui/core/TextField';
import navigateTo from '@gringlobal-ce/client/action/navigation';
import languages from '@gringlobal-ce/i18n/data/Languages';
const styles = (theme) => ({
fieldWrapper: {
......@@ -17,12 +18,6 @@ const styles = (theme) => ({
},
});
enum UILanguage {
EN = 'en',
FR = 'fr',
AR = 'ar',
ES = 'es',
}
interface IUILangSelect {
navigateTo: (path: string) => void;
......@@ -34,8 +29,9 @@ class UILangSelect extends React.Component<IUILangSelect & WithStyles & WithTran
}
private onSelectChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const selected = Object.values(UILanguage).find((lang) => lang === e.target.value);
const redirectLang = selected === 'en' ? '' : selected // en - default
const selected = languages.find((lang) => lang.short.toLowerCase() === e.target.value.toLowerCase());
const redirectLang = selected.short === 'en' ? '' : selected.short // en - default
console.log(`Redirecting you to ${redirectLang}/`);
window.location.replace(`${redirectLang}/`)
};
......@@ -50,13 +46,13 @@ class UILangSelect extends React.Component<IUILangSelect & WithStyles & WithTran
fullWidth
label={ t('client:model.Cooperator.sysLang') }
onChange={ this.onSelectChange }
value={ i18n.language || 'en' }
value={ i18n.language.toLowerCase() || 'en' }
helperText={ <a href="https://www.transifex.com/crop-trust/gg-ce-web/" target="_blank" rel="noreferrer">{ t('welcome.p.cards.language.helpTranslate') }</a> }
>
{
Object.entries(UILanguage).map((lang, i) => (
<MenuItem key={ `option-${lang}-${i}` } value={ lang[1] }>
{ lang[0] }
languages.map((lang, i) => (
<MenuItem key={ `option-${lang.short}` } value={ lang.short.toLowerCase() }>
{ lang.label }
</MenuItem>))
}
</TextField>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment