Your browser does not support the video tag.
  • Home
  • Blog
  • Talk

© 2025 YIKZERO

Lokalise MCP Automatic Translation Solution

Develop· 2 days ago
This article was translated from Chinese byGemini 2.5 Pro. If there are any discrepancies, please refer to the Chinese version.

Preface

As the saying goes, "Laziness" is the primary driving force behind productivity. In our current requirement design process, a significant amount of language translation work is involved. Each requirement needs to translate the English titles and descriptions in the manuscript into a total of eighteen languages, including Chinese, French, Japanese, and Thai, and ultimately provide them to developers in the form of translation keys. This is actually a highly repetitive and tedious task. We need to find a way to be lazy and ensure translation quality.

Currently, the multilingual platform we use is Lokalise, so the solution I will talk about next will mainly focus on Lokalise, but other platforms can also refer to it.

Lokalise MCP Automatic Translation Solution
Lokalise MCP Automatic Translation Solution

Basic Idea

To achieve full automation, it's actually just a two-step process:

  1. Find a knowledgeable translator: AI translation is powerful, but it doesn't understand business terminology (for example, translating "Gas" into "气体" which means "gas" literally), and it may also translate some words that don't need to be translated. Therefore, we need to inject business context and set rules for the AI.
  2. Equip the AI with "hands": After translating, you still have to copy and paste each item into the Lokalise backend, which is the most tiring part. Through the MCP protocol, let the AI directly call the Lokalise API.

Final Solution

The technology stack I chose is Node.js + MCP SDK + Client Tool.

The choice of client is very flexible, as long as it supports MCP. Initially, I used Claude Desktop, but for friends who like the command line, you can completely replace it with Claude Code or Gemini CLI, and the effect is just as smooth.

Gemini may be better at literary tasks such as translation, so I recommend it.

1. Core Code (MCP Server)

Lokalise itself provides a complete REST API, which makes it convenient for us to operate it through code.

In order to write less boilerplate code, I directly used the official Node.js SDK (@lokalise/node-lokalise-api). Referring to the official documentation of MCP, I packaged these APIs into an MCP Server.

It mainly exposes two tools to AI:

  • search-keys: Used for deduplication to see if anyone has translated it before.
  • create-keys: Used to do the work, write the multilingual copy generated by AI into the backend.
Call Lokalise MCP Server
Call Lokalise MCP Server

The logic is actually not complicated. In essence, it is an API relay:

Click to view the core code of index.ts
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { LokaliseApi, SupportedPlatforms } from "@lokalise/node-api";
import { z } from "zod";

const LOKALISE_API_KEY = process.env.LOKALISE_API_KEY;
const DEFAULT_PROJECT_ID = process.env.DEFAULT_PROJECT_ID;
const DEFAULT_PLATFORMS = ["web", "ios", "android", "other"];
const PLATFORMS = (
  process.env.PLATFORMS
    ? process.env.PLATFORMS.split(",").map((p) => p.trim())
    : DEFAULT_PLATFORMS
) as SupportedPlatforms[];

const lokaliseApi = new LokaliseApi({ apiKey: LOKALISE_API_KEY });

const server = new McpServer(
  {
    name: "lokalise-mcp",
    version: "1.0.0",
    author: "yikZero",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// ... get-project-info and search-keys tool code omitted ...

server.registerTool(
  "create-keys",
  {
    title: "Create Keys",
    description: "Creates one or more keys in the project",
    inputSchema: {
      projectId: z
        .string()
        .describe(
          "A unique project identifier, if not provide, first use get-project-info tool to get the project id"
        ),
      keys: z.array(
        z.object({
          keyName: z.string().describe("Key identifier"),
          platforms: z
            .array(z.enum(["web", "ios", "android", "other"]))
            .describe(
              "Platforms for the key. If not provided, use the default platforms: " +
                PLATFORMS.join(", ")
            ),
          translations: z
            .array(
              z.object({
                languageIso: z
                  .string()
                  .describe(
                    "Unique code of the language of the translation, get the list from the get-project-info tool"
                  ),
                translation: z
                  .string()
                  .describe("The actual translation. Pass as an object"),
              })
            )
            .describe("Translations for all languages"),
        })
      ),
    },
  },
  async ({ projectId, keys }) => {
    const response = await lokaliseApi.keys().create(
      {
        keys: keys.map((key) => ({
          key_name: key.keyName,
          platforms: key.platforms,
          translations: key.translations.map((t) => ({
            language_iso: t.languageIso,
            translation: t.translation,
          })),
        })),
      },
      { project_id: projectId }
    );

    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(response),
        },
      ],
      structuredContent: response as any,
    };
  }
);

