Văn bản UI trong Figma là một tạo tác thiết kế. Đó là bản sao mockup, thường được viết bởi nhà thiết kế chứ không phải product manager, hiếm khi được xem xét cho i18n. figmascope trích xuất nó dù sao — vì ngay cả bản sao placeholder cũng cần một khóa tài nguyên nếu bạn đang tạo code cuối cùng sẽ được bản địa hóa, và quá trình trích xuất là nơi logic tồn tại.
strings.json là tạo tác ánh xạ ID tài nguyên ký hiệu chấm sang giá trị chuỗi ký tự. Bài viết này trình bày cách tạo khóa, những gì bị lọc ra, điều gì xảy ra khi khóa va chạm và cách ánh xạ sang Android strings.xml và các định dạng i18n khác.
Định dạng
{
"speed.test": "Speed Test",
"data.transfer.rate": "Data Transfer Rate",
"start": "Start",
"results.download": "Download",
"results.upload": "Upload",
"results.ping": "Ping",
"unit.mbps": "Mbps",
"settings.server.auto": "Auto Select"
}
Cấu trúc là một đối tượng phẳng được khóa bởi ID tài nguyên ký hiệu chấm. Các giá trị là nội dung chuỗi ký tự từ Figma. Các đường dẫn chấm lồng nhau có ý nghĩa ngữ nghĩa — results.download và results.upload ở trong cùng một nhóm logic — nhưng file là JSON phẳng, không lồng nhau. Điều này khớp với cách Android's strings.xml hoạt động (tên tài nguyên phẳng với quy ước chấm để nhóm) và cách hầu hết các thư viện i18n (i18next, Rosetta, v.v.) xử lý namespace khóa phẳng.
Cách tạo khóa
Tạo khóa bắt đầu từ tên layer Figma của node, không phải nội dung văn bản. Một node văn bản có tên Data Transfer Rate Label với nội dung "Data Transfer Rate" tạo ra khóa từ tên layer, không phải giá trị.
Pipeline tạo:
- Lấy tên layer
- Áp dụng bộ lọc
sanitizeName: chuyển ký tự Cyrillic, loại bỏ ký tự kiểm soát/hai chiều (phạm vi Unicode U+202A–U+202E và tương tự), loại bỏ ký tự không phải chữ-số không phải khoảng trắng - Chuyển thành chữ thường và thay khoảng trắng bằng dấu chấm
- Cắt bỏ dấu chấm đầu và cuối
Vì vậy "Data Transfer Rate Label" → "data.transfer.rate.label". Trong thực tế, nhà thiết kế thường đặt tên layer văn bản mà không có danh từ cuối, nên "Data Transfer Rate" → "data.transfer.rate".
Bước chuyển ký tự Cyrillic tồn tại vì figmascope được sử dụng với file Figma trên nhiều ngôn ngữ. Một layer có tên Скорость chuyển thành Skorost', sau đó thành "skorost'" → sau khi xóa ký tự đặc biệt → "skorost". Không đẹp, nhưng khóa ổn định qua các lần chạy cho cùng tên layer.
Tạo khóa từ tên layer, không phải giá trị văn bản. Hai node văn bản có nội dung giống nhau nhưng tên layer khác nhau sẽ có khóa khác nhau. Hai node văn bản có nội dung khác nhau nhưng cùng tên layer tạo ra va chạm — được xử lý bên dưới.
Bộ lọc khóa — những gì bị loại bỏ
Không phải mọi node văn bản trong file Figma đều nên là chuỗi có thể bản địa hóa. figmascope lọc trước khi tạo khóa:
- Chuỗi rỗng: Các node văn bản không có nội dung hoặc chỉ có khoảng trắng bị loại bỏ.
- Chuỗi chỉ có số: Các giá trị như
"42","100%","3.14"bị loại bỏ. Đây là giá trị dữ liệu, không phải bản sao UI, và nên đến từ lớp dữ liệu của bạn. - Chuỗi ngắn (≤2 ký tự): Ký tự đơn và chuỗi hai ký tự bị loại bỏ. Icon, dấu đầu dòng, chỉ số trên — đây không phải tài nguyên chuỗi.
- Khóa sanitize thành rỗng: Nếu tên layer hoàn toàn gồm các ký tự bị xóa bởi
sanitizeName, kết quả là khóa rỗng. Các node này bị loại bỏ thầm lặng.
Bộ lọc số xứng đáng được giải thích thêm. Mockup thiết kế thường có số placeholder: "42 ms" (ping), "150 Mbps" (tốc độ tải). "42 ms" vượt qua bộ lọc vì không hoàn toàn là số — nó sẽ trở thành khóa "42.ms". Nhưng bạn có thể muốn trích xuất chỉ "ms" làm nhãn đơn vị và tính toán 42 lúc runtime. figmascope không tạo ra suy luận đó — nó lấy toàn bộ văn bản nguyên vẹn. Bộ lọc chuỗi ngắn loại bỏ "ms" một mình (2 ký tự), nhưng giữ "42 ms" như chuỗi đầy đủ.
Đây là giới hạn đã thừa nhận. Văn bản UI kết hợp dữ liệu template với nhãn ký tự rất khó tự động phân tách. Code được tạo nên xem chuỗi được trích xuất như điểm khởi đầu, không phải bản sao cuối cùng.
Xử lý va chạm
Va chạm xảy ra khi hai node văn bản khác nhau tạo ra cùng một khóa nhưng có giá trị khác nhau. Ví dụ: một layer có tên "Label" trên màn hình A chứa "Download" và một layer có tên "Label" trên màn hình B chứa "Upload". Cả hai đều tạo ra khóa "label".
Quy tắc va chạm của figmascope: loại bỏ khóa hoàn toàn khỏi strings.json và phát ra cảnh báo trong _meta.json:
// _meta.json
{
"warnings": [
"strings-collision:label"
]
}
Giữ một tùy tiện sẽ sai — bạn sẽ thầm lặng dịch sai một trong hai chuỗi. Giữ cả hai với các khóa được phân biệt (ví dụ: "label.1", "label.2") sẽ là đoán tên không phục vụ ai. Loại bỏ là trung thực.
IR xử lý va chạm gọn gàng: khi một khóa bị loại bỏ do va chạm, figmascope duyệt IR và xóa trường stringRef khỏi tất cả các node leaf đã tham chiếu nó. Trường text (giá trị ký tự) vẫn còn. Agent thấy leaf với text nhưng không có stringRef và biết sử dụng literal làm fallback — điều này an toàn vì quy tắc CONTEXT.md chỉ nói "dùng stringRef nếu có."
// Trước khi giải quyết va chạm — hai leaf cùng khóa, văn bản khác nhau
{ "kind": "leaf", "text": "Download", "stringRef": "label" }
{ "kind": "leaf", "text": "Upload", "stringRef": "label" }
// Sau khi giải quyết va chạm — khóa bị loại bỏ, văn bản được giữ
{ "kind": "leaf", "text": "Download" }
{ "kind": "leaf", "text": "Upload" }
Cảnh báo cho bạn biết để sửa tên layer trong Figma. Layer có tên "Download Label" và "Upload Label" sẽ tạo ra các khóa phân biệt "download.label" và "upload.label" mà không có va chạm.
Ánh xạ sang Android strings.xml
Android strings.xml sử dụng ID tài nguyên chuỗi phẳng với dấu gạch dưới. Ký hiệu chấm từ figmascope ánh xạ gọn gàng:
// strings.json
{
"speed.test": "Speed Test",
"data.transfer.rate": "Data Transfer Rate",
"results.download": "Download"
}
// → strings.xml (được tạo)
<resources>
<string name="speed_test">Speed Test</string>
<string name="data_transfer_rate">Data Transfer Rate</string>
<string name="results_download">Download</string>
</resources>
Phép biến đổi là: thay dấu chấm bằng dấu gạch dưới. Đó là phép biến đổi hoàn chỉnh. ID tài nguyên Android không cho phép dấu chấm; dấu gạch dưới là dấu phân cách theo quy ước. Khóa speed.test trong strings.json trở thành R.string.speed_test trong Kotlin, đó là điều ràng buộc CONTEXT.md chỉ agent sử dụng khi thấy stringRef: "speed.test".
// Ràng buộc CONTEXT.md trong hành động
// IR leaf: { "text": "Speed Test", "stringRef": "speed.test" }
// Đầu ra agent:
Text(text = stringResource(R.string.speed_test))
Ánh xạ sang các định dạng i18n khác
Ký hiệu chấm là lingua franca cho i18n. Hầu hết các hệ thống chấp nhận nó trực tiếp hoặc chỉ cần biến đổi tối thiểu:
| Định dạng | Định dạng khóa | Biến đổi từ ký hiệu chấm |
|---|---|---|
| Android strings.xml | speed_test |
Thay . bằng _ |
| iOS Localizable.strings | "speed.test" |
Không (ký hiệu chấm dùng trực tiếp) |
| i18next (JSON) | Lồng nhau: { "speed": { "test": "..." } } |
Mở rộng khóa phẳng thành cấu trúc lồng |
| Flutter ARB | speedTest |
Chuyển thành camelCase |
figmascope xuất định dạng ký hiệu chấm. Biến đổi theo mục tiêu được xử lý sau — bởi agent (nếu mục tiêu CONTEXT.md đủ rõ ràng) hoặc bởi một script chuyển đổi nhỏ.
Những gì strings.json không giải quyết
Ghi chú phạm vi trung thực: strings.json được trích xuất từ bất kỳ văn bản nào tồn tại trong Figma tại thời điểm xuất. Nó không phải là file tài nguyên i18n được xác nhận. Ba vấn đề bạn sẽ gặp:
Văn bản placeholder: Các mockup Figma thường sử dụng Lorem Ipsum, "[Title Here]", hoặc bản sao do nhà thiết kế viết chưa được xem xét. Các chuỗi được trích xuất là những gì có trong file, đã xem xét hay chưa.
Nội dung động: Các thiết kế thường hiển thị "John Doe" hoặc "42 Mbps" như dữ liệu đại diện. Đây không phải chuỗi có thể bản địa hóa — chúng là giá trị template. figmascope không thể phân biệt dữ liệu thời thiết kế với bản sao thời thiết kế. Bộ lọc số bắt được số thuần túy, nhưng chuỗi hỗn hợp như "42 Mbps" vẫn được trích xuất.
Chuỗi thiếu từ node bị lọc: Nếu node văn bản không vượt qua bộ lọc (quá ngắn, chỉ số, rỗng sau sanitize), nó sẽ không xuất hiện trong strings.json và leaf IR sẽ không có stringRef. Điều này là cố ý nhưng có nghĩa là độ bao phủ chuỗi của bạn phụ thuộc vào chất lượng đặt tên layer trong Figma.
Đầu ra là điểm khởi đầu. Sao chép nó vào file i18n của bạn, xem xét lại theo các quy ước đặt tên tài nguyên thực tế, xóa các chuỗi placeholder và thêm các khóa nội dung động theo cách thủ công. Đó là mười phút công việc thay vì trích xuất thủ công từng node văn bản từ Figma. Thử trích xuất chuỗi từ file của bạn trên figmascope.dev.
Để có bức tranh đầy đủ về cách stringRef chảy qua IR vào code được tạo, xem IR Theo Màn Hình — Stack, Overlay, Absolute, Leaf. Để biết cách các ràng buộc điều chỉnh việc sử dụng chuỗi được khai báo, xem Giải Phẫu CONTEXT.md. Để biết quy trình tạo Jetpack Compose từ đầu đến cuối, xem Jetpack Compose từ Figma. Sẵn sàng tạo strings.json của bạn? Sử dụng ứng dụng chính tại figmascope.dev.