Skip to content
This repository has been archived by the owner on Dec 10, 2021. It is now read-only.

Commit

Permalink
feat: properly translate the table chart (#724)
Browse files Browse the repository at this point in the history
  • Loading branch information
ktmud authored Aug 5, 2020
1 parent 9455f89 commit ffa6445
Show file tree
Hide file tree
Showing 19 changed files with 512 additions and 97 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,9 @@
"promise/param-names": "off",
"jest/require-to-throw-message": "off",
"jest/no-test-return-statement": "off",
"jest/no-expect-resolves": "off"
"jest/no-expect-resolves": "off",
"@typescript-eslint/no-require-imports": "off",
"global-require": "off"
}
},
{
Expand Down
1 change: 1 addition & 0 deletions packages/superset-ui-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ export { default as isDefined } from './utils/isDefined';
export { default as isRequired } from './utils/isRequired';
export { default as makeSingleton } from './utils/makeSingleton';
export { default as promiseTimeout } from './utils/promiseTimeout';
export { default as logging } from './utils/logging';

export * from './types';
31 changes: 31 additions & 0 deletions packages/superset-ui-core/src/utils/logging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
const logger = window.console || {
debug() {},
log() {},
info() {},
warn() {},
error() {},
trace() {},
};

/**
* Superset frontend logger, currently just an alias to console.
*/
export default logger;
60 changes: 60 additions & 0 deletions packages/superset-ui-core/test/utils/logging.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
describe('logging', () => {
beforeEach(() => {
jest.resetModules();
});
it('should pipe to `console` methods', () => {
const { logging } = require('../../src');

expect(() => {
logging.debug();
logging.log();
logging.info();
}).not.toThrow();
expect(() => {
logging.warn('warn');
}).toThrow('warn');
expect(() => {
logging.error('error');
}).toThrow('error');
expect(() => {
logging.trace();
}).toThrow('Trace:');
});
it('should use noop functions when console unavailable', () => {
const { console } = window;
Object.assign(window, { console: undefined });
const { logging } = require('../../src');

afterAll(() => {
Object.assign(window, { console });
});

expect(() => {
logging.debug();
logging.log();
logging.info();
logging.warn('warn');
logging.error('error');
logging.trace();
}).not.toThrow();
});
});
3 changes: 3 additions & 0 deletions packages/superset-ui-translation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
"dependencies": {
"jed": "^1.1.1"
},
"peerDependencies": {
"@superset-ui/core": "^0.14.18"
},
"publishConfig": {
"access": "public"
}
Expand Down
86 changes: 68 additions & 18 deletions packages/superset-ui-translation/src/Translator.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import UntypedJed from 'jed';
import { TranslatorConfig } from './types';
import { logging } from '@superset-ui/core';
import { Jed, TranslatorConfig, Locale, Translations, LocaleData, LanguagePack } from './types';

interface Jed {
translate(input: string): Jed;
ifPlural(value: number, plural: string): Jed;
fetch(...args: unknown[]): string;
}

const DEFAULT_LANGUAGE_PACK = {
const DEFAULT_LANGUAGE_PACK: LanguagePack = {
domain: 'superset',
locale_data: {
superset: {
'': {
domain: 'superset',
lang: 'en',
plural_forms: 'nplurals=1; plural=0',
plural_forms: 'nplurals=2; plural=(n != 1)',
},
},
},
Expand All @@ -23,25 +36,62 @@ const DEFAULT_LANGUAGE_PACK = {
export default class Translator {
i18n: Jed;

locale: Locale;

constructor(config: TranslatorConfig = {}) {
const { languagePack = DEFAULT_LANGUAGE_PACK } = config;
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
this.i18n = new UntypedJed(languagePack) as Jed;
this.locale = this.i18n.options.locale_data.superset[''].lang as Locale;
}

/**
* Add additional translations on the fly, used by plugins.
*/
addTranslation(key: string, texts: ReadonlyArray<string>) {
const translations = this.i18n.options.locale_data.superset;
if (key in translations) {
logging.warn(`Duplicate translation key "${key}", will override.`);
}
translations[key] = texts;
}

/**
* Add a series of translations.
*/
addTranslations(translations: Translations) {
if (translations && !Array.isArray(translations)) {
Object.entries(translations).forEach(([key, vals]) => this.addTranslation(key, vals));
} else {
logging.warn('Invalid translations');
}
}

addLocaleData(data: LocaleData) {
// always fallback to English
const translations = data?.[this.locale] || data?.en;
if (translations) {
this.addTranslations(translations);
} else {
logging.warn('Invalid locale data');
}
}

translate(input: string, ...args: unknown[]): string {
return this.i18n.translate(input).fetch(...args);
}

translateWithNumber(
singular: string,
plural: string,
num: number = 0,
...args: unknown[]
): string {
translateWithNumber(key: string, ...args: unknown[]): string {
const [plural, num, ...rest] = args;
if (typeof plural === 'number') {
return this.i18n
.translate(key)
.ifPlural(plural, key)
.fetch(plural, num, ...args);
}
return this.i18n
.translate(singular)
.ifPlural(num, plural)
.fetch(...args);
.translate(key)
.ifPlural(num as number, plural as string)
.fetch(...rest);
}
}
20 changes: 16 additions & 4 deletions packages/superset-ui-translation/src/TranslatorSingleton.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint no-console: 0 */

import Translator from './Translator';
import { TranslatorConfig } from './types';
import { TranslatorConfig, Translations, LocaleData } from './types';

let singleton: Translator | undefined;
let isConfigured = false;
Expand All @@ -25,12 +25,24 @@ function getInstance() {
return singleton;
}

function addTranslation(key: string, translations: string[]) {
return getInstance().addTranslation(key, translations);
}

function addTranslations(translations: Translations) {
return getInstance().addTranslations(translations);
}

function addLocaleData(data: LocaleData) {
return getInstance().addLocaleData(data);
}

function t(input: string, ...args: unknown[]) {
return getInstance().translate(input, ...args);
}

function tn(singular: string, plural: string, num?: number, ...args: unknown[]) {
return getInstance().translateWithNumber(singular, plural, num, ...args);
function tn(key: string, ...args: unknown[]) {
return getInstance().translateWithNumber(key, ...args);
}

export { configure, t, tn };
export { configure, addTranslation, addTranslations, addLocaleData, t, tn };
2 changes: 1 addition & 1 deletion packages/superset-ui-translation/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { configure, t, tn } from './TranslatorSingleton';
export * from './TranslatorSingleton';
export * from './types';
20 changes: 0 additions & 20 deletions packages/superset-ui-translation/src/types.ts

This file was deleted.

59 changes: 59 additions & 0 deletions packages/superset-ui-translation/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Jed as BaseJed, JedOptions, DomainData, Translations } from './jed';

export { Translations } from './jed';

/**
* Superset supported languages.
*/
export type Locale = 'de' | 'en' | 'es' | 'fr' | 'it' | 'ja' | 'ko' | 'pt' | 'pt_BR' | 'ru' | 'zh'; // supported locales in Superset

/**
* Language pack provided to `jed`.
*/
export type LanguagePack = JedOptions & {
// eslint-disable-next-line camelcase
locale_data: {
superset: DomainData & {
'': {
domain: 'superset';
lang: Locale;
// eslint-disable-next-line camelcase
plural_forms: string;
};
};
};
};

export interface Jed extends BaseJed {
options: LanguagePack;
}

/**
* Config options for Translator class.
*/
export interface TranslatorConfig {
languagePack?: LanguagePack;
}

/**
* Key-value mapping of translation key and the translations.
*/
export type LocaleData = Partial<Record<Locale, Translations>>;
35 changes: 35 additions & 0 deletions packages/superset-ui-translation/src/types/jed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Translations for a language in the format of { key: [singular, plural, ...]}.
*/
export type Translations = {
[key: string]: ReadonlyArray<string>;
};

export interface DomainConfig {
domain: string;
lang: string;
// eslint-disable-next-line camelcase
plural_forms: string;
}

export type DomainData = { '': DomainConfig } & {
[key: string]: ReadonlyArray<string> | DomainConfig;
};

export interface JedOptions {
domain: string;
// eslint-disable-next-line camelcase
locale_data: {
[domain: string]: DomainData;
};
}

export interface Jed {
translate(input: string): Jed;

ifPlural(value: number, plural: string): Jed;

fetch(...args: unknown[]): string;

options: JedOptions;
}
Loading

1 comment on commit ffa6445

@vercel
Copy link

@vercel vercel bot commented on ffa6445 Aug 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.