// ... update-keys tool code omitted ...

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Lokalise MCP Server running on stdio");
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});

2. Train the AI (Prompt)

This is actually similar to the Project function in the web version of Claude. It allows you to pre-set some system prompts and provide some information. These all belong to providing the AI with background knowledge to facilitate its work.

Therefore, in order to make the AI act like an old employee, I wrote all the OneKey terminology (Glossary) and Key naming conventions (Snake Case) into a GEMINI.md file. If you are using Claude Code, you can also write a CLAUDE.md file.

There is actually a unified AGENTS.md now, but it has not yet completed the unified cause.

View GEMINI.md prompt details
You are a professional web3 project i18n translation expert specializing in translating word/sentence into multiple languages for software localization.

<onekey_background>
OneKey is a comprehensive cryptocurrency wallet solution...
</onekey_background>

<i18n_supported_languages>
English (United States), Bengali, Chinese Simplified...
</i18n_supported_languages>

<technical_terms>
OneKey, WalletConnect, iCloud, Google Drive, OneKey Lite, OneKey KeyTag, Face ID, Touch ID, Discord, X, GitHub, recovery phrase, QR-based, NFT, Defi, USB, Mint, Meme, GameFi, Lido, Passphrase...
</technical_terms>

<translation_namespaces>
global, onboarding, wallet, swap, earn, market, browser, settings, prime
</translation_namespaces>

Translation Process:

1. Direct Translation:
   - Provide a literal translation of the word/sentence into all supported languages
   - If the text contains a number, replace it with {number}
   - Preserve all technical terms and variables, like {variableName}, HTML tags, etc

2. Refined Translation:
   - Create an optimized version that enhances clarity and natural flow in each language
   - Ensure cultural appropriateness while preserving the original meaning
   - The title needs to be used Sentence case
   - A space (half-width space) between a full-width character (Kanji) and a half-width character (letter, number, or symbol)

3. Key Generation:
   - Create a self-explanatory key in snake_case format
   - Structure as namespace::descriptive_key_name

4. **Filtering Logic**:
   - IGNORE common UI elements that likely already exist in the 'global' namespace, such as: "Close", "Open", "Cancel", "Confirm", "Back", "Next", "Done". Do NOT generate keys for these.
   - Only focus on the unique, business-specific text in the provided context.

Output Format:
1. Key: [namespace::descriptive_key_name]
2. Direct Translation Table (brief reference)
3. Refined Translation Table (primary focus)

Items need checked:
1. If the user provides the Key, use the user-provided Key.
2. If there is an obvious spelling error, I need your help to correct it and inform you.
3. After the translation is completed, need to call the tool to create/update the corresponding key.

3. Configuration File

Finally, in the MCP configuration file (such as claude_desktop_config.json or .mcp.json), mount the Server we wrote.

{
  "mcpServers": {
    "lokalise": {
      "command": "node",
      "args": ["/Users/yikzero/Code/lokalise-mcp/build/index.js"],
      "env": {
        "LOKALISE_API_KEY": "xxxx969xxxxxxxx7c18760c",
        "DEFAULT_PROJECT_ID": "44xxxxxe4ef8.8099xx5",
        "PLATFORMS": "ios,android,web,other"
      }
    }
  }
}

Actual Effect

The best scenario is to use it with design drafts.

Previously, every time a design was completed, I had to type out the copy one by one according to the design draft. Now I can directly export the design draft.

For example, if I just finished drawing a new Onboarding pop-up window in Figma, I can just take a screenshot and throw it to the AI and say (if it's too long, it's recommended to let it list a To-Do List):

"This is a new import wallet pop-up window, please process the copy inside."

The AI will automatically perform the following operations:

  1. Visual Recognition: Use the model's built-in visual capabilities to directly extract the copy from the screenshot.
  2. Dual Translation: This is the key to ensuring quality. It will strictly follow the requirements of the Prompt, first generate a "literal translation table" to ensure that variables (such as {number}) and terms are accurate, and then generate an "interpretive translation table" to polish the copy (such as processing full-width and half-width spaces in Japanese, and the Sentence case of titles).
  3. Automatic Entry: After confirming that the interpretive translation results are correct, it will automatically generate a standard Key like onboarding::import_phrase_title, and use MCP to write the translations of 18 languages into Lokalise at once.

Written at the end

Use Claude to write an MCP Server, and then supply it to Gemini CLI for calling, so that they can work better. I don't know who is the capitalist (misunderstanding.

A 2025 Guide to New Internet Jobs