diff --git a/.gitignore b/.gitignore index 06c7845e5..3b899d8f6 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ node_modules /playwright-report/ /blob-report/ /playwright/.cache/ -/theme/off/messages/ +# These are generated at build time by the build_languages script +/theme/off/common/messages/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 7b016a89f..158423f35 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,6 @@ { - "java.compile.nullAnalysis.mode": "automatic" + "java.compile.nullAnalysis.mode": "automatic", + "cSpell.words": [ + "keycloak" + ] } \ No newline at end of file diff --git a/build-scripts/build_languages.mjs b/build-scripts/build_languages.mjs index baa3c0d8e..ad66b8d65 100644 --- a/build-scripts/build_languages.mjs +++ b/build-scripts/build_languages.mjs @@ -1,19 +1,11 @@ -import { writeFileSync, appendFileSync, readFileSync, existsSync, mkdirSync, copyFileSync } from 'fs'; +import { writeFileSync, readFileSync, existsSync, mkdirSync, copyFileSync } from 'fs'; +import { getLanguages } from './utils.mjs'; -const runtimeDir = 'runtime-scripts'; const themeDir = 'theme/off/common'; -const languages = JSON.parse(readFileSync('build-scripts/languages.json')); const countries = JSON.parse(readFileSync('build-scripts/countries.json')); -const languageList = {}; -for (const [ key, language ] of Object.entries(languages)) { - if (key === 'en:unknown-language') continue; - - const code = language.language_code_2.en; - const name = (language.name?.[code] ?? language.name.en ?? key).replaceAll("'","''"); - languageList[code] = name; -} +const {languages, languageList} = getLanguages(); const languageMessages = '\n# The following are obtained from the OFF languages taxonomy\n' + Object.entries(languageList).map(([key,value]) => `locale_${key}=${value}`).sort().join('\n'); @@ -38,37 +30,6 @@ for (const [ key, language ] of Object.entries(languages)) { '\n# The following are obtained from the OFF countries taxonomy\n' + countryMessages.sort().join('\n') + languageMessages); } -const countryOptions = {}; -const countryList = {}; -// Try and sort the country list to avoid excess diffs -for (const [ countryId, country ] of Object.entries(countries).sort((a,b) => a[0].localeCompare(b[0]))) { - if (!country.country_code_2?.en) { - console.warn(countryId); - continue; - } - const countryCode = country.country_code_2.en; - // Currently get english name for sorting until Keycloak fixes sorting by localized name - const countryName = country.name.en; - countryOptions[countryCode] = '${country_' + countryCode + '}'; - countryList[countryCode] = countryName; -} - -// Currently sort countries by english name until keycloak supports sorting by localized name -const sortedCountryCodes = Object.entries(countryList).sort((a,b) => a[1].localeCompare(b[1])).map((entry) => entry[0]); -const sortedLanguageCodes = Object.entries(languageList).sort((a,b) => a[1].localeCompare(b[1])).map((entry) => entry[0]); // Add dummy language to show property names -sortedLanguageCodes.push('xx'); copyFileSync('build-scripts/messages_xx.properties', `${themeDir}/messages/messages_xx.properties`); - -const realmSettings = { - supportedLocales: sortedLanguageCodes -} -writeFileSync(`runtime-scripts/realm_settings.json`,JSON.stringify(realmSettings, undefined, 2)); -writeFileSync(`${themeDir}/theme.properties`,`locales=${sortedLanguageCodes.join(',')}\n`); - -const userProfile = JSON.parse(readFileSync(`${runtimeDir}/users_profile.json`)); -const countryAttribute = userProfile.attributes.find((a) => a.name === 'country'); -countryAttribute.validations.options.options = sortedCountryCodes; -countryAttribute.annotations.inputOptionLabels = countryOptions; -writeFileSync(`${runtimeDir}/users_profile.json`, JSON.stringify(userProfile, undefined, 2)); diff --git a/build-scripts/refresh_messages.mjs b/build-scripts/refresh_messages.mjs index 1501d2bde..f88778a3b 100644 --- a/build-scripts/refresh_messages.mjs +++ b/build-scripts/refresh_messages.mjs @@ -5,6 +5,7 @@ */ import { writeFileSync, readFileSync, existsSync, readdirSync } from 'fs'; +import { getLanguages } from './utils.mjs'; const baseThemeDir = 'theme'; const offMessagesDir = `src/messages`; @@ -74,4 +75,44 @@ writeFileSync('build-scripts/messages_xx.properties', xxMessages.join('\n')); fetch('https://static.openfoodfacts.org/data/taxonomies/languages.json').then(async (response) => { writeFileSync('build-scripts/languages.json', await response.text()); writeFileSync('build-scripts/countries.json', await (await fetch('https://static.openfoodfacts.org/data/taxonomies/countries.json')).text()); + + const runtimeDir = 'runtime-scripts'; + const themeDir = 'theme/off/common'; + + const {languageList} = getLanguages(); + const countries = JSON.parse(readFileSync('build-scripts/countries.json')); + + const countryOptions = {}; + const countryList = {}; + // Try and sort the country list to avoid excess diffs + for (const [ countryId, country ] of Object.entries(countries).sort((a,b) => a[0].localeCompare(b[0]))) { + if (!country.country_code_2?.en) { + console.warn(`No 2 letter code for: ${countryId}`); + continue; + } + const countryCode = country.country_code_2.en; + // Currently get english name for sorting until Keycloak fixes sorting by localized name + const countryName = country.name.en; + countryOptions[countryCode] = '${country_' + countryCode + '}'; + countryList[countryCode] = countryName; + } + + // Currently sort countries by english name until keycloak supports sorting by localized name + const sortedCountryCodes = Object.entries(countryList).sort((a,b) => a[1].localeCompare(b[1])).map((entry) => entry[0]); + const sortedLanguageCodes = Object.entries(languageList).sort((a,b) => a[1].localeCompare(b[1])).map((entry) => entry[0]); + + // Add dummy language to show property names + sortedLanguageCodes.push('xx'); + + const realmSettings = { + supportedLocales: sortedLanguageCodes + } + writeFileSync(`runtime-scripts/realm_settings.json`,JSON.stringify(realmSettings, undefined, 2)); + writeFileSync(`${themeDir}/theme.properties`,`locales=${sortedLanguageCodes.join(',')}\n`); + + const userProfile = JSON.parse(readFileSync(`${runtimeDir}/users_profile.json`)); + const countryAttribute = userProfile.attributes.find((a) => a.name === 'country'); + countryAttribute.validations.options.options = sortedCountryCodes; + countryAttribute.annotations.inputOptionLabels = countryOptions; + writeFileSync(`${runtimeDir}/users_profile.json`, JSON.stringify(userProfile, undefined, 2)); }); \ No newline at end of file diff --git a/build-scripts/utils.mjs b/build-scripts/utils.mjs new file mode 100644 index 000000000..4192854f2 --- /dev/null +++ b/build-scripts/utils.mjs @@ -0,0 +1,16 @@ +import { readFileSync } from 'fs'; + +export function getLanguages() { + const languages = JSON.parse(readFileSync('build-scripts/languages.json')); + + const languageList = {}; + for (const [ key, language ] of Object.entries(languages)) { + if (key === 'en:unknown-language') continue; + + const code = language.language_code_2.en; + const name = (language.name?.[code] ?? language.name.en ?? key).replaceAll("'","''"); + languageList[code] = name; + } + + return {languages, languageList}; +}