Skip to content

Commit 1bfae0b

Browse files
committed
FIO-9618 Move i18n shim from renderer
* FIO-9618 Update t() signature to pacify TS - TS was complaining about passing the rest args (...args) to Evaluator.interpolateString after the i18n class was moved to core (which has TS) - I think this is good anyhow since now we can reference the data param directly (data?.field) instead of doing args[0]?.field in the Evaluator's interpolateString method. * FIO-9618 add a couple premium translation strings for eamil rendering * FIO-9618: Add types to i18n shim
1 parent fc8960e commit 1bfae0b

File tree

3 files changed

+194
-0
lines changed

3 files changed

+194
-0
lines changed

src/utils/i18n.ts

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import enTranslation from './translations/en';
2+
import { fastCloneDeep } from '../utils/fastCloneDeep';
3+
import { isEmpty } from 'lodash';
4+
import { Evaluator } from './Evaluator';
5+
6+
export const coreEnTranslation = enTranslation;
7+
8+
type TranslationDictionary = {
9+
[key: string]: string;
10+
};
11+
12+
export type LanguageResources = {
13+
[language: string]: {
14+
translation: TranslationDictionary;
15+
};
16+
};
17+
18+
export type I18nConfig = {
19+
lng: string;
20+
nsSeparator: string;
21+
keySeparator: string;
22+
pluralSeparator: string;
23+
contextSeparator: string;
24+
resources: LanguageResources;
25+
};
26+
27+
export type LanguagesMap = {
28+
[language: string]: TranslationDictionary;
29+
};
30+
31+
export type I18nOptions = Partial<I18nConfig> & {
32+
language?: string;
33+
} & Omit<{ [language: string]: TranslationDictionary }, 'language'>;
34+
35+
export const i18nConfig: I18nConfig = {
36+
lng: 'en',
37+
nsSeparator: '::',
38+
keySeparator: '.|.',
39+
pluralSeparator: '._.',
40+
contextSeparator: '._.',
41+
resources: {
42+
en: {
43+
translation: fastCloneDeep(enTranslation),
44+
},
45+
},
46+
};
47+
48+
const i18Defaults: LanguagesMap = {};
49+
for (const lang in i18nConfig.resources) {
50+
if (i18nConfig.resources.hasOwnProperty(lang)) {
51+
i18Defaults[lang] = i18nConfig.resources[lang].translation;
52+
}
53+
}
54+
55+
/**
56+
* This file is used to mimic the i18n library interface.
57+
*/
58+
export class I18n {
59+
static languages = i18Defaults;
60+
languages = fastCloneDeep(I18n.languages || {});
61+
defaultKeys = I18n.languages?.en || {};
62+
language = 'en';
63+
currentLanguage = i18Defaults.en;
64+
65+
constructor(languages = {}) {
66+
this.setLanguages(languages, false);
67+
this.changeLanguage(this.language);
68+
}
69+
70+
static setDefaultTranslations(languages: LanguagesMap) {
71+
if (isEmpty(languages)) {
72+
return;
73+
}
74+
for (const lang in languages) {
75+
if (lang !== 'language' && languages.hasOwnProperty(lang)) {
76+
if (!this.languages[lang]) {
77+
this.languages[lang] = {};
78+
}
79+
this.languages[lang] = { ...languages[lang], ...this.languages[lang] };
80+
}
81+
}
82+
}
83+
84+
setLanguages(languages: I18nOptions, noDefaultOverride: boolean) {
85+
if (languages.resources) {
86+
for (const lang in languages.resources) {
87+
if (languages.resources.hasOwnProperty(lang)) {
88+
languages[lang] = languages.resources[lang].translation;
89+
}
90+
}
91+
delete languages.resources;
92+
}
93+
if (languages.lng) {
94+
languages.language = languages.lng;
95+
delete languages.lng;
96+
}
97+
// Do not use these configurations.
98+
delete languages.nsSeparator;
99+
delete languages.keySeparator;
100+
delete languages.pluralSeparator;
101+
delete languages.contextSeparator;
102+
103+
// Now establish the languages default.
104+
if (languages.language) {
105+
this.language = languages.language;
106+
}
107+
for (const lang in languages) {
108+
if (lang !== 'language' && languages.hasOwnProperty(lang)) {
109+
if (!this.languages[lang]) {
110+
this.languages[lang] = {};
111+
}
112+
this.languages[lang] = noDefaultOverride
113+
? { ...languages[lang], ...this.languages[lang] }
114+
: { ...this.languages[lang], ...languages[lang] };
115+
}
116+
}
117+
}
118+
119+
static init(languages = {}) {
120+
return new I18n(languages);
121+
}
122+
123+
dir(lang = '') {
124+
lang = lang || this.language;
125+
const rtls = ['ar', 'he', 'fa', 'ps', 'ur'];
126+
return rtls.includes(lang) ? 'rtl' : 'ltr';
127+
}
128+
129+
static createInstance() {
130+
return new I18n();
131+
}
132+
133+
changeLanguage(language: string, ready?: () => any) {
134+
if (!this.languages[language]) {
135+
language = 'en';
136+
}
137+
this.language = language;
138+
this.currentLanguage = this.languages[language] ? this.languages[language] : {};
139+
if (ready) {
140+
ready();
141+
}
142+
}
143+
144+
addResourceBundle(language: string, type: string, strings: TranslationDictionary) {
145+
this.languages[language] = strings;
146+
}
147+
148+
t(text: string, data: any, ...args: any[]) {
149+
let currentTranslation = this.currentLanguage[text];
150+
// provide compatibility with cases where the entire phrase is used as a key
151+
// get the phrase that is possibly being used as a key
152+
const defaultKey = this.defaultKeys[text];
153+
if (defaultKey && this.currentLanguage[defaultKey]) {
154+
// get translation using the phrase as a key
155+
currentTranslation = this.currentLanguage[defaultKey];
156+
}
157+
158+
if (currentTranslation) {
159+
const customTranslationFieldName = data?.field;
160+
if (customTranslationFieldName && this.currentLanguage[customTranslationFieldName]) {
161+
data.field = this.currentLanguage[customTranslationFieldName];
162+
}
163+
return Evaluator.interpolateString(currentTranslation, data, ...args);
164+
}
165+
return Evaluator.interpolateString(text, data, ...args);
166+
}
167+
}

src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export { unwind } from './unwind';
66
export * as Utils from './formUtil';
77
export * as dom from './dom';
88
export * from './utils';
9+
export * from './i18n';
910
export * from './date';
1011
export * from './mask';
1112
export * from './fastCloneDeep';

src/utils/translations/en.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { EN_ERRORS } from 'processes/validation/i18n/en';
2+
3+
export default {
4+
...EN_ERRORS,
5+
month: 'Month',
6+
day: 'Day',
7+
year: 'Year',
8+
january: 'January',
9+
february: 'February',
10+
march: 'March',
11+
april: 'April',
12+
may: 'May',
13+
june: 'June',
14+
july: 'July',
15+
august: 'August',
16+
september: 'September',
17+
october: 'October',
18+
november: 'November',
19+
december: 'December',
20+
yes: 'Yes',
21+
no: 'No',
22+
surveyQuestion: 'Question',
23+
surveyQuestionValue: 'Value',
24+
complexData: '[Complex Data]', // also in premium en.ts
25+
dots: 'Dots', // also in premium en.ts
26+
};

0 commit comments

Comments
 (0)