Skip to content

Commit

Permalink
i18n: initial separation of locales and languages
Browse files Browse the repository at this point in the history
Bug: #123
  • Loading branch information
jesec committed Dec 14, 2020
1 parent cea33d5 commit 3416308
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 22 deletions.
2 changes: 1 addition & 1 deletion client/src/javascript/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const FloodApp: FC = observer(() => {

return (
<Suspense fallback={<LoadingOverlay />}>
<AsyncIntlProvider locale={SettingStore.floodSettings.language}>
<AsyncIntlProvider language={SettingStore.floodSettings.language}>
<Router history={history}>
<AppWrapper className={ConfigStore.preferDark ? 'dark' : undefined}>
<Switch>
Expand Down
20 changes: 12 additions & 8 deletions client/src/javascript/i18n/languages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import EN from './strings.compiled.json';
import Languages from '../constants/Languages';

import type {Language} from '../constants/Languages';
import type {LocaleConfig} from '../util/detectLocale';

const messagesCache: Partial<Record<Exclude<Language, 'auto'>, Record<string, MessageFormatElement[]>>> = {en: EN};

Expand Down Expand Up @@ -45,28 +46,31 @@ function getMessages(locale: Exclude<Language, 'auto'>) {
}

interface AsyncIntlProviderProps {
locale?: Language;
language?: Language;
children: React.ReactNode;
}

const AsyncIntlProvider: React.FC<AsyncIntlProviderProps> = ({locale, children}: AsyncIntlProviderProps) => {
let validatedLocale: Exclude<Language, 'auto'>;
if (locale == null || locale === 'auto' || !Object.prototype.hasOwnProperty.call(Languages, locale)) {
const AsyncIntlProvider: React.FC<AsyncIntlProviderProps> = ({language, children}: AsyncIntlProviderProps) => {
let validatedLocale: LocaleConfig;
if (language == null || language === 'auto' || !Object.prototype.hasOwnProperty.call(Languages, language)) {
validatedLocale = detectLocale();
} else {
validatedLocale = locale;
validatedLocale = {
locale: language,
language,
};
}

const messages = getMessages(validatedLocale);
const messages = getMessages(validatedLocale.language);
return (
<IntlProvider locale={validatedLocale === 'translate' ? 'en' : validatedLocale} messages={messages}>
<IntlProvider locale={validatedLocale.language === 'translate' ? 'en' : validatedLocale.locale} messages={messages}>
{children}
</IntlProvider>
);
};

AsyncIntlProvider.defaultProps = {
locale: 'en',
language: 'en',
};

export default AsyncIntlProvider;
37 changes: 24 additions & 13 deletions client/src/javascript/util/detectLocale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,54 @@ import Languages from '../constants/Languages';

import type {Language} from '../constants/Languages';

let detectedLocale: Exclude<Language, 'auto'> = 'en';
export interface LocaleConfig {
locale: string;
language: Exclude<Language, 'auto'>;
}

const detectedLocales: LocaleConfig = {
locale: 'en',
language: 'en',
};

let localeDetected = false;

function detectLocale(): Exclude<Language, 'auto'> {
const detectLocale = (): LocaleConfig => {
if (localeDetected) {
return detectedLocale;
return detectedLocales;
}

// Reverse loop to respect language priority of user
getUserLocales()
.reverse()
.forEach((userLocale): void => {
let locale = userLocale;
switch (locale) {
detectedLocales.locale = userLocale;
switch (detectedLocales.locale) {
// Special handlings for languages with variants
case 'zh':
case 'zh-CN':
case 'zh-SG':
case 'zh-MY':
locale = 'zh-Hans';
detectedLocales.locale = 'zh-Hans';
break;
case 'zh-TW':
case 'zh-HK':
case 'zh-MO':
locale = 'zh-Hant';
detectedLocales.locale = 'zh-Hant';
break;
default:
break;
}
if (Object.prototype.hasOwnProperty.call(Languages, locale)) {
detectedLocale = locale as Exclude<Language, 'auto'>;
} else if (Object.prototype.hasOwnProperty.call(Languages, locale.substr(0, 2))) {
if (Object.prototype.hasOwnProperty.call(Languages, detectedLocales.locale)) {
detectedLocales.language = detectedLocales.locale as Exclude<Language, 'auto'>;
} else if (Object.prototype.hasOwnProperty.call(Languages, detectedLocales.locale.substr(0, 2))) {
// In rare cases, user provides a locale (eg. en-US) without fallback (eg. en)
detectedLocale = locale.substr(0, 2) as Exclude<Language, 'auto'>;
detectedLocales.language = detectedLocales.locale.substr(0, 2) as Exclude<Language, 'auto'>;
}
});

localeDetected = true;
return detectedLocale;
}
return detectedLocales;
};

export default detectLocale;

0 comments on commit 3416308

Please sign in to comment.