diff --git a/app/client/lib/localization.ts b/app/client/lib/localization.ts
index 39094809..39d69541 100644
--- a/app/client/lib/localization.ts
+++ b/app/client/lib/localization.ts
@@ -40,7 +40,13 @@ export async function setupLocale() {
const resourceUrl = loadPath.replace('{{lng}}', lang.replace("-", "_")).replace('{{ns}}', n);
const response = await fetch(resourceUrl);
if (!response.ok) {
- throw new Error(`Failed to load ${resourceUrl}`);
+ // Throw only if we don't have any fallbacks.
+ if (lang === i18next.options.fallbackLng && n === i18next.options.defaultNS) {
+ throw new Error(`Failed to load ${resourceUrl}`);
+ } else {
+ console.warn(`Failed to load ${resourceUrl}`);
+ return;
+ }
}
i18next.addResourceBundle(lang, n, await response.json());
}
diff --git a/app/common/Locales.ts b/app/common/Locales.ts
index b9a5d52a..045c51f6 100644
--- a/app/common/Locales.ts
+++ b/app/common/Locales.ts
@@ -75,7 +75,12 @@ export function getCountryCode(locale: string) {
if (locale === 'en') { return 'US'; }
let countryCode = locale.split(/[-_]/)[1];
if (countryCode) { return countryCode.toUpperCase(); }
- countryCode = locale.toUpperCase();
+
+ // Some defaults that we support and can't be read from language code.
+ countryCode = {
+ 'uk': 'UA', // Ukraine
+ }[locale] ?? locale.toUpperCase();
+
// Test if we can use language as a country code.
if (localeCodes.map(code => code.split(/[-_]/)[1]).includes(countryCode)) {
return countryCode;
diff --git a/static/icons/locales/PL.svg b/static/icons/locales/PL.svg
new file mode 100644
index 00000000..57f279d1
--- /dev/null
+++ b/static/icons/locales/PL.svg
@@ -0,0 +1,15 @@
+
+
diff --git a/static/icons/locales/RU.svg b/static/icons/locales/RU.svg
new file mode 100644
index 00000000..4404aec4
--- /dev/null
+++ b/static/icons/locales/RU.svg
@@ -0,0 +1,16 @@
+
+
diff --git a/static/icons/locales/UA.svg b/static/icons/locales/UA.svg
new file mode 100644
index 00000000..8e5737ce
--- /dev/null
+++ b/static/icons/locales/UA.svg
@@ -0,0 +1,14 @@
+
diff --git a/test/nbrowser/Localization.ts b/test/nbrowser/Localization.ts
index 6b66be15..4ae6fd45 100644
--- a/test/nbrowser/Localization.ts
+++ b/test/nbrowser/Localization.ts
@@ -51,8 +51,8 @@ describe("Localization", function() {
assert.deepEqual(gristConfig.namespaces.sort(), [...namespaces].sort());
});
- // Now make a Polish language file, and test that it is used.
- describe("with Polish language file", function() {
+ // Now make a uz-UZ language file, and test that it is used.
+ describe("with uz-UZ language file", function() {
let oldEnv: testUtils.EnvironmentSnapshot;
let tempLocale: string;
let existingLocales: string[];
@@ -65,7 +65,7 @@ describe("Localization", function() {
oldEnv = new testUtils.EnvironmentSnapshot();
// Add another language to the list of supported languages.
tempLocale = makeCopy();
- createLanguage(tempLocale, "pl");
+ createLanguage(tempLocale, "uz");
process.env.GRIST_LOCALES_DIR = tempLocale;
await server.restart();
});
@@ -79,7 +79,7 @@ describe("Localization", function() {
const homeUrl = `${server.getHost()}/o/docs`;
// Read response from server, and check that it contains the correct language.
const enResponse = await (await fetch(homeUrl)).text();
- const plResponse = await (await fetch(homeUrl, {headers: {"Accept-Language": "pl-PL,pl;q=1"}})).text();
+ const uzResponse = await (await fetch(homeUrl, {headers: {"Accept-Language": "uz-UZ,uz;q=1"}})).text();
const ptResponse = await (await fetch(homeUrl, {headers: {"Accept-Language": "pt-PR,pt;q=1"}})).text();
function present(response: string, ...langs: string[]) {
@@ -96,19 +96,19 @@ describe("Localization", function() {
// English locale is preloaded always.
present(enResponse, "en");
- present(plResponse, "en");
+ present(uzResponse, "en");
present(ptResponse, "en");
// Other locales are not preloaded for English.
- notPresent(enResponse, "pl", "pl-PL", "en-US");
+ notPresent(enResponse, "uz", "un-UZ", "en-US");
- // For Polish we have additional pl locale.
- present(plResponse, "pl");
- // But only pl code is preloaded.
- notPresent(plResponse, "pl-PL");
+ // For uz-UZ we have additional uz locale.
+ present(uzResponse, "uz");
+ // But only uz code is preloaded.
+ notPresent(uzResponse, "uz-UZ");
// For Portuguese we have only en.
- notPresent(ptResponse, "pt", "pt-PR", "pl", "en-US");
+ notPresent(ptResponse, "pt", "pt-PR", "uz", "en-US");
});
it("loads correct languages from file system", async function() {
@@ -116,7 +116,7 @@ describe("Localization", function() {
await driver.navigate().refresh();
assert.equal(await driver.findWait('.test-welcome-title', 3000).getText(), 'TestMessage');
const gristConfig: any = await driver.executeScript("return window.gristConfig");
- assert.sameDeepMembers(gristConfig.supportedLngs, [...existingLocales, 'pl']);
+ assert.sameDeepMembers(gristConfig.supportedLngs, [...existingLocales, 'uz']);
});
});