Teks UI di Figma adalah artefak desain. Ini adalah copy mockup, sering ditulis oleh desainer daripada manajer produk, jarang ditinjau untuk i18n. figmascope mengekstraknya juga — karena bahkan copy placeholder membutuhkan kunci resource jika Anda menghasilkan kode yang pada akhirnya akan dilokalisasi, dan proses ekstraksi adalah tempat logika berada.
strings.json adalah artefak yang memetakan ID resource notasi titik ke nilai string literal. Artikel ini mencakup cara kunci dibuat, apa yang difilter, apa yang terjadi ketika kunci bertabrakan, dan cara ini dipetakan ke Android strings.xml dan format i18n lainnya.
Format
{
"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"
}
Strukturnya adalah objek flat yang dikunci oleh ID resource notasi titik. Nilainya adalah konten string literal dari Figma. Jalur titik bersarang memiliki makna semantik — results.download dan results.upload berada dalam kelompok logis yang sama — tetapi file ini adalah JSON flat, bukan bersarang. Ini sesuai dengan cara kerja strings.xml Android (nama resource flat dengan konvensi titik untuk pengelompokan) dan cara sebagian besar library i18n (i18next, Rosetta, dll.) menangani namespace kunci flat.
Cara kunci dibuat
Pembuatan kunci dimulai dari nama layer Figma node, bukan konten teks. Node teks bernama Data Transfer Rate Label dengan konten "Data Transfer Rate" menghasilkan kunci dari nama layer, bukan nilainya.
Pipeline pembuatan kunci:
- Ambil nama layer
- Terapkan filter
sanitizeName: transliterasi karakter Sirilik, hapus karakter bidirectional/kontrol (rentang Unicode U+202A–U+202E dan sejenisnya), hapus karakter non-alfanumerik non-spasi - Ubah ke huruf kecil dan ganti spasi dengan titik
- Trim titik di awal dan akhir
Jadi "Data Transfer Rate Label" → "data.transfer.rate.label". Dalam praktiknya, desainer sering memberi nama layer teks tanpa kata benda di akhir, jadi "Data Transfer Rate" → "data.transfer.rate".
Langkah transliterasi Sirilik ada karena figmascope digunakan dengan file Figma lintas bahasa. Layer bernama Скорость ditransliterasi ke Skorost', kemudian menjadi "skorost'" → setelah strip karakter khusus → "skorost". Tidak terlalu indah, tetapi kuncinya stabil lintas run untuk nama layer yang sama.
Pembuatan kunci berasal dari nama layer, bukan nilai teks. Dua node teks dengan konten teks identik tetapi nama layer berbeda mendapatkan kunci yang berbeda. Dua node teks dengan konten teks berbeda tetapi nama layer yang sama menciptakan tabrakan — ditangani di bawah.
Filter kunci — apa yang dibuang
Tidak setiap node teks dalam file Figma harus menjadi string yang dapat dilokalisasi. figmascope memfilter sebelum membuat kunci:
- String kosong: Node teks tanpa konten atau konten hanya spasi dibuang.
- String numerik saja: Nilai seperti
"42","100%","3.14"dibuang. Ini adalah nilai data, bukan copy UI, dan harus berasal dari lapisan data Anda. - String pendek (≤2 karakter): Karakter tunggal dan string dua karakter dibuang. Ikon, poin peluru, superskrip — ini bukan resource string.
- Kunci yang tersanitasi menjadi kosong: Jika nama layer terdiri sepenuhnya dari karakter yang distrip oleh
sanitizeName, hasilnya adalah kunci kosong. Node ini dibuang secara diam-diam.
Filter numerik perlu penjelasan lebih lanjut. Mockup desain sering memiliki angka placeholder: "42 ms" (ping), "150 Mbps" (kecepatan unduh). "42 ms" lolos filter karena tidak sepenuhnya numerik — itu akan menjadi kunci "42.ms". Tetapi Anda mungkin ingin mengekstrak hanya "ms" sebagai label satuan dan menghitung 42 saat runtime. figmascope tidak membuat inferensi tersebut — ia mengambil teks penuh apa adanya. Filter string pendek membuang "ms" saja (2 karakter), tetapi menyimpan "42 ms" sebagai string penuh.
Ini adalah keterbatasan yang diakui. Teks UI yang mencampur data template dengan label literal sulit didekomposisi secara otomatis. Kode yang dihasilkan harus memperlakukan string yang diekstrak sebagai titik awal, bukan copy akhir.
Penanganan tabrakan
Tabrakan terjadi ketika dua node teks yang berbeda menghasilkan kunci yang sama tetapi memiliki nilai yang berbeda. Misalnya: layer bernama "Label" di layar A berisi "Download" dan layer bernama "Label" di layar B berisi "Upload". Keduanya menghasilkan kunci "label".
Aturan tabrakan figmascope: hapus kunci sepenuhnya dari strings.json dan emit peringatan dalam _meta.json:
// _meta.json
{
"warnings": [
"strings-collision:label"
]
}
Menyimpan salah satu secara sembarangan akan salah — Anda akan secara diam-diam menerjemahkan salah satu dari dua string secara tidak benar. Menyimpan keduanya dengan kunci yang disambiguasi (mis., "label.1", "label.2") akan menjadi tebakan penamaan yang tidak berguna bagi siapa pun. Membuang adalah pilihan yang jujur.
IR menangani tabrakan dengan bersih: ketika kunci dibuang karena tabrakan, figmascope menelusuri IR dan menghapus bidang stringRef dari semua node leaf yang mereferensikannya. Bidang text (nilai literal) tetap ada. Agen melihat leaf dengan text tetapi tanpa stringRef dan mengetahui untuk menggunakan literal sebagai fallback — yang aman karena aturan CONTEXT.md hanya mengatakan "gunakan stringRef jika ada."
// Sebelum resolusi tabrakan — dua leaf dengan kunci sama, teks berbeda
{ "kind": "leaf", "text": "Download", "stringRef": "label" }
{ "kind": "leaf", "text": "Upload", "stringRef": "label" }
// Setelah resolusi tabrakan — kunci dibuang, teks dipertahankan
{ "kind": "leaf", "text": "Download" }
{ "kind": "leaf", "text": "Upload" }
Peringatan memberi tahu Anda untuk memperbaiki nama layer di Figma. Layer bernama "Download Label" dan "Upload Label" akan menghasilkan kunci berbeda "download.label" dan "upload.label" tanpa tabrakan.
Pemetaan ke Android strings.xml
Android strings.xml menggunakan ID resource string flat dengan garis bawah. Notasi titik dari figmascope dipetakan dengan bersih:
// strings.json
{
"speed.test": "Speed Test",
"data.transfer.rate": "Data Transfer Rate",
"results.download": "Download"
}
// → strings.xml (yang dihasilkan)
<resources>
<string name="speed_test">Speed Test</string>
<string name="data_transfer_rate">Data Transfer Rate</string>
<string name="results_download">Download</string>
</resources>
Transformasinya adalah: ganti titik dengan garis bawah. Itu adalah transformasi yang lengkap. ID resource Android tidak mengizinkan titik; garis bawah adalah pemisah konvensional. Kunci speed.test dalam strings.json menjadi R.string.speed_test dalam Kotlin, yang merupakan apa yang ditunjukkan batasan CONTEXT.md ke agen saat melihat stringRef: "speed.test".
// Batasan CONTEXT.md dalam aksi
// IR leaf: { "text": "Speed Test", "stringRef": "speed.test" }
// Output agen:
Text(text = stringResource(R.string.speed_test))
Pemetaan ke format i18n lainnya
Notasi titik adalah lingua franca untuk i18n. Sebagian besar sistem menerimanya secara langsung atau hanya memerlukan transformasi minimal:
| Format | Format kunci | Transformasi dari notasi titik |
|---|---|---|
| Android strings.xml | speed_test |
Ganti . dengan _ |
| iOS Localizable.strings | "speed.test" |
Tidak ada (notasi titik digunakan langsung) |
| i18next (JSON) | Bersarang: { "speed": { "test": "..." } } |
Perluas kunci flat ke struktur bersarang |
| Flutter ARB | speedTest |
Konversi ke camelCase |
figmascope menghasilkan format notasi titik. Transformasi khusus target ditangani di hilir — baik oleh agen (jika target CONTEXT.md cukup eksplisit) atau oleh skrip konversi kecil.
Apa yang tidak diselesaikan strings.json
Catatan cakupan yang jujur: strings.json diekstrak dari teks apa pun yang ada dalam Figma pada waktu ekspor. Ini bukan file resource i18n yang tervalidasi. Tiga masalah yang akan Anda temui:
Teks placeholder: Mockup Figma sering menggunakan Lorem Ipsum, "[Judul Di Sini]", atau copy yang ditulis desainer yang belum ditinjau. String yang diekstrak adalah apa yang ada dalam file, ditinjau atau tidak.
Konten dinamis: Desain sering menampilkan "John Doe" atau "42 Mbps" sebagai data representatif. Ini bukan string yang dapat dilokalisasi — ini adalah nilai template. figmascope tidak dapat membedakan data waktu desain dari copy waktu desain. Filter numerik menangkap angka murni, tetapi string campuran seperti "42 Mbps" tetap diekstrak.
String yang hilang dari node yang difilter: Jika node teks gagal filter (terlalu pendek, numerik saja, kosong setelah sanitasi), itu tidak akan muncul dalam strings.json dan leaf IR tidak akan memiliki stringRef. Ini disengaja tetapi berarti cakupan string Anda bergantung pada kualitas penamaan layer di Figma.
Outputnya adalah titik awal. Salin ke file i18n Anda, tinjau terhadap konvensi penamaan resource Anda yang sebenarnya, hapus string placeholder, dan tambahkan kunci konten dinamis secara manual. Itu sepuluh menit pekerjaan alih-alih mengekstrak setiap node teks dari Figma secara manual. Coba ekstrak string dari file Anda sendiri di figmascope.dev.
Untuk gambaran lengkap tentang cara stringRef mengalir melalui IR ke kode yang dihasilkan, lihat Per-Screen IR — Stack, Overlay, Absolute, Leaf. Untuk cara batasan yang mengatur penggunaan string dideklarasikan, lihat Anatomi CONTEXT.md. Untuk alur kerja pembuatan Jetpack Compose end to end, lihat Jetpack Compose dari Figma. Siap membuat strings.json Anda sendiri? Gunakan aplikasi utama di figmascope.dev.