mirror of
https://github.com/wassname/talk.git
synced 2026-07-27 11:28:12 +08:00
[CORL-406] Tenant Locale Selection (#2450)
* feat: added preload config * feat: support changing locale * fix: name case * fix: removed unused code * feat: added translations for default reactions * fix: do not translate icon * fix: shorter i18n keys
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import { Kind } from "graphql";
|
||||
|
||||
import Locale from "./locale";
|
||||
|
||||
describe("parseLiteral", () => {
|
||||
it("parses a valid locale from a string", () => {
|
||||
expect(
|
||||
Locale.parseLiteral({
|
||||
kind: Kind.STRING,
|
||||
value: "en-US",
|
||||
})
|
||||
).toBe("en-US");
|
||||
});
|
||||
it("parses an unsupported locale from a string", () => {
|
||||
expect(() =>
|
||||
Locale.parseLiteral({
|
||||
kind: Kind.STRING,
|
||||
value: "xyz",
|
||||
})
|
||||
).toThrow();
|
||||
});
|
||||
|
||||
it("throws when not a string", () => {
|
||||
expect(() =>
|
||||
Locale.parseLiteral({
|
||||
kind: Kind.INT,
|
||||
value: "4",
|
||||
})
|
||||
).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseValue", () => {
|
||||
it("parses a valid locale from a string", () => {
|
||||
expect(Locale.parseValue("en-US")).toBe("en-US");
|
||||
});
|
||||
it("parses an unsupported locale from a string", () => {
|
||||
expect(() => Locale.parseValue("xyz")).toThrow();
|
||||
});
|
||||
it("throws when not a string", () => {
|
||||
expect(() => Locale.parseValue(4)).toThrow();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
import { LOCALES } from "coral-common/helpers/i18n";
|
||||
import { GraphQLScalarType } from "graphql";
|
||||
import { Kind } from "graphql/language";
|
||||
|
||||
function assertSupportLocale(locale: string) {
|
||||
if (!LOCALES.includes(locale as any)) {
|
||||
throw new Error(`Supported locales are ${JSON.stringify(LOCALES)}`);
|
||||
}
|
||||
}
|
||||
|
||||
export default new GraphQLScalarType({
|
||||
name: "Locale",
|
||||
description: "Locale represents a language code in the BCP 47 format.",
|
||||
serialize(value) {
|
||||
return value;
|
||||
},
|
||||
parseValue(value) {
|
||||
if (typeof value !== "string") {
|
||||
throw new Error("Locale must be a string in BCP 47 format.");
|
||||
}
|
||||
assertSupportLocale(value);
|
||||
return value;
|
||||
},
|
||||
parseLiteral(ast) {
|
||||
if (ast.kind !== Kind.STRING) {
|
||||
throw new Error("Locale must be a string in BCP 47 format.");
|
||||
}
|
||||
const value = ast.value.toString();
|
||||
assertSupportLocale(value);
|
||||
return value;
|
||||
},
|
||||
});
|
||||
@@ -1,28 +0,0 @@
|
||||
import { LanguageCode } from "coral-common/helpers/i18n/locales";
|
||||
|
||||
import { GQLLOCALES } from "../schema/__generated__/types";
|
||||
import { LOCALES } from "./LOCALES";
|
||||
|
||||
it("does not contain duplicate entries", () => {
|
||||
const seen: Partial<Record<LanguageCode, true>> = {};
|
||||
for (const key in LOCALES) {
|
||||
if (!LOCALES.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const value = LOCALES[key as GQLLOCALES];
|
||||
expect(value in seen).toBeFalsy();
|
||||
seen[value] = true;
|
||||
}
|
||||
});
|
||||
|
||||
it("contains the correct mappings to the BCP 47 format", () => {
|
||||
for (const key in LOCALES) {
|
||||
if (!LOCALES.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const value = LOCALES[key as GQLLOCALES];
|
||||
expect(value).toEqual(key.replace(/_/, "-"));
|
||||
}
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
import { LanguageCode } from "coral-common/helpers/i18n/locales";
|
||||
|
||||
import { GQLLOCALES } from "../schema/__generated__/types";
|
||||
|
||||
export const LOCALES: Record<GQLLOCALES, LanguageCode> = {
|
||||
en_US: "en-US",
|
||||
pt_BR: "pt-BR",
|
||||
es: "es",
|
||||
de: "de",
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import Cursor from "coral-server/graph/common/scalars/cursor";
|
||||
import Locale from "coral-server/graph/common/scalars/locale";
|
||||
import Time from "coral-server/graph/common/scalars/time";
|
||||
import { GQLResolver } from "coral-server/graph/tenant/schema/__generated__/types";
|
||||
|
||||
@@ -81,6 +82,7 @@ const Resolvers: GQLResolver = {
|
||||
UsernameHistory,
|
||||
Tag,
|
||||
Time,
|
||||
Locale,
|
||||
User,
|
||||
UserStatus,
|
||||
UsernameStatus,
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
import {
|
||||
addResolveFunctionsToSchema,
|
||||
attachDirectiveResolvers,
|
||||
IEnumResolver,
|
||||
IResolvers,
|
||||
} from "graphql-tools";
|
||||
import { attachDirectiveResolvers, IResolvers } from "graphql-tools";
|
||||
|
||||
import { loadSchema } from "coral-common/graphql";
|
||||
import auth from "coral-server/graph/common/directives/auth";
|
||||
import resolvers from "coral-server/graph/tenant/resolvers";
|
||||
import { LOCALES } from "coral-server/graph/tenant/resolvers/LOCALES";
|
||||
|
||||
export default function getTenantSchema() {
|
||||
const schema = loadSchema("tenant", resolvers as IResolvers);
|
||||
@@ -16,15 +10,5 @@ export default function getTenantSchema() {
|
||||
// Attach the directive resolvers.
|
||||
attachDirectiveResolvers(schema, { auth });
|
||||
|
||||
// Attach the GraphQL enum fields.
|
||||
addResolveFunctionsToSchema({
|
||||
schema,
|
||||
resolvers: {
|
||||
// For some reason, the resolver doesn't quite work without coercing the
|
||||
// type.
|
||||
LOCALES: LOCALES as IEnumResolver,
|
||||
},
|
||||
});
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,11 @@ Cursor represents a paginating cursor.
|
||||
"""
|
||||
scalar Cursor
|
||||
|
||||
"""
|
||||
Locale represents a language code in the BCP 47 format.
|
||||
"""
|
||||
scalar Locale
|
||||
|
||||
################################################################################
|
||||
## Actions
|
||||
################################################################################
|
||||
@@ -990,17 +995,6 @@ type StoryMessageBox {
|
||||
## Settings
|
||||
################################################################################
|
||||
|
||||
"""
|
||||
LOCALES list all the supported locales in a modified BCP 47 format, where the
|
||||
hyphen is replaced by an underscore.
|
||||
"""
|
||||
enum LOCALES {
|
||||
en_US
|
||||
pt_BR
|
||||
es
|
||||
de
|
||||
}
|
||||
|
||||
"""
|
||||
CloseCommenting contains settings related to the automatic closing of commenting
|
||||
on Stories.
|
||||
@@ -1124,7 +1118,7 @@ type Settings {
|
||||
"""
|
||||
locale is the specified locale for this Tenant.
|
||||
"""
|
||||
locale: LOCALES!
|
||||
locale: Locale!
|
||||
|
||||
"""
|
||||
live provides configuration options related to live updates for stories on
|
||||
@@ -3371,6 +3365,11 @@ input SettingsInput {
|
||||
accountFeatures specifies the configuration for accounts.
|
||||
"""
|
||||
accountFeatures: CommenterAccountFeaturesInput
|
||||
|
||||
"""
|
||||
locale specifies the locale for this Tenant.
|
||||
"""
|
||||
locale: Locale
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user