Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[i18n] .i18nrc file as the source of truth and enhance tooling #39774

Merged
merged 26 commits into from
Jul 21, 2019
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ead0ee9
scan node_modules/@kbn directory for i18n
Bamieh Apr 16, 2019
b2b6cbc
remove es-lint-disable-next line
Bamieh Apr 16, 2019
a29c6cf
update paths
Bamieh Apr 25, 2019
2464a03
look inside .i18nrc.json instead of traversing files
Bamieh Jun 26, 2019
a18fc31
Merge branch 'master' of github.com:elastic/kibana into i18n/packages…
Bamieh Jun 26, 2019
7f37160
split .i18nrc file and enhance i18n tooling
Bamieh Jun 27, 2019
904d8a8
checkout master kibana config
Bamieh Jun 27, 2019
8963fd7
include x-pack/.i18nrc.json file
Bamieh Jun 27, 2019
658f565
remove unused import
Bamieh Jun 27, 2019
b1978ec
fix i18n_integrate
Bamieh Jun 27, 2019
da94bf1
fix i18n_integrate
Bamieh Jun 27, 2019
d529138
Merge branch 'master' of github.com:elastic/kibana into i18n/packages…
Bamieh Jun 27, 2019
db8a42d
Merge branch 'master' of github.com:elastic/kibana into i18n/packages…
Bamieh Jul 2, 2019
2eba298
code review changes
Bamieh Jul 3, 2019
84cadf2
code review changes
Bamieh Jul 3, 2019
e940be4
Merge branch 'master' of github.com:elastic/kibana into i18n/packages…
Bamieh Jul 3, 2019
b6b9db9
try using scanDir
Bamieh Jul 3, 2019
aea37d1
Merge branch 'master' of github.com:elastic/kibana into i18n/packages…
Bamieh Jul 3, 2019
a8cfcbd
revert to using concat
Bamieh Jul 3, 2019
19c1f52
add config type
Bamieh Jul 3, 2019
0ba536b
Merge branch 'master' of github.com:elastic/kibana into i18n/packages…
Bamieh Jul 10, 2019
fb45fe3
Merge branch 'master' of github.com:elastic/kibana into i18n/packages…
Bamieh Jul 21, 2019
619aa1a
code review fixes
Bamieh Jul 21, 2019
76a73f1
Merge branch 'i18n/packages-translations' of github.com:Bamieh/kibana…
Bamieh Jul 21, 2019
0ca5dc6
finalize PR
Bamieh Jul 21, 2019
bbd62fa
revert kibana.yml
Bamieh Jul 21, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 2 additions & 39 deletions .i18nrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,45 +23,8 @@
"timelion": "src/legacy/core_plugins/timelion",
"tagCloud": "src/legacy/core_plugins/tagcloud",
"tsvb": "src/legacy/core_plugins/metrics",
"kbnESQuery": "packages/kbn-es-query",
"xpack.actions": "x-pack/legacy/plugins/actions",
"xpack.alerting": "x-pack/legacy/plugins/alerting",
"xpack.apm": "x-pack/legacy/plugins/apm",
"xpack.beatsManagement": "x-pack/legacy/plugins/beats_management",
"xpack.canvas": "x-pack/legacy/plugins/canvas",
"xpack.code": "x-pack/legacy/plugins/code",
"xpack.crossClusterReplication": "x-pack/legacy/plugins/cross_cluster_replication",
"xpack.dashboardMode": "x-pack/legacy/plugins/dashboard_mode",
"xpack.fileUpload": "x-pack/legacy/plugins/file_upload",
"xpack.graph": "x-pack/legacy/plugins/graph",
"xpack.grokDebugger": "x-pack/legacy/plugins/grokdebugger",
"xpack.idxMgmt": "x-pack/legacy/plugins/index_management",
"xpack.indexLifecycleMgmt": "x-pack/legacy/plugins/index_lifecycle_management",
"xpack.infra": "x-pack/legacy/plugins/infra",
"xpack.kueryAutocomplete": "x-pack/legacy/plugins/kuery_autocomplete",
"xpack.licenseMgmt": "x-pack/legacy/plugins/license_management",
"xpack.maps": "x-pack/legacy/plugins/maps",
"xpack.ml": "x-pack/legacy/plugins/ml",
"xpack.logstash": "x-pack/legacy/plugins/logstash",
"xpack.main": "x-pack/legacy/plugins/xpack_main",
"xpack.telemetry": "x-pack/legacy/plugins/telemetry",
"xpack.monitoring": "x-pack/legacy/plugins/monitoring",
"xpack.remoteClusters": "x-pack/legacy/plugins/remote_clusters",
"xpack.reporting": "x-pack/legacy/plugins/reporting",
"xpack.rollupJobs": "x-pack/legacy/plugins/rollup",
"xpack.searchProfiler": "x-pack/legacy/plugins/searchprofiler",
"xpack.siem": "x-pack/legacy/plugins/siem",
"xpack.security": "x-pack/legacy/plugins/security",
"xpack.server": "x-pack/legacy/server",
"xpack.snapshotRestore": "x-pack/legacy/plugins/snapshot_restore",
"xpack.spaces": "x-pack/legacy/plugins/spaces",
"xpack.upgradeAssistant": "x-pack/legacy/plugins/upgrade_assistant",
"xpack.uptime": "x-pack/legacy/plugins/uptime",
"xpack.watcher": "x-pack/legacy/plugins/watcher"
"kbnESQuery": "packages/kbn-es-query"
},
"exclude": ["src/legacy/ui/ui_render/ui_render_mixin.js"],
"translations": [
"x-pack/plugins/translations/translations/zh-CN.json",
"x-pack/plugins/translations/translations/ja-JP.json"
]
"translations": []
Bamieh marked this conversation as resolved.
Show resolved Hide resolved
}
1 change: 1 addition & 0 deletions src/dev/build/tasks/copy_source_task.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const CopySourceTask = {
'webpackShims/**',
'config/kibana.yml',
'tsconfig*.json',
'.i18nrc.json',
Bamieh marked this conversation as resolved.
Show resolved Hide resolved
'kibana.d.ts'
],
});
Expand Down
54 changes: 28 additions & 26 deletions src/dev/i18n/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,45 +21,47 @@ import { resolve } from 'path';

