Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 43 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
// Use IntelliSense to learn about possible Node.js debug attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "JavaScript Test using SourceMap",
"program": "${workspaceRoot}/test/index.ts",
"cwd": "${workspaceRoot}",
"args": [
//----
// Unable to reset DB in debugging mode.
//----
// Therefore, reset DB first by running
// `npm run reset-for-debugging` command,
// and run debugging mode later.
//----
"--reset", "false",

//----
// You can run specific test functions
//----
"--include", "compiler_",
"--exclude", "index",
],
"outFiles": ["${workspaceRoot}/bin/**/*.js"],
},
{
"type": "node",
"request": "launch",
"name": "Compiler Manual Testing",
"cwd": "${workspaceRoot}",
"args": [
"${workspaceRoot}/test/manual/compiler/result.ts"
],
"runtimeArgs": ["-r", "ts-node/register"],
"outFiles": ["${workspaceRoot}/bin/**/*.js"],
}
]
}
13 changes: 13 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"editor.tabSize": 2,
"editor.formatOnSave": true,
"[javascript][typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
},
"[prisma]": {
"editor.defaultFormatter": "Prisma.prisma",
}
}
28 changes: 28 additions & 0 deletions .vscode/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: build
on:
push:
paths:
- 'assets/**'
- 'src/**'
- 'test/**'
- 'package.json'
pull_request:
paths:
- 'assets/input/**'
- 'src/**'
- 'test/**'
- 'package.json'
jobs:
Ubuntu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Install dependencies
run: npm install
- name: Build
run: npm run build
- name: Test
run: npm run test
24 changes: 24 additions & 0 deletions .vscode/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: release
on:
release:
types: [created]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: none
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20.x
registry-url: https://registry.npmjs.org/
- name: Install dependencies
run: npm install
- name: Build
run: npm run build
- name: Publish to npm
run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH }}
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

Translate JSON file via Google Translate API.

`@samchon/json-translate` is a wrapper library that translates JSON files using the Google Translate API. It has optimization logic that reduces costs and elapsed time by minimizing the number of API calls.
`@samchon/json-translate` is a wrapper library that translates JSON files using the Google Translate API. It provides a more convenient way to translate JSON data, including optimization strategies recuding the cost and elapsed time of the translation by minimizing the number of the API calls.

Here is an example code translating `swagger.json` file.

