Skip to content

Commit

Permalink
update canonicalizeLocale to handle 中文(chinese) (#239)
Browse files Browse the repository at this point in the history
J=SLAP-1526
TEST=auto,manual

unit tests
ran build with zh-hans-ch in locale config, saw that the generated source code used the correct locale in the page
tried building a page with a locale with >3 sections, got a jambo warning but build continued without changing the locale
  • Loading branch information
oshi97 committed Aug 18, 2021
1 parent 2d76f4d commit 44b7f79
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 25 deletions.
84 changes: 73 additions & 11 deletions src/utils/i18nutils.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,87 @@
const UserError = require('../errors/usererror');

/**
* Normalizes a locale code
*
* @param {string} localeCode
* @returns {string}
*/
canonicalizeLocale = function(localeCode) {
exports.canonicalizeLocale = function(localeCode) {
if (!localeCode) {
return;
}
const localeCodeSections = localeCode.replace('-', '_')
.split('_');

const languageIndex = 0;
const regionIndex = 1;
const { language, modifier, region } = parseLocale(localeCode);
return formatLocale(language, modifier, region);
}

localeCodeSections[languageIndex] = localeCodeSections[languageIndex].toLowerCase();
/**
* Parses a locale code into its constituent parts.
* Performs case formatting on the result.
*
* @param {string} localeCode
* @returns { language: string, modifier?: string, region?: string }
*/
function parseLocale(localeCode) {
const localeCodeSections = localeCode.replace(/-/g, '_').split('_');
const language = localeCodeSections[0].toLowerCase();
const parseModifierAndRegion = () => {
const numSections = localeCodeSections.length;
if (numSections === 1) {
return {};
} else if (numSections === 2 && language === 'zh') {
const ambiguous = localeCodeSections[1].toLowerCase();
if (['hans', 'hant'].includes(ambiguous)) {
return { modifier: ambiguous };
} else {
return { region: ambiguous };
}
} else if (numSections === 2) {
return { region: localeCodeSections[1] };
} else if (numSections === 3) {
return {
modifier: localeCodeSections[1],
region: localeCodeSections[2]
};
} else if (numSections > 3) {
throw new UserError(
`Encountered strangely formatted locale "${localeCode}", ` +
`with ${numSections} sections.`);
}
}
const capitalizeFirstLetterOnly = raw => {
return raw.charAt(0).toUpperCase() + raw.slice(1).toLowerCase();
}
const parsedLocale = {
language,
...parseModifierAndRegion()
};

if (localeCodeSections.length > regionIndex) {
localeCodeSections[regionIndex] = localeCodeSections[regionIndex].toUpperCase();
if (parsedLocale.modifier) {
parsedLocale.modifier = capitalizeFirstLetterOnly(parsedLocale.modifier);
}
if (parsedLocale.region) {
parsedLocale.region = parsedLocale.region.toUpperCase();
}

return localeCodeSections.join('_');
return parsedLocale;
}
exports.canonicalizeLocale = canonicalizeLocale;
exports.parseLocale = parseLocale;

/**
* Formats a locale code given its constituent parts.
*
* @param {string} language zh in zh-Hans_CH
* @param {string?} modifier Hans in zh-Hans_CH
* @param {string?} region CH in zh-Hans_CH
* @returns
*/
function formatLocale(language, modifier, region) {
let result = language.toLowerCase();
if (modifier) {
result += '-' + modifier;
}
if (region) {
result += '_' + region;
}
return result;
}
24 changes: 12 additions & 12 deletions tests/acceptance/suites/themeupgrader.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const ThemeManager = require('../../../src/utils/thememanager');
const path = require('path');

ThemeManager.getRepoForTheme = () => {
return path.resolve(__dirname, '../test-themes/basic-flow');
return path.resolve(__dirname, '../test-themes/basic-flow');
};

//Silence error logs
Expand All @@ -14,15 +14,15 @@ console.error = jest.fn();
afterAll(() => console.error = error);

it('tests upgrade fail', () => runInPlayground(async t => {
await git.cwd(process.cwd());
await t.jambo('init');
await t.jambo(
'import --themeUrl ../test-themes/basic-flow');
await git.add('.');
await git.commit('theme');
await expect(t.jambo('upgrade --branch fail')).rejects.toThrow(
/Remote branch fail not found in upstream origin/);
const diff = await git.diff();
expect(diff).toBe('');
}));
await git.cwd(process.cwd());
await t.jambo('init');
await t.jambo(
'import --themeUrl ../test-themes/basic-flow');
await git.add('.');
await git.commit('theme');
await expect(t.jambo('upgrade --branch fail')).rejects.toThrow(
/Remote branch fail not found in upstream origin/);
const diff = await git.diff();
expect(diff).toBe('');
}));

62 changes: 60 additions & 2 deletions tests/utils/i18nutils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { canonicalizeLocale } = require('../../src/utils/i18nutils');
const { canonicalizeLocale, parseLocale } = require('../../src/utils/i18nutils');

describe('canonicalizeLocale correctly normalizes locales', () => {
it('converts language to lower case and region to upper case', () => {
Expand All @@ -12,4 +12,62 @@ describe('canonicalizeLocale correctly normalizes locales', () => {
const canonicalizedLocale = canonicalizeLocale(locale);
expect(canonicalizedLocale).toEqual('fr_CH');
});
});

describe('works for chinese', () => {
function runTest(testName, inputLocale, expectedLocale) {
it(testName, () => {
expect(canonicalizeLocale(inputLocale)).toEqual(expectedLocale);
});
}
const testCases = [
['using dashes', 'zh-Hans-CH'],
['using underscores', 'zh_Hans_CH'],
['underscore then dash', 'zh_Hans-CH'],
['dash then underscore', 'zh-Hans_CH'],
['updates casing', 'ZH-hans_Ch'],
['does not have region code', 'zh-hans', 'zh-Hans'],
['has region but no modifier', 'zh-cH', 'zh_CH']
];
const expected = 'zh-Hans_CH';
for (const [testName, inputLocale, specificExpected] of testCases) {
runTest(testName, inputLocale, specificExpected || expected);
}
});
});

describe('parseLocale', () => {
it('performs case formatting', () => {
expect(parseLocale('Zh-hans-Ch')).toEqual({
language: 'zh',
modifier: 'Hans',
region: 'CH'
})
});

it('chinese with modifier only', () => {
expect(parseLocale('ZH_HANS')).toEqual({
language: 'zh',
modifier: 'Hans'
})
});

it('chinese with region only', () => {
expect(parseLocale('ZH-cH')).toEqual({
language: 'zh',
region: 'CH'
})
});

it('2 section non-chinese locale', () => {
expect(parseLocale('FR-freE')).toEqual({
language: 'fr',
region: 'FREE'
});
});

it('simple language', () => {
expect(parseLocale('FR')).toEqual({
language: 'fr'
});
});
});

0 comments on commit 44b7f79

Please sign in to comment.