Skip to content

Commit

Permalink
refactor: improve gemini translator (#1006)
Browse files Browse the repository at this point in the history
  • Loading branch information
lacolaco authored Dec 22, 2024
1 parent 8733d0e commit 2e443f4
Show file tree
Hide file tree
Showing 9 changed files with 331 additions and 388 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GOOGLE_API_KEY=
16 changes: 8 additions & 8 deletions adev-ja/src/content/introduction/essentials/components.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<docs-decorative-header title="コンポーネント" imgSrc="adev/src/assets/images/components.svg"> <!-- markdownlint-disable-line -->
Angularでアプリケーションを作成するための基本的な構成要素
Angularアプリケーションを作成するための基本的な構成要素
</docs-decorative-header>

コンポーネントは、Angularアプリケーションの主要な構成要素です。各コンポーネントは、より大きなウェブページの一部を表します。アプリケーションをコンポーネントに整理することで、プロジェクトに構造が与えられ、コードが特定の部分に明確に分割されるため、保守と拡張が容易になります。
Expand Down Expand Up @@ -73,7 +73,7 @@ h1 {

## コンポーネントの使用

複数のコンポーネントを組み合わせてアプリケーションを構築します。例えば、ユーザープロフィールページを構築する場合、ページを次のような複数のコンポーネントに分割できます
アプリケーションは複数のコンポーネントを組み合わせて構築します。例えば、ユーザーのプロファイルページを作成する場合、次のようにページをいくつかのコンポーネントに分割できます

```mermaid
flowchart TD
Expand All @@ -84,14 +84,14 @@ flowchart TD
D[UserAddress]
```

ここでは`UserProfile`コンポーネントは他のいくつかのコンポーネントを使用して最終的なページを作成します。
ここで`UserProfile`コンポーネントは他のいくつかのコンポーネントを使用して最終的なページを作成します。

コンポーネントをインポートして使用するには、次の手順が必要です。
1. コンポーネントのTypeScriptファイルで、使用するコンポーネントの`import`文を追加します。
2. `@Component`デコレーターで、使用するコンポーネントの`imports`配列にエントリを追加します
3. コンポーネントのテンプレートで、使用するコンポーネントのセレクターと一致する要素を追加します。
1. コンポーネントのTypeScriptファイルに、使用するコンポーネントの`import`文を追加します。
2. `@Component`デコレーターの`imports`配列に、使用するコンポーネントのエントリを追加します
3. コンポーネントのテンプレートに、使用するコンポーネントのセレクターと一致する要素を追加します。

`UserProfile`コンポーネントが`ProfilePhoto`コンポーネントをインポートする例を以下に示します
`ProfilePhoto`コンポーネントをインポートする`UserProfile`コンポーネントの例を次に示します

```angular-ts
// user-profile.ts
Expand All @@ -111,7 +111,7 @@ export class UserProfile {
}
```

Tip: Angularコンポーネントについてもっと知りたいですか? 詳細については[詳細なコンポーネントガイド](guide/components)を参照してください。
Tip: Angularコンポーネントの詳細については[詳細なコンポーネントガイド](guide/components)を参照してください。

## 次の手順

Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
"test": "yarn test:patch",
"test:patch": "git apply -v --check --directory origin ./tools/adev-patches/*.patch",
"update-origin": "tsx tools/update-origin.ts",
"translate": "tsx tools/translate.ts"
"translate": "tsx --env-file=.env tools/translator/main.ts"
},
"packageManager": "[email protected]",
"devDependencies": {
"@google/generative-ai": "0.14.1",
"@google/generative-ai": "0.21.0",
"@types/node": "20.14.10",
"chokidar": "3.6.0",
"consola": "3.2.3",
Expand All @@ -32,6 +32,6 @@
"textlint-rule-preset-ja-spacing": "2.4.3",
"textlint-rule-preset-ja-technical-writing": "10.0.1",
"textlint-rule-prh": "^6.0.0",
"tsx": "^4.16.2"
"tsx": "4.19.2"
}
}
225 changes: 0 additions & 225 deletions tools/translate.ts

This file was deleted.

72 changes: 72 additions & 0 deletions tools/translator/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import consola from 'consola';
import assert from 'node:assert';
import { readFile, writeFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import { parseArgs } from 'node:util';
import {
cpRf,
exists,
getEnFilePath,
getLocalizedFilePath,
} from '../lib/fsutils';
import { rootDir } from '../lib/workspace';
import { GeminiTranslator } from './translate';

async function main() {
const apiKey = process.env.GOOGLE_API_KEY;
assert(apiKey, 'GOOGLE_API_KEY 環境変数が設定されていません。');

const args = parseArgs({
options: { write: { type: 'boolean', default: false, short: 'w' } },
allowPositionals: true,
});
const { write } = args.values;
const [file] = args.positionals;

const fileExists = await exists(file);
if (!fileExists) {
throw new Error(`ファイルが見つかりません: ${file}`);
}

const content = await readFile(file, 'utf-8');
const prh = await readFile(resolve(rootDir, 'prh.yml'), 'utf-8');

const translator = new GeminiTranslator(apiKey);
const translated = await translator.translate(content, prh);

console.log(translated);
await writeTranslatedContent(file, translated, write);
}

async function writeTranslatedContent(
file: string,
content: string,
forceWrite = false
) {
const outputFile = getLocalizedFilePath(file);
const save =
forceWrite ||
(await consola.prompt(`翻訳結果を保存しますか?\n保存先: ${outputFile}`, {
type: 'confirm',
initial: false,
}));
if (!save) {
return;
}

const enFile = getEnFilePath(file);
// .en.* が存在しない場合は原文コピーを忘れているため、.en.md に元ファイルをコピーする
if (!(await exists(enFile))) {
consola.warn(
`原文ファイルが見つかりません。入力ファイルを ${enFile} にコピーします。`
);
await cpRf(file, enFile);
}
await writeFile(outputFile, content);
consola.success(`保存しました`);
}

main().catch((error) => {
consola.error(error);
process.exit(1);
});
14 changes: 14 additions & 0 deletions tools/translator/markdown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export type ContentBlock = string;

export function splitMarkdown(content: string): ContentBlock[] {
// split content by heading lines (lines starting with ##)
return content.split(/\n(?=##\s)/);
}

export async function renderMarkdown(blocks: ContentBlock[]) {
const content = blocks
.map((block) => (block.endsWith('\n') ? block.replace(/\n$/, '') : block))
.join('\n\n');
// add trailing newline
return content + '\n';
}
Loading

0 comments on commit 2e443f4

Please sign in to comment.