Skip to content

Commit f9bff88

Browse files
committed
Add language fallback tests and enhance language setting logic
- Introduced new Cypress tests to verify language fallback behavior for 2-letter and 3-letter language codes. - Enhanced the `setLang` method in `L.PM.Map` to improve language normalization and fallback handling. - Added logging functionality in Cypress plugins for better debugging.
1 parent d720305 commit f9bff88

File tree

3 files changed

+105
-33
lines changed

3 files changed

+105
-33
lines changed

cypress/e2e/toolbar.cy.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,41 @@ describe('Testing the Toolbar', () => {
158158
.and('include', 'Dibujar Marcador de Círculo');
159159
});
160160

161+
it('Sets 3-letter language code correctly to fallback when not available', () => {
162+
cy.window().then(({ map, L }) => {
163+
map.pm.setLang('jam'); // 'jam' translations don't exist
164+
expect(L.PM.activeLang).to.equal('en'); // Should fallback to 'en'
165+
});
166+
});
167+
168+
it('Sets 3-letter language code with region correctly to fallback when not available', () => {
169+
cy.window().then(({ map, L }) => {
170+
map.pm.setLang('jam-JM'); // 'jam' translations don't exist
171+
expect(L.PM.activeLang).to.equal('en'); // Should fallback to 'en'
172+
});
173+
});
174+
175+
it('Sets 2-letter language code with region correctly to base when available', () => {
176+
cy.window().then(({ map, L }) => {
177+
map.pm.setLang('fr-CA'); // 'fr' translations exist
178+
expect(L.PM.activeLang).to.equal('fr'); // Should use 'fr'
179+
});
180+
});
181+
182+
it('Sets 2-letter language code ', () => {
183+
cy.window().then(({ map, L }) => {
184+
map.pm.setLang('de'); // 'fr' translations exist
185+
expect(L.PM.activeLang).to.equal('de'); // Should use 'fr'
186+
});
187+
});
188+
189+
it('Handles non-existent language code correctly by falling back', () => {
190+
cy.window().then(({ map, L }) => {
191+
map.pm.setLang('xyz'); // 'xyz' translations don't exist
192+
expect(L.PM.activeLang).to.equal('en'); // Should fallback to 'en'
193+
});
194+
});
195+
161196
it('has functioning actions', () => {
162197
cy.toolbarButton('polygon').click();
163198

cypress/plugins/index.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,18 @@
1111
// This function is called when a project is opened or re-opened (e.g. due to
1212
// the project's config changing)
1313

14-
module.exports = () => {
14+
module.exports = (on, config) => {
1515
// `on` is used to hook into various events Cypress emits
1616
// `config` is the resolved Cypress config
17+
18+
// Define the 'log' task
19+
on('task', {
20+
log(message) {
21+
console.log('CYPRESS TASK LOG: ', message);
22+
return null; // Task must return null or a promise
23+
},
24+
});
25+
26+
// Return the config object or plugins might not work
27+
return config;
1728
};

src/js/L.PM.Map.js

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -44,45 +44,71 @@ const Map = L.Class.extend({
4444
this.Keyboard._initKeyListener(map);
4545
},
4646
// eslint-disable-next-line default-param-last
47-
setLang(lang = 'en', override, fallback = 'en') {
48-
// Normalize the language code to lowercase and trim any whitespace
49-
lang = lang.trim().toLowerCase();
47+
setLang(langInput = 'en', override, fallback = 'en') {
48+
// 1. Normalize input and determine the intended language code
49+
const normalizedInput = langInput?.trim().toLowerCase() || '';
50+
const originalFallbackLang = fallback?.trim().toLowerCase() || 'en';
51+
let intendedLang = originalFallbackLang; // Default intention is the fallback
5052

51-
// First, check if the input is already in the expected format (e.g., 'fr')
52-
if (/^[a-z]{2}$/.test(lang)) {
53-
// No further processing needed for single-letter codes
54-
} else {
55-
// Handle formats like 'fr-FR', 'FR', 'fr-fr', 'fr_FR'
56-
const normalizedLang = lang
57-
.replace(/[-_\s]/g, '-')
58-
.replace(/^(\w{2})$/, '$1-');
59-
const match = normalizedLang.match(/([a-z]{2})-?([a-z]{2})?/);
53+
const match = normalizedInput.match(/^([a-z]{2,3})(?:[-_]([a-z]{2}))?.*$/);
54+
let baseLang = null;
55+
if (match) {
56+
[, baseLang] = match;
57+
} else if (/^[a-z]{2,3}$/.test(normalizedInput)) {
58+
baseLang = normalizedInput;
59+
}
6060

61-
if (match) {
62-
// Construct potential keys to search for in the translations object
63-
const potentialKeys = [
64-
`${match[1]}_${match[2]}`, // e.g., 'fr_BR'
65-
`${match[1]}`, // e.g., 'fr'
66-
];
61+
if (baseLang) {
62+
intendedLang = baseLang; // If input gives a valid base code, that's the intention
63+
} else if (!normalizedInput) {
64+
intendedLang = 'en'; // If input is empty/invalid, intention defaults to 'en'
65+
}
66+
// Now, intendedLang is the primary code derived from input, or the fallback, or 'en'.
6767

68-
// Search through the translations object for a matching key
69-
for (const key of potentialKeys) {
70-
if (translations[key]) {
71-
lang = key; // Set lang to the matching key
72-
break; // Exit the loop once a match is found
73-
}
74-
}
75-
}
68+
const oldLang = L.PM.activeLang || 'en'; // Store the previous language, default to 'en' if undefined
69+
70+
// 2. Calculate merged translations for the event *if* override is provided
71+
let translationsForEvent = null; // Initialize
72+
if (override && typeof override === 'object') {
73+
// Find the best base for merging: intended lang -> fallback -> 'en' -> empty
74+
const baseForMerge =
75+
translations[intendedLang] ||
76+
translations[originalFallbackLang] ||
77+
translations.en ||
78+
{};
79+
// Calculate the merged result, but DO NOT assign back to global translations[intendedLang]
80+
translationsForEvent = merge({}, baseForMerge, override);
7681
}
7782

78-
const oldLang = L.PM.activeLang;
79-
if (override) {
80-
translations[lang] = merge(translations[fallback], override);
83+
// 3. Determine the final active language BASED ON ORIGINAL translations
84+
let finalLang = 'en'; // Default final language to 'en'
85+
// Check the *original* translations, ignoring any temporary override merge
86+
if (translations[intendedLang]) {
87+
finalLang = intendedLang; // Use intended if it now exists (due to override or initially)
88+
} else if (translations[originalFallbackLang]) {
89+
finalLang = originalFallbackLang; // Otherwise, use fallback if it exists
8190
}
91+
// If neither intended nor fallback exists, finalLang remains 'en'
8292

83-
L.PM.activeLang = lang;
84-
this.map.pm.Toolbar.reinit();
85-
this._fireLangChange(oldLang, lang, fallback, translations[lang]);
93+
// 4. Set active language
94+
L.PM.activeLang = finalLang;
95+
// 5. Reinitialize toolbar and fire event if the language actually changed
96+
if (oldLang !== L.PM.activeLang) {
97+
this.map.pm.Toolbar.reinit();
98+
// Use the potentially merged translations *only* for the event payload
99+
// Fallback to the standard active translations if no override was performed
100+
const activeTranslations =
101+
translationsForEvent ||
102+
translations[L.PM.activeLang] ||
103+
translations.en ||
104+
{};
105+
this._fireLangChange(
106+
oldLang,
107+
L.PM.activeLang,
108+
originalFallbackLang,
109+
activeTranslations
110+
);
111+
}
86112
},
87113
addControls(options) {
88114
this.Toolbar.addControls(options);

0 commit comments

Comments
 (0)