Expand All @@ -27,8 +27,9 @@ const main = async (): Promise<void> => {
});
const input: OpenApi.IDocument = await fetchOpenApiDocument();
const output: OpenApi.IDocument = await translator.translate({
input,
to: "ko",
input, // JSON input data to translate
target: "ko", // target language to translate
// source: "en", // current language, but not essential
filter: (explore) =>
explore.key === "title" ||
explore.key === "description" ||
Expand All @@ -38,4 +39,11 @@ const main = async (): Promise<void> => {
console.log(output);
};
main().catch(console.error);
```
```

Also, you can see some example cases:

English (source) | Korean | Japanese | Arabic
--------|--------|----------|--------
[bbs.article.json](https://github.com/samchon/json-translator/blob/master/assets/input/bbs.article.json) | [bbs.ko.json](https://github.com/samchon/json-translator/blob/master/assets/output/bbs.article.ko.json) | [bbs.ja.json](https://github.com/samchon/json-translator/blob/master/assets/output/bbs.article.ja.json) | [bbs.ar.json](https://github.com/samchon/json-translator/blob/master/assets/output/bbs.article.ar.json)
[shopping.swagger.json](https://github.com/samchon/json-translator/blob/master/assets/input/shopping.swagger.json) | [shopping.ko.json](https://github.com/samchon/json-translator/blob/master/assets/output/shopping.swagger.ko.json) | [shopping.ja.json](https://github.com/samchon/json-translator/blob/master/assets/output/shopping.swagger.ja.json) | [shopping.ar.json](https://github.com/samchon/json-translator/blob/master/assets/output/shopping.swagger.ar.json)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@samchon/json-translator",
"version": "0.1.0",
"version": "0.1.1",
"description": "",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand Down
78 changes: 74 additions & 4 deletions src/JsonTranslator.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
import { Translate } from "@google-cloud/translate/build/src/v2";

/**
* JSON Translator.
*
* `JsonTranslator` is a class translating JSON data into another language.
*
* It wraps the `@google-cloud/translate` module and provides
* a more convenient way to translate JSON data, including optimization
* strategy reducing the cost and elapsed time of the translation by
* minimizing the number of the API calls.
*
* @reference
* @author Jeongho Nam - https://github.com/samchon
*/
export class JsonTranslator {
private readonly service_: Translate;

public constructor(options?: ConstructorParameters<typeof Translate>[0]) {
this.service_ = new Translate(options);
}

/**
* Translate JSON data.
*
* @param props Properties for the translation.
* @returns The translated JSON data.
*/
public async translate<T>(props: JsonTranslator.IProps<T>): Promise<T> {
const collection: ICollection = prepareCollection(props);
const translated: string[] = [];
const from: string | undefined =
props.from ?? (await this.detect(collection.raw));
props.source ?? (await this.detect(collection.raw));

let queue: Array<IPiece> = [];
let bytes: number = 0;
Expand All @@ -21,7 +40,7 @@ export class JsonTranslator {
queue.map((p) => p.text),
{
from,
to: props.to,
to: props.target,
},
);
translated.push(...response);
Expand Down Expand Up @@ -57,6 +76,12 @@ export class JsonTranslator {
return collection.output;
}

/**
* Detect the language of the texts.
*
* @param texts Texts to detect the language.
* @returns The detected language or `undefined` if the language is unknown.
*/
public async detect(texts: string[]): Promise<string | undefined> {
if (texts.length === 0) return undefined;
const [response] = await this.service_.detect(
Expand All @@ -70,17 +95,61 @@ export class JsonTranslator {
}
}
export namespace JsonTranslator {
/**
* Properties for the translation.
*/
export interface IProps<T> {
/**
* The JSON input data to translate.
*/
input: T;
from?: string;
to: string;

/**
* Source language code.
*/
source?: string;

/**
* Target language code.
*/
target: string;

/**
* Filter function specifying which data to translate.
*
* @param explore Information about the data to explore.
* @returns `true` if the data should be translated; otherwise, `false`.
*/
filter?: (explore: IExplore) => boolean;
}

/**
* Exploration information used in the {@link IProps.filter} function.
*/
export interface IExplore {
/**
* The parent object instance.
*/
object: object | null;

/**
* The property key containing the {@link value}
*/
key: string | null;

/**
* Index number if the {@link value} is an array element.
*/
index: number | null;

/**
* Accessor path to the {@link value}.
*/
accessor: string[];

/**
* The string value to translate.
*/
value: string;
}
}
Expand Down Expand Up @@ -158,6 +227,7 @@ const visitCollectionData = (next: {
...next.explore,
object: next.value,
key,
index: null,
accessor: [...next.explore.accessor, key],
},
setter: (x) => (next.value[key] = x),
Expand Down
2 changes: 1 addition & 1 deletion test/features/test_bbs_article.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const test_bbs_article = async (
JSON.stringify(
await translator.translate({
input,
to: lang,
target: lang,
filter: ({ key }) => key === "title" || key === "body",
}),
null,
Expand Down
27 changes: 0 additions & 27 deletions test/features/test_connector_swagger.ts

This file was deleted.

2 changes: 1 addition & 1 deletion test/features/test_shopping_swagger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const test_connector_swagger = async (
JSON.stringify(
await translator.translate({
input,
to: lang,
target: lang,
filter: (explore) =>
explore.key === "title" ||
explore.key === "description" ||
Expand Down