// @ts-ignore
import { normalizePath, readFileAsync } from '.';
// @ts-ignore
import rootConfig from '../../../.i18nrc.json';

export interface I18nConfig {
paths: Record<string, string>;
exclude: string[];
translations: string[];
prefix?: string;
}

/**
* Merges root .i18nrc.json config with any other additional configs (e.g. from
* third-party plugins).
* @param configPaths List of config paths.
*/
export async function mergeConfigs(configPaths: string | string[] = []) {
const mergedConfig: I18nConfig = { exclude: [], translations: [], ...rootConfig };
export async function checkConfigNamespacePrefix(configPath: string) {
const { prefix, paths } = JSON.parse(await readFileAsync(resolve(configPath)));
for (const [namespace] of Object.entries(paths)) {
if (prefix && prefix !== namespace.split('.')[0]) {
throw new Error(`namespace ${namespace} must be prefixed with ${prefix} in ${configPath}`);
}
}
}

for (const configPath of Array.isArray(configPaths) ? configPaths : [configPaths]) {
const additionalConfig: I18nConfig = {
paths: {},
exclude: [],
translations: [],
...JSON.parse(await readFileAsync(resolve(configPath))),
};
export async function mergeConfig(
configPath: string,
config: I18nConfig = { exclude: [], translations: [], paths: {} }
) {
const additionalConfig: I18nConfig = {
paths: {},
exclude: [],
translations: [],
...JSON.parse(await readFileAsync(resolve(configPath))),
};

for (const [namespace, path] of Object.entries(additionalConfig.paths)) {
mergedConfig.paths[namespace] = normalizePath(resolve(configPath, '..', path));
}
for (const [namespace, path] of Object.entries(additionalConfig.paths)) {
config.paths[namespace] = normalizePath(resolve(configPath, '..', path));
}

for (const exclude of additionalConfig.exclude) {
mergedConfig.exclude.push(normalizePath(resolve(configPath, '..', exclude)));
}
for (const exclude of additionalConfig.exclude) {
config.exclude.push(normalizePath(resolve(configPath, '..', exclude)));
}

for (const translations of additionalConfig.translations) {
mergedConfig.translations.push(normalizePath(resolve(configPath, '..', translations)));
}
for (const translations of additionalConfig.translations) {
config.translations.push(normalizePath(resolve(configPath, '..', translations)));
}

return mergedConfig;
return config;
Bamieh marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/dev/i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export { extractMessagesFromPathToMap } from './extract_default_translations';
// @ts-ignore
export { matchEntriesWithExctractors } from './extract_default_translations';
// @ts-ignore
export { writeFileAsync, readFileAsync, normalizePath, ErrorReporter } from './utils';
export { arrayify, writeFileAsync, readFileAsync, normalizePath, ErrorReporter } from './utils';
export { serializeToJson, serializeToJson5 } from './serializers';
export { I18nConfig, filterConfigPaths, mergeConfigs } from './config';
export { I18nConfig, filterConfigPaths, mergeConfig, checkConfigNamespacePrefix } from './config';
export { integrateLocaleFiles } from './integrate_locale_files';
43 changes: 43 additions & 0 deletions src/dev/i18n/tasks/check_configs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. 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 { resolve, join } from 'path';
import { ErrorReporter, checkConfigNamespacePrefix, arrayify } from '..';

export function checkConfigs(additionalConfigPaths: string | string[] = []) {
const root = join(__dirname, '../../../../');
const kibanaRC = resolve(root, '.i18nrc.json');
Bamieh marked this conversation as resolved.
Show resolved Hide resolved
const xpackRC = resolve(root, 'x-pack/.i18nrc.json');

const configPaths = [kibanaRC, xpackRC, ...arrayify(additionalConfigPaths)];

return configPaths.map(configPath => ({
task: async (context: { reporter: ErrorReporter }) => {
try {
await checkConfigNamespacePrefix(configPath);
} catch (err) {
const { reporter } = context;
const reporterWithContext = reporter.withContext({ name: configPath });
reporterWithContext.report(err);
throw reporter;
}
},
title: `Checking configs in ${configPath}`,
}));
}
9 changes: 1 addition & 8 deletions src/dev/i18n/tasks/extract_default_translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,7 @@ import chalk from 'chalk';
import { createFailError } from '../../run';
import { ErrorReporter, extractMessagesFromPathToMap, filterConfigPaths, I18nConfig } from '..';

export function extractDefaultMessages({
path,
config,
}: {
path?: string | string[];
config: I18nConfig;
}) {
const inputPaths = Array.isArray(path) ? path : [path || './'];
export function extractDefaultMessages(config: I18nConfig, inputPaths: string[]) {
const filteredPaths = filterConfigPaths(inputPaths, config) as string[];
if (filteredPaths.length === 0) {
throw createFailError(
Expand Down
12 changes: 6 additions & 6 deletions src/dev/i18n/tasks/extract_untracked_translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,13 @@ export async function extractUntrackedMessagesTask({
}
}

export function extractUntrackedMessages(srcPaths: string[], config: I18nConfig) {
return srcPaths.map(srcPath => ({
title: `Checking untracked messages in ${srcPath}`,
task: async (context: { reporter: ErrorReporter }) => {
const { reporter } = context;
export function extractUntrackedMessages(inputPaths: string[]) {
return inputPaths.map(inputPath => ({
title: `Checking untracked messages in ${inputPath}`,
task: async (context: { reporter: ErrorReporter; config: I18nConfig }) => {
const { reporter, config } = context;
const initialErrorsNumber = reporter.errors.length;
const result = await extractUntrackedMessagesTask({ path: srcPath, config, reporter });
const result = await extractUntrackedMessagesTask({ path: inputPath, config, reporter });
if (reporter.errors.length === initialErrorsNumber) {
return result;
}
Expand Down
2 changes: 2 additions & 0 deletions src/dev/i18n/tasks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@
export { extractDefaultMessages } from './extract_default_translations';
export { extractUntrackedMessages } from './extract_untracked_translations';
export { checkCompatibility } from './check_compatibility';
export { mergeConfigs } from './merge_configs';
export { checkConfigs } from './check_configs';
43 changes: 43 additions & 0 deletions src/dev/i18n/tasks/merge_configs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. 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 { resolve, join } from 'path';
import { ErrorReporter, I18nConfig, mergeConfig, arrayify } from '..';

export function mergeConfigs(additionalConfigPaths: string | string[] = []) {
const root = join(__dirname, '../../../../');
const kibanaRC = resolve(root, '.i18nrc.json');
Bamieh marked this conversation as resolved.
Show resolved Hide resolved
const xpackRC = resolve(root, 'x-pack/.i18nrc.json');

const configPaths = [kibanaRC, xpackRC, ...arrayify(additionalConfigPaths)];

return configPaths.map(configPath => ({
task: async (context: { reporter: ErrorReporter; config?: I18nConfig }) => {
try {
context.config = await mergeConfig(configPath, context.config);
} catch (err) {
const { reporter } = context;
const reporterWithContext = reporter.withContext({ name: configPath });
reporterWithContext.report(err);
throw reporter;
}
},
title: `Merging configs in ${configPath}`,
}));
}
5 changes: 5 additions & 0 deletions src/dev/i18n/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,3 +324,8 @@ export class ErrorReporter {
);
}
}

// export function arrayify<Subj = any>(subj: Subj | Subj[]): Subj[] {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is there commented out code here? Did you start typescripting this file and then stop?

Copy link
Member Author

Choose a reason for hiding this comment

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

I left it for whenever we want to mvoe this file to TS

export function arrayify(subj) {
return Array.isArray(subj) ? subj : [subj];
}
35 changes: 24 additions & 11 deletions src/dev/run_i18n_check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@
import chalk from 'chalk';
import Listr from 'listr';

import { ErrorReporter, mergeConfigs } from './i18n';
import { extractDefaultMessages, extractUntrackedMessages, checkCompatibility } from './i18n/tasks';
import { ErrorReporter } from './i18n';
import {
extractDefaultMessages,
extractUntrackedMessages,
checkCompatibility,
checkConfigs,
mergeConfigs,
} from './i18n/tasks';
import { createFailError, run } from './run';

run(
Expand Down Expand Up @@ -59,27 +65,34 @@ run(
throw createFailError(`${chalk.white.bgRed(' I18N ERROR ')} --fix can't have a value`);
}

const config = await mergeConfigs(includeConfig);
const srcPaths = Array().concat(path || ['./src', './packages', './x-pack']);

if (config.translations.length === 0) {
return;
}

const list = new Listr(
[
{
title: 'Checking .i18nrc.json files',
task: () => new Listr(checkConfigs(includeConfig), { exitOnError: true }),
},
{
title: 'Merging .i18nrc.json files',
task: () => new Listr(mergeConfigs(includeConfig), { exitOnError: true }),
},
{
title: 'Checking For Untracked Messages based on .i18nrc.json',
task: () => new Listr(extractUntrackedMessages(srcPaths, config), { exitOnError: true }),
skip: ({ config }) => !config.translations.length,
Bamieh marked this conversation as resolved.
Show resolved Hide resolved
task: ({ config }) =>
new Listr(extractUntrackedMessages(srcPaths), { exitOnError: true }),
},
{
title: 'Validating Default Messages',
task: () =>
new Listr(extractDefaultMessages({ path: srcPaths, config }), { exitOnError: true }),
skip: ({ config }) => !config.translations.length,
task: ({ config }) =>
new Listr(extractDefaultMessages(config, srcPaths), { exitOnError: true }),
},
{
title: 'Compatibility Checks',
task: () =>
skip: ({ config }) => !config.translations.length,
task: ({ config }) =>
new Listr(
checkCompatibility(
config,
Expand Down
20 changes: 9 additions & 11 deletions src/dev/run_i18n_extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,8 @@ import chalk from 'chalk';
import Listr from 'listr';
import { resolve } from 'path';

import {
ErrorReporter,
mergeConfigs,
serializeToJson,
serializeToJson5,
writeFileAsync,
} from './i18n';
import { extractDefaultMessages } from './i18n/tasks';
import { ErrorReporter, serializeToJson, serializeToJson5, writeFileAsync } from './i18n';
import { extractDefaultMessages, mergeConfigs } from './i18n/tasks';
import { createFailError, run } from './run';

run(
Expand All @@ -52,13 +46,17 @@ run(
`${chalk.white.bgRed(' I18N ERROR ')} --path and --include-config require a value`
);
}

const config = await mergeConfigs(includeConfig);
const srcPaths = Array().concat(path || ['./src', './packages', './x-pack']);
Bamieh marked this conversation as resolved.
Show resolved Hide resolved

const list = new Listr([
{
title: 'Merging .i18nrc.json files',
task: () => new Listr(mergeConfigs(includeConfig), { exitOnError: true }),
},
{
title: 'Extracting Default Messages',
task: () => new Listr(extractDefaultMessages({ path, config }), { exitOnError: true }),
task: ({ config }) =>
new Listr(extractDefaultMessages(config, srcPaths), { exitOnError: true }),
},
{
title: 'Writing to file',
Expand Down
Loading