
Spanish: 
Hola, me llamo Leland Richardson.
Soy ingeniero de software en el equipo
del kit de herramientas de IU de Android.
Mi trabajo se centra en el compilador
y el entorno de ejecución de Compose.
A comienzos del año, convertimos
el código de Compose en código abierto
en Google I/O. Desde entonces,
lo hemos desarrollado de esa forma
como parte del proyecto
de código abierto de Android.
Como desarrolladores de apps,
aumentaron las expectativas
sobre el desarrollo de IU.
Hoy, no podemos crear una app
y cumplir con sus expectativas
sin una interfaz de usuario prolija,
animación y movimiento.
Todos estos elementos,
hace 10 años, no existían
como expectativas del usuario.
Creemos que Compose
es un kit de herramientas de IU moderno
que prepara a los desarrolladores

English: 
[MUSIC PLAYING]
LELAND RICHARDSON: Hello, my
name is Leland Richardson.
I'm a software engineer on
the Android UI Tool Kit team.
More specifically, I work on the
Compose Runtime and the Compose
Compiler.
So earlier this year,
we open-sourced Compose
at Google I/O. And
since then, we've
been developing it
out in the open,
as part of the Android
Open Source Project.
As app developers,
the expectations
around UI development
have really grown.
Today, we can't
really build an app
and meet the user's expectations
without having a polished user
interface, animation, motion.
All of these things
are things that
didn't exist 10 years ago as
an expectation from the user.
So Compose, we believe,
is a modern UI toolkit
that really sets
app developers up

Chinese: 
大家好 我是 Leland Richardson
是 Android UI Tool Kit 团队的软件工程师
说得再具体一点 我主要负责的是
Compose Runtime 和 Compose Compiler
今年早些时候 我们在 Google I/O 大会上
对 Compose 进行了开源
从那时起 我们就把它作为 Android 开源项目的一部分
一直没有停止对它的研发
如今 应用开发者们对 UI 开发的期待比以往高了很多
如今 如果没有精美的用户界面 动画 动效
我们就几乎无法满足用户的期待
而10年前 用户根本不会去期待这些东西
我们认为 Compose 是一个现代化的 UI 工具箱
足以帮助应用开发者们在这个新领域中取得成功

Portuguese: 
Olá, meu nome é Leland Richardson.
Sou engenheiro de software da equipe
do toolkit de IU do Android.
Mias especificamente, trabalho com o
ambiente de execução
e o compilador do Compose.
No começo deste ano, disponibilizamos
o código-fonte do Compose
no Google I/O. Desde então,
ele está sendo desenvolvido
em código aberto,
como parte do Android Open Source Project.
Como desenvolvedores de
apps, as expectativas
para o desenvolvimento de IUs
cresceram bastante.
Hoje, não podemos criar um app e
atender às expectativas do usuário
sem uma interface
refinada, animação, movimento.
Essas coisas não
existiam há 10 anos como
expectativa do usuário.
Acreditamos que o Compose
seja um toolkit de IU moderno
que realmente prepara os
desenvolvedores de apps

Indonesian: 
[SUARA MUSIK]
LELAND RICHARDSON: Halo, 
saya Leland Richardson.
Saya software engineer di
tim Android UI Tool Kit.
Secara khusus, saya mengerjakan
Compose Runtime dan
Compose Compiler.
Di awal tahun ini, kami
membuat open source Compose
di Google I/O.
Sejak itu, kami telah
mengembangkannya
secara terbuka,
sebagai bagian Android
Open Source Project.
Sebagai developer aplikasi,
harapan
seputar pengembangan UI
telah berkembang.
Kini kita tidak bisa
membuat aplikasi
dan memenuhi harapan pengguna
tanpa membuat antarmuka,
animasi, dan gerakan
yang bagus.
10 tahun lalu semua ini belum
menjadi harapan pengguna.
Compose adalah
toolkit UI modern
yang membantu
developer aplikasi

Japanese: 
こんにちは
Leland Richardsonです
Android UI Tool Kitチームで
ソフトウェア エンジニアをしています
もっと詳しく言うと
ComposeランタイムとComposeコンパイラを
担当しています
今年の初め Composeを
Google I/Oでオープンソースにしました
それ以来
Androidオープンソースプロジェクトの
一環として
オープンソースで開発しています
アプリの開発者として
UI 開発まわりは
すごく期待されるようになりました
今は アプリを作るときは
ユーザーインターフェース アニメーション
モーションなどがよっぽど
良くないと
ユーザーの期待に応えられません
10年前に
こんなことを期待するユーザーは
いませんでした
Composeは
こんな時代に
アプリ開発者の役に立つ
最新のUIツールキットだと

Korean: 
[음악 재생]
안녕하세요, 저는
릴런 리처드슨입니다
Android UI Tool Kit팀의
소프트웨어 엔지니어고요
그중에서 제가 작업하는 분야는 
Compose 런타임과
Compose 컴파일러입니다
올해 초 저희는 Compose를
Google I/O에서
오픈 소스화했는데요,
그 이후부터는
Compose를 공개적으로 개발해왔어요
Android Open Source 
Project의 일환으로요
앱 개발자들의 UI 개발에 대한
기대감은 상당히 커졌습니다
오늘날에는 아주 뛰어난 인터페이스나
애니메이션, 모션 등이 없이는 사용자들의
기대를 충족하는 앱을 만들 수가 없죠
이 모든 건 사실
10년 전에는 사용자가 앱에서
기대하던 것이 아니었어요
Compose는 이러한 새로운 환경에서
앱 개발자가 사용자의 기대에 부응하도록

English: 
for success in
this new landscape.
So today, what I
want to talk about
is, what problems specifically
does Compose solve?
What were the reasons behind
some of our design decisions?
And how can that help
you as an app developer?
Additionally, I want to
talk about the mental model
of Compose.
I want to talk about
how you should think
about code that you
write in Compose-- how
you should shape your APIs.
And then finally, I
want to talk about some
of the implementation details
and how Compose actually
works under the hood and explain
what's actually happening here.
So let's get started.
What problems does
Compose solve?
And really, to frame this,
what I want to talk about today
is separation of concerns.
Separation of concerns is a
well-known software design
principle.
It's one of the
fundamental things
that we learn as app developers.
And really, it's an
age-old kind of thing.

Japanese: 
思います
そこで 今日は
Composeで具体的に
どんな問題が解決できるのかを
話そうと思います
デザインをしたとき
何を考えたか
それがアプリ開発者に
どう役に立つかです
また Composeのメンタルモデル
についても
お話ししようと思います
Composeでコードを書くときに
どんなことを考えればよいか
どうやってAPIをつくるか
お話ししたいと思います
最後に
インプリメントするときの詳細や
Composeが実際に裏で
どのように動いているのか
お話ししようと思います
では 始めましょう
Composeを使えば
どんな問題が解決されるのでしょうか？
今日 本当にお話ししたいことは
関心の分離です
関心の分離というのは
よく知られたソフトウエア設計の
原則です
アプリの開発者は
基本的なこととして学ぶものです
古くからある考え方です

Spanish: 
para que tengan éxito en este nuevo panorama.
Hoy quiero hablar
sobre qué problemas resuelve Compose,
por qué tomamos ciertas decisiones
relacionadas con el diseño
y de qué forma eso puede ayudarlos
como desarrolladores de apps.
Además, quiero mencionar
el modelo mental de Compose.
Hablaré sobre cómo deben pensar
el código que escriben en Compose
y cómo dar forma a sus API.
Por último, hablaré sobre
los detalles de implementación
y cómo funciona Compose
en un nivel más profundo
para explicar los procesos.
Comencemos.
¿Qué problemas resuelve Compose?
Para enmarcar esto, hoy quiero hablar
sobre la separación de intereses.
Es un principio muy conocido
de diseño de software.
Es una de las cosas fundamentales
que aprendemos como desarrolladores de apps.
En realidad, no es nada nuevo.

Indonesian: 
untuk mencapai kesuksesan
dalam lanskap yang baru ini.
Hari ini, saya ingin
bicara tentang
masalah apa yang
bisa dipecahkan Compose?
Apa alasan di balik
keputusan desain kami?
Bagaimana ini membantu Anda
sebagai developer aplikasi?
Saya juga mau membahas
model mental dari Compose.
Saya mau membahas
cara berpikir tentang
tentang kode yang
Anda tulis di Compose --
cara Anda merancang API.
Terakhir, saya mau
membahas beberapa
detail implementasi
dan cara kerja Compose
di balik layar dan
menjelaskan prosesnya.
Mari kita mulai.
Apa masalah yang 
bisa dipecahkan Compose?
Untuk memfokuskannya,
saya ingin membahas
pemisahan masalah.
Pemisahan masalah
adalah prinsip desain software
yang sudah terkenal.
Ini salah satu
hal fundamental
yang dipelajari
developer aplikasi.
Ini sudah ada
sejak lama.

Portuguese: 
para o sucesso nesse novo cenário.
Hoje, quero falar sobre
problemas que o Compose resolve.
Quais foram as motivações para
algumas das nossas decisões de design?
Como isso pode ajudar vocês, como
desenvolvedores de apps?
Além disso, quero falar
sobre o modelo mental
do Compose.
Quero falar como vocês devem pensar
no código que criam
no Compose e como
dar forma às suas APIs.
Por fim, quero falar sobre alguns
dos detalhes de implementação e
como o Compose realmente
funciona internamente e explicar
o que de fato acontece aqui.
Vamos começar.
Que problemas o Compose resolve?
Hoje, quero falar sobre
a separação de conceitos.
Separação de conceitos é um
princípio famoso de design de software.
É uma das coisas fundamentais
que aprendemos como
desenvolvedores de apps.
É uma coisa antiga.

Chinese: 
今天我想讲的是 Compose 解决了哪些具体问题
我们作出设计决策的依据是什么
而这些信息又能如何帮助各位应用开发者
此外 我还想谈谈 Compose 的心理模型
我想谈谈你应该如何看待你在 Compose 中编写的代码
如何塑造你的 API
最后 我还想谈一些实现细节 
也就是解释给大家 Compose 内部的运行原理是怎样的
下面我们开始吧
Compose 解决了哪些问题？
这个问题的框架可以这样来描述：关注点分离 (separation of concerns)
关注点分离 是一个广为人知的软件设计理念
是各位应用开发者学习的基础知识之一
这东西很有年头了

Korean: 
도와주는 현대적인 UI 도구입니다
오늘 제가 말씀드릴 내용은
Compose가 정확히 어떤
문제를 해결해주는지
디자인 결정을 내릴 때
어떤 점을 고려했는지
또 이것이 어떻게 앱 개발자를
도와주는지에 대한 것입니다
그리고 Compose의
멘탈 모델에 대한 얘기도
해보려 합니다
Compose에서 작성하는
코드에 대해서,
API 틀을 잡는 방법에 대해서도
얘기하고 싶고요
그리고 끝으로는
구현 세부사항들과,
Compose가 실제로
내부에서 어떻게 작동하는지
그 내용에 대해 말씀드릴 겁니다
그럼 시작하죠
Compose는 어떤 문제를 해결해줄까요?
이 부분을 설명하기 위해서
관심사 분리에 대해 말해야겠네요
관심사 분리는 널리 알려진
소프트웨어 디자인 원칙입니다
앱 개발자라면 기본적으로
배우는 것이죠
그리고 아주 오래된 개념이에요

English: 
More than 40 years ago,
when separation of concerns
was originally postulated,
it was actually
framed in terms of
two other words--
coupling and cohesion.
And so what I want
to do today is
I want to talk about separation
of concerns in terms of this,
because I think it's a
little bit more concrete
and can help us understand
exactly what we're
talking about.
So abstractly,
when we write code,
we think of our application
in terms of modules.
And we might think of our module
in terms of multiple units.
So our application has
several of these modules.
And between them, we can
think of these dependencies
as coupling.
Basically, there's ways in
which parts of one module
influence the other.
And one way to
think of this is--
if I make a change to
some code somewhere,
how many other
changes to other files
am I going to have to make?
And that's coupling.
And in general,
what we want to do
is we want to reduce
coupling as much as possible.
And sometimes, coupling
is actually implicit.

Chinese: 
40多年前 关注点分离 这个理念刚刚提出的时候
其实描述它的语言是这两个词：耦合与内聚
所以 我今天就想从这个角度谈谈关注点分离
因为我觉得 这是一个更加坚实的概念
有助于我们理解今天的演讲内容
抽象地讲 当我们编写代码的时候
我们是把应用当作一个个的模块来考虑的
同样 我们也会把模块当作一个个的单元来考虑
我们的应用内含多个这样的模块
我们可以把模块之间的依赖当作耦合
也就是一个模块影响另一个模块的方式
换个说法 如果我更改了某处的代码
那么我还要对其他文件进行多少改动？
这就是耦合
大体上讲 我们想做的就是 尽量减少耦合
有时 耦合现象并不容易发现

Indonesian: 
Lebih 40 tahun lalu,
saat pemisahan masalah
pertama dikemukakan,
ini sebenarnya
dilihat menggunakan
dua kata lainnya --
coupling dan kohesi.
Hari ini saya ingin
membahas pemisahan masalah
dengan dua konsep ini
karena lebih konkret
dan bisa membantu kita
memahami topik
yang dibicarakan.
Secara abstrak, saat
menulis kode,
kita membayangkan aplikasi
sebagai modul.
Dan modul dibayangkan
sebagai sejumlah unit.
Jadi, aplikasi punya
beberapa modul seperti ini.
Di antara modul, kita
membayangkan dependensi
sebagai coupling.
Pada dasarnya, bagian dari
sebuah modul
memengaruhi bagian lainnya.
Satu cara memahaminya
adalah --
jika saya mengubah kode
di suatu bagian,
berapa banyak perubahan
yang harus dibuat pada file lain?
Itu coupling.
Secara umum,
kita ingin
mengurangi coupling
sebanyak mungkin.
Terkadang,
coupling tidak tampak jelas.

Korean: 
40년도 더 전에 관심사의 분리가
처음 대두되었을 때
두 단어로 설명되었는데
바로 결합도와 응집도입니다
따라서 오늘은
이 두 가지의 관점에서
관심사의 분리를 설명할게요
그래야 좀 더 명확하고
오늘의 주제를 이해하기도
더 쉬워질 겁니다
추상적으로 말해서,
우리는 코드를 쓸 때
모듈을 염두에 두고 앱을 만듭니다
그리고 모듈은 다수의
유닛으로 구성되죠
따라서 앱에는 여러 모듈이 들어있고
우리는 이 모듈 간의 의존도를
결합도라고 부릅니다
기본적으로 한 모듈의 어떤 부분이
다른 모듈에 영향을 주는
방법들이 있어요
이렇게 생각할 수 있는데요
어떤 코드에 변화를 주면
다른 파일들에 얼마나
영향을 주게 될까?
이게 결합도입니다
일반적으로
결합도는 가능한 한 낮아야 하죠
가끔은 결합도가 드러나지 않기도 합니다

Spanish: 
Hace más de 40 años,
cuando la separación de intereses
se planteó por primera vez,
se formuló en términos de otras dos palabras,
cohesión y acoplamiento.
Lo que quiero hacer hoy
es hablar en ese marco
sobre la separación de intereses
porque creo que es más concreto
y nos ayudará a entender exactamente
a qué nos referimos.
De forma abstracta, al escribir código,
pensamos en la aplicación
en términos de módulos.
Y pensamos los módulos
en términos de varias unidades.
Nuestra aplicación tiene
muchos de estos módulos.
Entre ellos, podemos pensar
en estas dependencias
como acoplamiento.
Básicamente, hay formas en las que un módulo
influencia al otro.
Una manera de pensar esto
es imaginar que, si hago un cambio
en alguna parte del código,
cuántos cambios más
tendré que hacer en otros archivos.
Es eso.
En general, lo que queremos
es reducir el acoplamiento
lo más que podamos.
A veces, está implícito.

Japanese: 
40年以上前に
関心の分離がはじめて
言われ始めたときは
実際は
別の2つの言葉が
使われていました
結合度(coupling)と凝集度(cohesion)です
そこで
今日私がやりたいことは
この観点から 関心の分離について
お話しすることです
その理由は
少し具体的な話ができるし
話が理解しやすいと
思うからです
抽象的に言うと
コードを書くとき 私たちは
モジュールを意識して
アプリケーションを考えます
モジュールは
たくさんのユニットの集まりとして考えます
したがって アプリケーションは
これらモジュールが何個か集まったものです
モジュール間の相互依存関係が
結合度です
基本的には
一つのモジュールの部分が
他に影響することがあります
どういうことかと言うと
どこかコードを変更すると
別のファイルで修正しなければ
ならない箇所が
どのくらいあるか？ということです
これが結合度です
一般的には
どうしたいかと言うと
結合度をできるだけ
減らしたいわけです
結合は表に出ないことも
あります

Portuguese: 
Há mais de 40 anos, quando
a separação de conceitos
foi concebida, ela foi definida
em termos
de duas outras palavras:
acoplamento e coesão.
Hoje, gostaria de
conversar sobre separação
de conceitos com base nisso,
porque acho que é um
pouco mais concreto
e pode ajudar a entender
exatamente o que estamos falando.
De uma forma abstrata,
quando criamos um código,
pensamos no nosso app
em termos de módulos.
Podemos pensar no nosso módulo
como várias unidades.
Nosso app tem vários desses módulos.
Entre eles, podemos pensar
nessas dependências
como um acoplamento.
Basicamente, há maneiras em que
partes de um módulo
influenciam outras.
Um maneira de pensar isso é...
se eu faço uma mudança em
alguma parte de um código,
quantas outras mudanças
nos arquivos
terei que fazer?
Isso é acoplamento.
Geralmente, o ideal
é reduzir ao máximo o acoplamento.
Às vezes, o acoplamento é
realmente implícito.

Portuguese: 
Contamos com uma dependência
ou com algo que não esteja muito claro,
mas alguma coisa falha
devido a uma mudança
que acontece em algum outro lugar.
Por outro lado, temos a coesão.
Coesão tem a ver com a forma
como as unidades dentro de um
certo módulo pertencem umas às outras.
Elas se relacionam.
Em geral, a coesão é vista como algo bom.
Um modo de pensar é
que separação de conceitos
é agrupar o máximo
de códigos relacionados
para que nosso código possa
ser mantido ao longo do tempo
e dimensionado à medida
que nosso app cresce.
Pensando nisso em termos
de algo mais familiar para vocês,
vamos falar de uma situação comum.
Temos um ViewModel.
Aqui à esquerda.
E temos também um layout XML.
O ViewModel fornece
dados a este layout.
Temos uma visualização que precisa
ser preenchida com algo.
Acontece que há muitas
dependências ocultas aqui.

Chinese: 
有些我们离不开的依赖或者其他东西 本身并不是很清楚
但是还是因为其他地方所做的更改而出了问题
另一个问题是 内聚
内聚的确切含义就是 某个模块内部的多个单元
互相归属 彼此之间都有联系
我们通常认为内聚是好事
换句话说 关注点分离 这个理念的实质就是
尽可能地把相关的代码聚集在一起
让我们的代码可以长期保持可维护性 
并随着应用的增长而扩大
用大家熟悉的语言来讲一下
我们来看一个常见的情景
左侧这里是 ViewModel 
右侧这里是 XML 布局
由 ViewModel 向布局提供数据
这里有一个视图需要填充
其实 这里隐藏着很多的依赖

English: 
There's a dependency
that we're relying on
or something that we're relying
on that's not actually very
clear, but something
breaks because of a change
that happens somewhere else.
On the other hand,
we have cohesion.
And cohesion is really about
how the units inside of a given
module belong to one another.
They're related to one another.
And cohesion is generally
seen as a good thing.
And so one way to think of this
is that separation and concerns
is really all about
grouping as much related
code together as possible
so that our code can
be maintainable over
time and really scale
as our application grows.
So framing this in terms of
something more familiar to you,
let's talk about a kind
of common situation.
We have a view model.
Here on the left.
And then we also
have an XML layout.
And the view model is really
providing data to this layout.
We have a view that we need
to populate with something.
And it turns out,
there's actually a lot
of dependencies hidden here.

Japanese: 
気がつかないところで
依存性がある場合もあって
どこか違う場所の変更で
動かなくなることもあります
一方で
凝集もあります
凝集は モジュール内で
ユニットがお互いに
どう関係しあうかについて
のものです
ユニットはお互いに
関係しあいます
凝集は通常
良いものと考えられています
つまり
関心の分離とは
実は 関係のあるコードを
できるだけまとめて
アプリが発展して
だんだんコードの規模が
大きくなっても
メンテナンスしやすく
することなのです
もっと分かりやすいことで
説明しましょう
よくある状況で
ビューモデルがあります
この左側です
XMLレイアウトもあります
ビューモデルはこのレイアウトに
データを渡します
ビューモデルに何か
入れなければなりません
ここには
いろいろな依存性が
隠されていることが
わかります

Indonesian: 
Ada dependensi atau sesuatu
yang kita andalkan
tapi tidak begitu jelas,
tapi saat kita mengubahnya
ada bagian lain yang terganggu.
Di sisi lain, ada kohesi.
Kohesi adalah bagaimana
unit-unit dalam modul tertentu
saling terkait.
Unit-unit tersebut
saling terhubung.
Kohesi biasanya
dianggap hal yang baik.
Jadi, kita bisa memahami
pemisahan masalah
sebagai cara untuk
menggabungkan kode terkait
sebanyak-banyaknya
agar kode bisa
dipelihara seiring waktu
dan diskalakan
seiring dengan
perkembangan aplikasi.
Agar Anda lebih mudah dalam
memahami hal ini,
mari membahas 
situasi umum.
Ada model tampilan
di sebelah kiri.
Juga ada XML tata letak.
Model tampilan memasok data
ke tata letak ini.
Ada tampilan yang 
perlu diisi informasi.
Dan ternyata,
ada banyak
dependensi yang
tersembunyi di sini.

Spanish: 
Hay una dependencia que necesitamos
o algo más de lo que dependemos
y que no está muy claro,
pero que falla debido a un cambio
que se hizo en otra parte.
Por otro lado, está la cohesión.
Se trata de cómo las unidades
dentro de un módulo específico
pertenecen una a la otra.
Están todas relacionadas.
En general, la cohesión
se considera algo bueno.
Una manera de verlo
es que la separación de intereses
se trata de agrupar la mayor cantidad
de código relacionado posible
para poder mantenerlo y ampliarlo
a medida que crece nuestra app.
Para plantearlo en términos más familiares,
hablemos sobre un tipo de situación común.
Tenemos un modelo de vista
en el lado izquierdo,
y también un diseño XML.
El modelo de vista
brinda datos a este diseño.
Tenemos una vista que debemos
completar de alguna forma.
Hay muchas dependencias ocultas aquí.

Korean: 
우리가 생각하는 어떤 의존도가
확실히 보이지 않는데도
한 부분에서 변화가 발생했을 때
또 다른 한쪽이 무너진다거나 하는 거죠
한편 응집도라는 것도 있는데요
이는 어떤 모듈 안의 유닛들이
어떻게 서로에게 속해있느냐 하는 겁니다
이들은 서로 연관되어 있죠
응집도는 보통 좋은 것으로 여겨져요
그럼 관심사의 분리는 사실 관련된 코드를
가능한 한 같은 그룹으로 분류하는 것인데
그러면 시간이 지나도 코드를
유지 관리할 수 있고
또 앱의 크기가 커져도
맞춰서 조정할 수 있게 되죠
여러분에게 좀 더 친숙할 만한
일반적인 상황을 들어 설명해볼게요
여기 뷰모델이 있습니다
왼쪽에요
그리고 XML 레이아웃도 있고요
뷰모델이 이 레이아웃으로
데이터를 보내주므로
뭔가를 표시해줘야 하는 뷰가 있는 거죠
알고보니, 여기에는 눈에 보이지 않는
의존도가 많이 있었습니다

English: 
There's a lot of
coupling between the view
model and the layout.
And one of the more familiar
ways that you can see this
is through findViewByID.
What we're doing is we're trying
to understand what the XML
layout is actually
defining, finding
specific elements into it,
and piping data through it.
We might even, more
subtly, depend on things
that happen in layout XML.
We actually might rely
on a certain structure
that was defined there.
And so we have to keep
these things in sync
as our application grows.
And really, our
application can grow a lot.
These layout XMLs
get very, very large.
We have very large
complicated UIs.
And they're dynamic too.
So sometimes, one element
might leave the view hierarchy
at runtime but not
statically, and this
leads to null reference
exceptions and things
like that.
So one of the
fundamental things here
is that we have a view
model defined in Kotlin.

Spanish: 
Hay un acoplamiento alto
entre el modelo de vista y el diseño.
Una de las formas más conocidas de ver esto
es mediante findViewByID.
Lo que queremos es intentar comprender
qué define en realidad el diseño XML
descubriendo sus elementos específicos
y canalizando datos a través de él.
También podemos,
más sutilmente, depender de cosas
que ocurren en el diseño XML.
Tal vez necesitemos cierta estructura
que se definió ahí.
Debemos mantener esos elementos sincronizados
a medida que crece nuestra app.
De hecho, puede crecer bastante.
Estos diseños XML se agrandan mucho.
Tenemos IU extensas y complicadas
que también son dinámicas.
A veces, un elemento puede
dejar la jerarquía de vistas
durante el tiempo de ejecución,
pero no estáticamente.
Eso genera excepciones
de referencias nulas y errores así.
Uno de los puntos fundamentales aquí
es que el modelo de vista
está definido en Kotlin

Indonesian: 
Ada banyak coupling antara
model tampilan dan tata letak.
Salah satu cara yang lebih mudah
untuk menemukannya adalah
melalui findViewByID.
Kita mencoba memahami
apa yang ditentukan
oleh XML tata letak,
menemukan elemen spesifik untuk itu,
dan menyalurkan data.
Kita mungkin sedikit
lebih mengandalkan
proses yang terjadi di
XML tata letak.
Kita mungkin mengandalkan
struktur tertentu di sana.
Kita harus 
menyinkronkan semua
seiring perkembangan aplikasi.
Aplikasi bisa
berkembang pesat.
XML tata letak ini
menjadi sangat besar.
UI-nya jadi sangat besar
dan rumit.
Dan juga dinamis.
Sebuah elemen
mungkin keluar dari
hierarki tampilan saat proses
berjalan, tapi tidak statis.
Ini menimbulkan 
pengecualian referensi nihil,
atau semacamnya.
Salah satu hal mendasar
di sini adalah
ada model tampilan yang
dibentuk dalam Kotlin,

Portuguese: 
Há muito acoplamento entre
ViewModel e o layout.
Umas das maneiras
mais familiares de notar isso
é por meio de findViewById.
O que estamos fazendo é tentar
entender o que o layout XML
está definindo, descobrindo
elementos específicos nele e
enviando dados por meio dele.
Podemos até, mais sutilmente,
depender de coisas
que acontecem no layout XML.
Podemos contar com uma
determinada estrutura
que tenha sido definida lá.
E temos que manter essas
coisas sincronizadas
à medida que nosso app cresce.
Nosso app pode crescer bastante.
Esses layouts XML são muito grandes.
Temos IUs complicadas e muito grandes.
E temos a questão da dinâmica.
Às vezes, um elemento pode
deixar a hierarquia de visualização
no ambiente de execução, mas não
estaticamente.
Isso gera exceções
de referências nulas e coisas assim.
Uma das principais questões aqui é que
temos um ViewModel definido em Kotlin.

Korean: 
뷰모델과 레이아웃 사이에
결합도가 많이 있는 거죠
이걸 확인할 수 있는 더 익숙한 방법은
findViewByID예요
우리는 XML 레이아웃이
무엇을 정의하는지 이해하고
관련된 특정 요소를 찾고 또
데이터를 주입하려 합니다
심지어는 은근히 
레이아웃 XML에서 벌어지는
일들에 의존하기도 하고요
또 여기서 정의된 특정 구조에
의존할 수도 있죠
따라서 우리는 앱이 커져감에 따라
이들의 싱크가 맞도록
유지해야 합니다
앱은 꽤 커질 수 있으니
이 레이아웃 XML도 
엄청나게 커질 수 있는데요
그럼 몹시 크고 복잡한 UI가 생기고
역동적이기도 합니다
그러니까 가끔은 하나의 요소가 런타임에
비정적으로 뷰 계층 구조를 떠나면
null reference 
exception이나 그 비슷한
결과로 이어지기도 합니다
또 다른 기본적인 내용으로는
뷰모델은 Kotlin으로
정의되었다는 겁니다

Japanese: 
ビューモデルと
レイアウトの間には
いろいろな結合が
あります
これがわかるよく知られた方法に
findViewByIDがあります
何をしているかと言うと
XMLレイアウトが
何を定義しているか
特定の要素を入れているか
どのデータをパイプしているかを
理解しようとしています
もっと細かいことを言えば
レイアウトXMLで起こっていることに
依存していることもあります
そこで定義されている
構造に依存していることもあります
したがって
アプリケーションが成長するにつれて
これらを同期させる必要が
あります
アプリケーションは 実際
大きく成長するものです
レイアウトXMLは
ものすごく大きくなります
とても複雑なUIを持つようになります
さらに ダイナミックです
時には あるエレメントが
静的でなくランタイム中に
ビューの階層を越えることもあり
すると null referecne exceptionなどが
起こったりします
基本的なこととして
Kotlinでビューモデルが
定義されています

Chinese: 
ViewModel 和布局之间存在着很多的耦合
大家都熟悉的一个查看办法就是 findViewById
我们在做的事情 是理解 XML
如何定义元素 找到特定元素 并向其中添加数据
它可能还暗中依赖布局 XML 中的一些东西
我们可能会依靠在那里被定义的一些特定结构
所以 随着应用的增长 我们必须让这些东西维持同步
而且 我们的应用增长的空间是很大的
布局 XML 可能会变得非常大
UI 也可能会变得很大 很复杂
而且它们是动态的
有时 一个元素可能会在运行环境中用非静态的方式离开视图层级
从而导致空引用异常 等等诸如此类的问题
这里的基本要点之一在于 我们在 Kotlin 中定义了 ViewModel

Spanish: 
y el XML de diseño está definido en XML.
Debido a esta diferencia de lenguaje,
hay una línea forzada de separación,
incluso aunque
el modelo de vista y el diseño XML
a veces pueden estar
íntimamente relacionados.
En otras palabras, están muy acoplados.
Entonces, ¿qué ocurre
si definimos el diseño, la estructura
de la IU, en el mismo lenguaje?
¿Qué sucede si elegimos Kotlin?
Ahora, como usamos el mismo lenguaje,
algunas de estas dependencias
pueden empezar a ser más explícitas.
También podemos refactorizar parte del código
y mover elementos al sitio
donde pertenecen para reducir
un poco el acoplamiento
y aumentar la cohesión.
Quizás algunos de ustedes
tengan serias dudas sobre lo que digo.
¿Estoy diciendo que mezclemos
la lógica con nuestra IU?
Bien, veamos.

Portuguese: 
Nosso layout é definido em XML.
E por causa dessa diferença em linguagem,
há uma linha forçada de separação,
mesmo que ViewModel e o XML do layout
estejam relacionados.
Em outras palavras, eles têm
um acoplamento forte.
E se começarmos a definir
o layout, a estrutura
da nossa IU na mesma linguagem?
E se escolhermos Kotlin?
Como estamos na mesma linguagem,
algumas dessas dependências podem
começar a ficar mais explícitas.
E também podemos começar a refatorar
alguns códigos e mover
as coisas para o lugar a que elas
pertencem e, assim, reduzir
um pouco esse acoplamento e
aumentar um pouco a coesão.
Vocês podem estar pensando
no que estou dizendo aqui e
estar um pouco céticos.
Estou dizendo que podemos
combinar lógica na IU?

Chinese: 
而我们的布局 XML 则使用 XML 进行定义
因为这些语言上的差异
即使 ViewModel 和 布局 XML 有时彼此关系颇为紧密
换句话说 它们是紧密耦合的
也会产生一条强制性的分隔线
那么 如果我们开始使用同一种语言来定义
布局 和 UI 结构 结果会如何呢？
如果我们选择 Kotlin 会怎样？
因为我们使用的是同一种语言
部分依赖可能会变得更加明确
此外 我们还可以开始重构部分代码
并将一些东西移动到它们本来归属的地方
从而减少耦合 增加内聚
现在 可能有的人会想 我讲的这些东西真的有用吗
我是不是在建议大家把逻辑和 UI 混合在一起？
是这样的

Japanese: 
一方で レイアウトXMLは
XMLで定義されています
したがって
使う言語が違うので
無理やり分離が
起こってしまいます
ビューモデルとレイアウトXMLが
深く関係している場合もです
言い換えると 結合が深い場合もです
もし 同じ言語で
レイアウトやUIの構造を
定義できたら
どうなるでしょうか？
Kotlinを使ったら
どうでしょうか？
同じ言語なので
このような依存性のうち いくつかは
わかりやすくなると思います
さらに コードを少し
書き換えて 整理すれば
結合度を減らせて
凝集度を高められます
こう言うと
本当にできるかどうか
疑問に思う人が
いるかもしれません
ロジックをUIと一緒にすべきだと
言うことでしょうか？

Korean: 
레이아웃 XML은 XML로
정의되었고요
이렇듯 사용언어가 다르기 때문에
강제로 구분선이 생기게 됩니다
뷰모델과 레이아웃 XML은 아주 긴밀하게
연관될 때가 있는데도 불구하고 말이죠
다시 말해 결합도가 높다는 거예요
그럼 레이아웃, 그러니까 UI 구조를
같은 언어로 정의하면 어떨까요?
Kotlin을 선택한다면요?
이제 언어가 같기 때문에
의존도가 더 명백히 드러날 수 있죠
나아가서 코드를 리팩터할 수도 있고
요소들을 자신이 속하는
제 자리로 옮겨서
결합도를 낮추고
응집도를 높일 수 있습니다
어떤 분들은 아마도
저의 이런 설명에 의구심을
가지실지도 모르겠는데요
로직을 UI와 혼합한다는 말인가?
하시면서요

Indonesian: 
sementara XML tata letak
dibentuk dalam XML.
Karena perbedaan bahasa ini,
ada garis pemisah
yang dipaksakan di sini
meski model tampilan
dan XML tata letak
kadang bisa terkait
sangat erat.
Dengan kata lain,
coupling di antara keduanya sangat erat.
Bagaimana kalau kita
membentuk tata letak,
struktur UI, dalam
bahasa yang sama?
Bagaimana jika
kita memilih Kotlin?
Karena menggunakan
bahasa yang sama,
beberapa dependensi
mungkin terlihat lebih jelas.
Kita bisa melakukan
refactoring kode
dan memindahkan berbagai hal
ke tempat seharusnya dan
mengurangi coupling,
meningkatkan kohesi.
Anda mungkin
memikirkan perkataan saya
dan merasa agak skeptis.
Apa kita harus mencampur
Logika dengan UI?

English: 
And then our layout
XML is defined in XML.
And so because of this
difference in language,
there's actually a
forced line of separation
here, even though the view
model and the layout XML
can sometimes be very,
very intimately related.
In other words, they're
very tightly coupled.
So what if we started to define
the layout, the structure
of our UI, in the same language?
What if we chose Kotlin?
Now because we're in
the same language,
some of these dependencies might
start to become more explicit.
And even more, we can start
to refactor some code and move
things over to where they
belong and actually reduce
some of that coupling and
increase some of the cohesion.
Now, some of you
might be thinking
about what I'm saying here
and be a little bit skeptical.
Am I saying that we should
mix Logic with our UI?

Korean: 
제 말은 이런 뜻입니다
프레임워크 제작자로서 저희는 
여러분의 관심사를
완벽하게 분리해드리지는 못합니다
그건 오직 여러분만이 할 수 있어요
여러분의 UI에서 떨어질 수 없는
로직이 있을 겁니다
UI의 일부니까요
저희가 그걸 막을 수는 없지만
관심사를 더 쉽게 분리할 수 있는
도구를 제공해드릴 수는 있습니다
그 도구가 바로 Composable
함수라는 것을 여러분께
보여드리려는 것입니다
이 함수는 별 어려움 없이
들릴 거예요
Composable이라는 말을 빼면
이건 사실 그냥 함수죠
여러분은 아마 아주 오랫동안
코드에서 관심사를 분리하기 위해
함수를 사용해오셨을 겁니다
그러면서 여러분이 습득해오신
믿을만하고, 유지보수 가능하고 또 깨끗한
코드를 만들고 리팩터링하는 그 스킬을

Portuguese: 
A questão é a seguinte.
Como criadores de frameworks,
não conseguimos separar
perfeitamente seus conceitos para vocês.
Isso é algo que só vocês podem fazer.
Vocês têm partes da sua lógica
que não farão o escape da IU.
São partes da sua IU.
E não temos como evitar isso.
Mas podemos fornecer ferramentas
para facilitar a separação.
Então, estou aqui para tentar
convencer vocês
de que essa ferramenta é
uma função combinável.
Na verdade, isso pode soar um pouco
menos controverso do que é de fato.
Se desconsiderarmos a parte "combinável",
é apenas uma função.
E uma função é algo que
vocês têm usado, provavelmente
há algum tempo, para separar
conceitos em outros lugares
do seu código.
As habilidades que vocês adquiriram para
fazer esse tipo de refatoração e criação
de código confiável, limpo
e de fácil manutenção...

Chinese: 
作为框架作者 我们其实无法完美地替大家完成关注点分离
这件事情其实只有你自己才能做到
有些逻辑是无法脱离你的 UI 的
它们是你的 UI 的一部分
这是我们无法避免的问题
但是 我们可以为大家提供工具
简化这个分离的过程
今天我想试着告诉大家的是
@Composable 方法就是最合适的工具
其实这个东西的争议性要比想象中的小
如果你拿掉它里面的 Composable 部分
剩下的就只是方法而已
而大家使用各种方法 在代码内部分离关注点也有很久了
大家已经拥有的那些技能
比如重构 编写可靠 易于维护 干净的代码

English: 
Well, here's the thing.
As framework authors, we
actually can't perfectly
separate your concerns for you.
This is something that
only, really, you can do.
You have parts of your logic
that will not escape the UI.
They are part of your UI.
And we actually
can't prevent that.
But what we can do is
provide you with tools
to make that separation easier.
And so I'm here today
to try and convince you
that that tools is a
Composable function.
And actually, this
might sound a little bit
less controversial than it is.
If you take away the Composable
part, it's just a function.
And a function is something
that you've been using, probably
for a long time, to
separate concerns elsewhere
in your code.
And the skills that
you have acquired to
do that type of
refactoring and writing
reliable, maintainable,
clean code--

Indonesian: 
Masalahnya begini.
Sebagai pembuat framework,
kami tidak bisa
memisahkan masalah untuk Anda.
Hanya Anda yang
bisa melakukannya.
Ada bagian logika yang
tidak bisa keluar dari UI.
Ia juga bagian dari UI.
Kami tidak bisa
mencegahnya.
Namun, kami bisa
menyediakan alat
untuk memudahkan
pemisahan itu.
Di sini saya mencoba
meyakinkan Anda
bahwa alat itu adalah
fungsi Composable.
Ini mungkin terdengar
lebih tidak kontroversial
dari sebenarnya.
Jika Composable dihapus,
ini hanya berupa fungsi.
Anda telah lama
menggunakan fungsi
untuk memisahkan
masalah di mana pun
dalam kode.
Kemampuan yang 
telah Anda peroleh
untuk melakukan refactoring
dan menulis
kode bersih yang andal
dan mudah dipelihara --

Japanese: 
こう言うことです
フレームワークの作成者としては
皆さんの懸念事項を
完全に分離することは
できません
これは 皆さんにしか
できないことです
ロジックの中には
UIに無関係ではいられないものもあります
UIの一部です
どうすることもできません
私たちができるのは
その分離が簡単になるような
ツールを提供することです
そこで 私の今日の役目は
皆さんに そのようなツールとして
Composable関数を紹介して
使ってもらうことです
実は 言うほど
難しいことでは
ないようです
Composableな部分を除けば
関数の一つにすぎません
関数は 皆さんも
昔から自分のコードで
やりたいことを分離するのに
使ってきたものだと思います
皆さんがこれまで
自分のコードを
整理したり 
信頼性の高めたり
メンテしやすくしたり
きれいにしたりするのに

Spanish: 
Como autores de marcos de trabajo,
no podemos separar los intereses
a la perfección por ustedes.
Solo ustedes pueden hacer eso.
Hay partes de su lógica
que no se pueden quitar de la IU.
Están unidas,
y nosotros no podemos evitarlo.
Pero sí podemos brindarles las herramientas
para facilitar la separación.
Yo vine aquí hoy para intentar convencerlos
de que esa herramienta
es una función componible.
Esto puede sonar menos controversial
de lo que es.
Si quitamos "componible",
es solo una función.
Y las funciones son algo
que seguramente vienen usando
desde hace mucho tiempo
para separar intereses
en otras partes del código.
Las habilidades que adquirieron
para que esa refactorización y escritura
sea un código confiable
y prolijo que se puede mantener

Portuguese: 
essas mesmas habilidades se aplicam
a funções combináveis.
Hoje, quero falar um
pouco sobre a anatomia
de uma função combinável
e tentar ajudar vocês a entender como
pensar sobre essas questões.
Aqui temos um exemplo de
uma função combinável.
Ela recebe dados como parâmetros.
Temos esta classe AppData.
Pensamos nos parâmetros que
entram na função combinável
como dados imutáveis.
A função combinável
não deve mudar.
Devemos apenas tratá-la como uma
função de transformação
desses dados.
Por causa disso,
podemos usar qualquer código
que quisermos, em Kotlin, para pegar
esses dados, criá-los, direcioná-los.
Usá-los e descrever
a hierarquia nesta função.
Isso significa que chamamos
outras funções combináveis.
Essas invocações representam
a IU na nossa hierarquia.

Japanese: 
身につけてきたスキルをそのまま
Composable関数にも応用できます
そこで 今日は
Composable関数について
その中身について
お話しして
皆さんに理解してもらおうと
思います
Composable関数の例です
データをパラメータとして受取ります
このAppdataのクラスが
入ってきます
Composable関数に入ってくる
パラメータは
可変(mutable)データだと
考えがちですが
Composable関数では
このデータの値を
変更はできません
そのデータの
変換関数として
取り扱わなければなりません
そのため Kotlin内では
どんなコードの中でも
そのデータを受け取り 生成し
データを取出して 利用し
この関数の中のここで
階層を表現できます
つまり
ほかのComposable関数を呼びます
この呼び出しが
階層のUIを表します

Korean: 
Composable 함수에도
적용하실 수 있습니다
이 Composable 함수의 구조를
조금 뜯어보고 또 여러분이
이에 대해 더 잘 이해하실 수 있도록
도와드리고자 합니다
이건 Composable 함수의 
예시입니다
매개변수로 데이터를 수신하죠
앱 데이터 클래스가 들어옵니다
우리는 Composable 함수로
들어온 매개변수들을
변환 데이터로 취급하고 싶습니다
사실 Composable 함수가
변환해서는 안 되는 데이터죠
우리는 그냥 이것을 해당 데이터의
변환 함수로 취급해야 합니다
이 때문에 우리는 Kotlin에서 데이터를
얻거나 만들거나 끌어오게 하기 위해 
어떤 코드든 쓸 수 있고
그 코드로 이 함수에 있는 계층 구조를
설명할 수 있어요
즉, 다른 Composable 함수를
불러올 수 있습니다
그러한 호출이 계층구조에서
UI를 나타낼 수 있는 거죠

Chinese: 
完全可以适用于 Composable 方法
今天 我想为大家分析一下 Composable 方法
帮助大家理解这个东西
这里是一个 Composable 方法的例子
它会把数据作为参数进行接收
这里收入了一些 AppData 类
我们想把这个被收入到 Composable 功能中的参数
看作可变数据
Composable 功能不应该更改这种数据
我们应该将其看作那个数据的转换方法
因此 我们可以使用任何 Kotlin 代码
使用这些数据创建 deriveData
再用它来在这个方法中描述我们的层级
这意味着 我们要调用其他 Composable 方法
这些调用代表我们层级中的 UI

English: 
those same skills apply
to Composable functions.
So today, I want to
talk about the anatomy
of a Composable
function a little bit
and try to help
you understand how
to think about these things.
So here's an example of
a Composable function.
And it receives
data as parameters.
We have this app data
class that comes in.
And we want to think
of the parameters that
come into a Composable function,
really, as a mutable data.
It's data that-- the
Composable function really
shouldn't be changing.
We should just be treating
it as a transform function
of that data.
Now because of that,
we can use any code
that we want to, in Kotlin,
to take that data, create,
drive data from it and then use
that and describe our hierarchy
here in this function.
And this means that we call
other Composable functions.
And those invocations represent
the UI in our hierarchy.

Spanish: 
son las mismas que se aplican
a las funciones componibles.
Hoy quiero hablar sobre la anatomía
de las funciones componibles
para intentar ayudarlos a entender
cómo deben pensarlas.
Aquí tenemos un ejemplo
de función componible.
Recibe datos como parámetros.
Tenemos esta clase de datos de app.
Queremos pensar en los parámetros
que entran en una función componible,
como datos inmutables.
Son datos que la función componible
no debería modificar.
Deberíamos considerarla
una función de transformación
de esos datos.
Debido a eso, podemos usar cualquier código
que queramos, en Kotlin,
para tomar esos datos,
crear datos derivados a partir de ellos,
y luego usarlos y describir nuestra jerarquía
aquí en esta función.
Quiere decir que llamamos
a otras funciones componibles.
Esas llamadas representan
la IU en nuestra jerarquía.

Indonesian: 
juga berlaku untuk
fungsi Composable.
Hari ini saya mau
membahas anatomi
fungsi Composable
dan membantu Anda
memahami cara
memikirkannya.
Berikut contoh
fungsi Composable.
Fungsi ini menerima data
sebagai parameter.
Ada class data aplikasi
yang masuk.
Mari kita anggap parameter
yang masuk ke
fungsi Composable
sebagai data yang bisa berubah.
Ini data yang -- tidak boleh
diubah oleh fungsi Composable.
Perlakukan fungsi ini sebagai
fungsi transformasi
untuk data tersebut.
Karena itu, kita bisa
menggunakan kode apa pun
yang kita mau di Kotlin,
untuk mengambil,
membuat, dan menyalurkan data dari sana,
lalu menggunakannya untuk mendeskripsikan
hierarki di fungsi ini.
Artinya, kita memanggil
fungsi Composable lain.
Pemanggilan itu 
mewakili UI dalam hierarki kita.

Korean: 
또한 Kotlin에 있는 모든
언어 레벨의 프리미티브를
사용해서 동적으로 작업할 수도 있어요
따라서 if 문장이나 제어 흐름에서 for loop
등을 사용할 수 있고
UI에 들어 있는 더 복잡한 로직도
처리할 수 있죠
그리고 끝으로 저희가 Kotlin의
trailing lambda
syntax를 활용한다는 걸 말씀드립니다
여기 있는 Body는 composable
lambda를 매개변수로 가지는
Composable 함수입니다
이 결과로 계층이나 구조가
만들어지게 되는데요
따라서 Body는 여기 있는 항목들을
모두 포괄해주는 것이죠
'선언형'이라는 단어를 
들어보셨을 겁니다
유행어지만
중요한 단어이죠
무슨 의미인지 설명해 드릴게요
보통 선언형이라고 하면
명령형 프로그래밍의
반대말로 쓰곤 합니다
예를 통해 더 알아보도록 할까요
우리에게 메일이나 채팅 앱처럼

Chinese: 
此外 我们可以使用 Kotlin 中现有的语言级别原语
来实现动态处理
我们可以使用 if 语句 和 for 循环控制流
处理我们的 UI 所有的较为复杂的逻辑
最后 我想指出 我们正在利用 Kotlin 后面的 lambda 语法
这里的 Body 是 Composable 方法
它拥有一个以参数形式存在的 Composable lambda
它意味着某种层级或结构
Body 会封装这些成套的项目
大家可能听过我们提到过“声明式”这个概念
“声明式”是个热门词 不过也确实很重要
我想说明一下我们为什么这么说
通常 我们在谈到“声明式”的时候
是相对于“命令式”编程而言的
下面我们来通过举例进一步强化理解
如果我们有一个邮件或聊天应用 UI

Spanish: 
También podemos usar todos
los primitivos a nivel del lenguaje
que Kotlin ya tiene
para hacer cosas de forma dinámica.
Podemos usar instrucciones if
y bucles for para controlar el flujo
y manejar la lógica más compleja
que pueda tener nuestra IU.
Por último, quiero destacar
que aprovechamos la sintaxis
de lambda final de Kotlin.
Body es una función componible
que tiene una expresión lambda
componible como parámetro,
lo que al final implica
una jerarquía o estructura.
Aquí, Body es algo que une
este conjunto de elementos.
Tal vez hayan escuchado
la palabra "declarativa".
Es una palabra de moda,
pero es importante.
Quiero describir a qué nos referimos con eso.
En general, cuando decimos "declarativa",
es para marcar el contraste
con la programación imperativa.
Veamos un ejemplo para entender el concepto.
Supongamos que tenemos una IU,
como la de una app de correo o chat,

English: 
Also, we're able to use all of
the language level primitives
that Kotlin already has in
order to do things dynamically.
So we can if statements and
for loops for control flow
and dealing with the
more complicated logic
that our UI might have.
And then finally, I
want to point out here
that we're leveraging Kotlin's
trailing lambda syntax.
So Body here is a
composable function
that has a composable
lambda as a parameter.
And that ends up implying some
sort of hierarchy or structure.
And so Body is something that
wraps these set of items here.
So you've probably heard us
say the word "declarative."
"Declarative" is a buzzword.
But it's an important one.
And I want to describe
what we mean by that.
And usually, when we
talk about declarative,
we're talking about
it in contrast
to imperative programming.
So let's look at an example
to understand this more.
What if we had a UI, like a mail
or a chat application, where we

Indonesian: 
Kita bisa menggunakan semua
primitive pada tingkat bahasa
dalam Kotlin untuk
bekerja secara dinamis.
Gunakan pernyataan if
dan for loop untuk alur kontrol
dan menangani
logika yang lebih rumit
yang mungkin ada di UI.
Terakhir, saya mau
menunjukkan
pemanfaatan sintaks
trailing lambda di Kotlin.
Body ini adalah fungsi
Composable
dengan lambda composable
sebagai parameter.
Ini menyiratkan sebuah
hierarki atau struktur.
Body adalah pembungkus
semua set item yang ada di sini
Mungkin Anda pernah
mendengar "deklaratif".
"Deklaratif" adalah jargon.
Tapi kata ini penting
dan saya ingin
menjelaskan maksudnya.
Saat membahas
deklaratif,
kita membandingkannya
dengan
pemrograman imperatif.
Mari lihat contoh
untuh memahaminya.
Jika ada UI, seperti
aplikasi email atau chat,

Japanese: 
またこれを
ダイナミックに実現するために
Kotlinがすでに持っている言語レベルの
プリミティブがすべて使えます
制御フローに if文やforループを
使えますし
UIにもっと複雑なロジックが
あっても
対応できます
もう一つ最後に
言っておきたいのは
Kotlinのラムダ式を
用いています
このBodyはcomposableラムダを
パラメータとして持つ
composable関数です
そして なんらかの階層または構造が
あることを示しています
Bodyはこれらアイテムのセットを
ラップしています
「declarative(宣言的)」という言葉
を聞いたことがあると思います
「Declarative」は
バズワードになっていますが
重要な言葉です
ここで 私たちがどんな意味で使っているか
説明したいと思います
declarativeという言葉は通常
命令型プログラミングとの対比で
用いられています
もっとよくわかるように
例を使って説明します
メールやチャットアプリなどの
UIがあるとします

Portuguese: 
Além disso, podemos usar todos
os primitivos no nível da linguagem
que o Kotlin já tem para fazer
coisas dinamicamente.
Podemos usar instruções "if"
e loops "for" para controlar o fluxo
e lidar com a lógica mais complicada
que nossa IU possa ter.
Por fim, quero destacar que
estamos utilizando a sintaxe
do lambda à direita do Kotlin.
"Body" aqui é uma função combinável
que tem um lambda
combinável como parâmetro.
Isso gera algum tipo de
hierarquia ou estrutura.
Então, "Body" é algo que
une esse conjunto de itens aqui.
Vocês já devem ter ouvido
a palavra "declarativo".
"Declarativo" é um chavão,
mas é importante.
Quero descrever o que ela
significa para nós.
Quando falamos em "declarativo",
estamos fazendo uma
comparação com programação imperativa.
Vamos observar um exemplo
para entender isso melhor.
Imaginem que temos uma IU, um
app de e-mail ou chat, que

Indonesian: 
dengan ikon Pesan
Belum Dibaca.
Jika tidak ada pesan,
ditampilkan amplop kosong.
Jika ada sejumlah pesan,
ada kertas di dalam.
Mungkin kita mau
tampil keren.
Jika ada lebih dari
100 pesan,
muncul api dan
aksesori semacamnya.
Dengan antarmuka imperatif,
kita dapat menulis
fungsi update hitungan
seperti ini, untuk
mendapat hitungan baru.
Kita memeriksa dan
mencari tahu
cara merancang UI ini
untuk mencerminkan
state yang tepat.
Sebenarnya ada banyak
kasus luar biasa.
Logika ini tidak mudah,
meski ini
contoh yang relatif mudah.
Jika mengambil logika
ini dan menulisnya
pada antarmuka deklaratif,
Anda mungkin mendapati ini.
Jadi, di sini 
maksudnya adalah
jika jumlah di atas 100,
tampilkan api.
Jika jumlah di atas 0,
tampilkan kertas.
Jika jumlah di atas 0,
tampilkan badge berisi hitungan.

Spanish: 
donde queremos un ícono de mensaje no leídos.
Si no hay mensajes,
renderizamos un sobre vacío.
Si hay mensajes, el sobre tendrá un papel.
Tal vez nos ponemos creativos.
Si hay más de 100 mensajes,
agregamos fuego o algún dibujo similar.
Con una interfaz imperativa,
podemos crear una función
de conteo de actualizaciones.
Algo como esto,
donde obtenemos el nuevo conteo,
avanzamos y desciframos
cómo debemos manipular esta IU
para que refleje el estado adecuado.
De hecho, hay muchos casos límite aquí.
Y esta lógica no es sencilla,
incluso en este ejemplo bastante fácil.
Si toman esta lógica y,
en cambio, la escriben
en una interfaz declarativa, pueden obtener
algo como esto.
Lo que hacemos es decir: "Bien.
Si el conteo da más de 99, muestra fuego.
Si da más de 0, muestra papel.
"Si da más de 0, renderiza
una insignia con ese conteo".

Japanese: 
未読メッセージのアイコンが
あります
メッセージがないときは
空の封筒で表示します
メッセージがあるときは
手紙が入った封筒を表示します
少しかわいげのある
表現ですが
100通以上溜まっていると
燃え上がっているような
絵を表示します
命令型のインターフェースでは
このようなupdateCount関数を
書くのだと思います
メッセージの数を更新して
取入れる関数です
このような処理をして
現在の状態を反映させるのに
このUIを書き換えます
ここには 数多くのケースがあります
比較的簡単な例ですが
ここのロジックは単純ではありません
代わりに
declarativeインターフェースで
このロジックを書いてみると
このようになります
ここで何をしているかと言うと
メッセージ数が99を超えたら
火を表示せよ
メッセージ数が0より大きかったら
手紙を表示せよ
メッセージ数が0より大きかったら
このcountを使ってBadgeを実行せよ

Chinese: 
其中包括了“未读消息”这个图标
如果没有未读信息 我们就会显示一个空白信封
如果有 我们就在信封里放进一些纸
如果因为我们太受欢迎 收到了超过100封来信
这时我们就会显示一些火焰 等等
在命令式界面下 我们可能会写出一个更新计数功能
就像这样 我们获取最新计数值
在分析该值后 决定要如何更改这个 UI
让它能反映出适当的状态
其实这里会出现很多的边界状况
虽然这个例子看起来不复杂 但这个逻辑并不简单
如果你把这个逻辑写在声明式界面里
可能就会得出这样的代码
现在我们需要做的是 若果计数值超过99 就显示火焰
如果计数值超过0 就显示纸张
并生成一个带计数值的图标

Korean: 
읽지 않은 메시지 아이콘을 쓰는
UI가 있다고 가정해보죠
만약 메시지가 없다면 빈 봉투
모양을 렌더링할 것이고
메시지가 있다면 봉투 안에
종이 모양을 보여줍니다
나름 귀엽게
읽지 않은 메일이 100개 이상이면
종이 위에 불같은 걸 붙이기도 하고요
명령형 인터페이스에서는
이와 비슷한 update count
함수를 쓰겠죠
새 카운트 숫자를 받는 기능이죠
그러다가 우리는 이 UI가
적합한 상태를
표시하도록 하려면
어떻게 건드려야 할지
생각하게 됩니다
사실 여기엔 코너 케이스들이
많이 있는데요
비교적 쉬운 예시인데도
로직이 간단하지는 않습니다
따라서 여러분이 이 로직을 가져다
선언형 인터페이스에서 쓴다면
이런 결과가 나오죠
이 내용이 무슨 의미냐면
'좋아, 카운트가 99개 이상이면 
불이 보이게 하고'
'또 카운트가 0개 이상이면
종이가 보이게 하고'
'카운트가 0개 이상이면
그 카운트 숫자의 배지가 보이게 하자'

English: 
have an Unread Messages icon.
And so if there are no messages,
we render a blank envelope.
If there are some messages,
we put some paper in it.
And maybe we're a
little bit cutesy.
And if there are over
100 or something,
we show some fire
and stuff like that.
So with an imperative
interface, we
might write an update
count function something
like this, where what we do
is we get in the new count.
And we go through
and we figure out
how we're supposed
to poke at this UI
in order to make it
reflect the proper state.
And actually, there's a
lot of corner cases here.
And this logic isn't
easy, even though it's
a relatively simple example.
And so if you take this
logic and, instead, write it
in a declarative
interface, you might end up
with something like this.
And so here what we're
doing is we're saying, OK,
if the count's
over 99, show fire.
If the count's
over 0, show paper.
If the count's over 0, render
a badge with this count.

Portuguese: 
tem um ícone "Mensagens não lidas".
Se não há nenhuma mensagem,
exibimos um envelope em branco.
Se há mensagens, colocamos um
papel nele.
Depois damos uma enfeitada.
Se há mais de 100 mensagens,
mostramos fogo ou algo assim.
Com uma interface imperativa,
podemos criar algo como uma função
de contagem de atualização,
em que fazemos a nova contagem.
Avançamos e descobrimos
como devemos interagir com a IU
para que ela reflita o estado correto.
Na verdade, há vários casos isolados aqui.
Essa lógica não é fácil, embora seja
um exemplo relativamente simples.
Se você pegar essa lógica e usá-la
em uma interface declarativa, poderá
acabar com algo assim.
Aqui, o que estamos fazendo é dizer:
"Se a contagem estiver
acima de 99, mostre fogo.
Se estiver acima de 0, mostre papel.
Se a contagem for acima de 0,
exiba um selo com a contagem."

Korean: 
저희가 말씀드린 선언형 API는 바로
이런 뜻입니다
UI 개발자로서 여러분들은
이런 생각을 하실 텐데요
나는 이 데이터들로
어떤 UI를 보여주고자 하는가?
이벤트에 어떻게 반응하고 또
어떻게 내 UI를 인터랙티브하게 만들까?
그리고 아주 중요한 점이 있습니다
이제는 시간이 지남에 따라 UI가
어떻게 바뀔지 생각할 필요가 없습니다
이제는 데이터를 받을 때
그게 어떻게 표시되어야 하는지 
알려주는 거예요
다음 상태를 보여주는 거죠
그리고 프레임워크가 어떻게 
하나의 상태에서 다음으로 넘어가는지
제어합니다
그래서 더 이상은 이걸
생각할 필요가 없는 거죠
매우 중요한 점이에요
주어진 매개변수들을 가지고
UI를 표현하고
Composable 함수가
하나의 함수 정의에 불과하지만
UI의 모든 가능한 상태를
한 곳에서 표현할 수 있음을
이해해야 합니다
로컬로 정의된 거죠
이제 composition이라는
개념으로 넘어가는데요

Indonesian: 
Ini maksud saya
dengan API deklaratif.
Jika mau memikirkannya
-- sebagai developer UI
yang perlu Anda
pikirkan --
-- dengan data ini, UI
mana yang harus muncul?
Bagaimana cara merespons peristiwa
dan membuat UI interaktif?
Ini hal pentingnya.
Kita tidak perlu lagi memikirkan
perubahan UI seiring waktu.
Yang terjadi, saat
memasukkan data,
kita memberikan
tampilan yang seharusnya,
atau state berikutnya.
Framework mengontrol
cara beralih dari
satu state ke state lainnya.
Tidak perlu lagi
memikirkannya.
Itulah bagian pentingnya.
Jadi, deskripsikan UI berdasarkan
parameter yang diberikan.
Pahami bahwa
fungsi Composable
adalah satu definisi fungsi,
tetapi menjelaskan semua kemungkinan
state UI di satu tempat.
Ini didefinisikan secara lokal.
Ini mengarahkan kita ke
komposisi.

English: 
And that is what I mean when we
talk about a declarative API.
And if you want to think about
it-- so as a UI developer,
the things you need
to think about--
one-- given this data,
what UI do I want to show?
How do I respond to events
and make my UI interactive?
And then here's
the critical thing.
We no longer need to think about
how our UI changes over time.
What happens is, when
we get in the data,
we show what it
should look like.
We show what the next state is.
And then the framework controls
how to get from one state
into the other.
And so now we no longer
need to think about it.
And that's the critical piece.
So describe the UI based
on the provided parameters.
And understand that the
Composable function,
it's one function definition.
But it describes all possible
states of your UI in one place.
It's locally defined.
And that leads into what
we mean by composition.

Portuguese: 
É isso o que queremos dizer quando
falamos de uma API declarativa.
Parando para pensar,
como desenvolvedores de IU,
as coisas em que vocês precisam pensar...
Com esses dados,
que IU quero mostrar?
Como responder a eventos
e tornar minha IU interativa?
E aqui está algo importante.
Não precisamos mais pensar em
como nossa IU muda com o tempo.
O que acontece é que,
quando vamos aos dados,
mostramos como eles devem ser.
Qual será o próximo estado.
Depois, o framework controla
como passar de um estado para outro.
Agora, não precisamos mais pensar nisso.
E essa é a parte importante.
Descreva a IU com base nos
parâmetros fornecidos.
E entenda que a função combinável
é a definição de uma função.
Ela descreve todos os estados
possíveis da sua IU em um lugar.
Ela é localmente definida.
Isso nos leva ao que chamamos
de "composição".

Chinese: 
这就是声明式 API 能够做到的
作为 UI 开发者 你需要考虑的是
第一 在给定数据的前提下 我想展示什么 UI?
我要如何回应事件 让我的 UI 具备互动性？
关键在于 
我们现在已经不需要考虑 UI 应该如何随时间推移而变动了
当我们收入数据时 会显示它应有的样子
显示下一个状态是什么
框架会控制如何从一个状态到另一个状态
现在我们不需要考虑这个问题了
这就是关键所在
所以 请根据预先提供的参数来描述 UI
而且请注意 Composable 方法虽然只是一个功能定义
但它可以描述你的 UI 内部的所有状态
它是在本地定义的
这就把我们带到了下一个话题 Composition

Japanese: 
declarative APIというのは
こう言うものを意味しています
UI開発者として考えてみるとき
何を考えなければ
ならないかと言うと
このデータが与えられたとき
UIに何を表示させるか？
イベントにどう反応して
UIをインタラクティブにするか？ということです
重要なことは
UIを時間でどう変えるかを
考える必要がないということです
やることは
データが来たとき
UIが何を表示するかを
決めることです
次の状態が何であるかを
示します
すると フレームワークが
一つの状態から別の状態へ
どう変わるかを
制御してくれます
これについては
考える必要はありません
ここが重要な部分です
したがって 与えられたパラメータに基づいて
UIを記述すればよいのです
そして Composable関数と言うのは
単なる一つの関数定義だということを
理解してください
ただし 一箇所でUIがとり得るすべての状態を
表現します
ローカルに定義されます
そして 次の話は
Compositionが何を意味するかです

Spanish: 
A eso me refiero cuando hablo
sobre una API declarativa.
Si quieren pensarlo,
como desarrolladores de IU…
Deben analizar, primero,
¿qué IU quieren mostrar con estos datos?
¿Cómo responder a eventos
y crear una IU interactiva?
Aquí aparece lo importante.
Ya no necesitamos pensar
cómo cambia nuestra IU con el tiempo.
Lo que ocurre es que,
cuando ingresamos los datos,
indicamos cómo deben verse
y cuál es el siguiente estado.
Luego, el marco de trabajo
controla cómo pasar de un estado
al siguiente.
Ya no tenemos que pensar en eso.
Esa es la parte importante.
Describan la IU en función
de los parámetros proporcionados.
Y entiendan que la función componible
es la definición de una función,
pero describe todos los estados
posibles de su IU en un solo lugar.
Se define localmente.
Esto me da el pie
para explicar la composición.

English: 
So with a name like Compose
and an annotation called
Composable, it seems
like composition
is an important concept here.
So I want to talk
more about that.
And really, one of the things
that we're talking about here
is that our model of
composition differs
from the model of composition
that Inheritance follows.
And they're both
types of compositions.
So what we're talking about
here is a different type.
So let's go through an
example for this as well.
Let's say we have a view.
And we want to create an input.
And so we use View
as our base class.
And then we want
a ValidatedInput,
and so we create a subclass
of input to do that.
And we want a DateInput.
And we want to use the
validation of a date,
and so we subclass
ValidatedInput here as well.
But then we run into a problem.
When we want to create a date
range input, we have two dates.

Chinese: 
有了 Compose 这样的名称 和 Composable 这样的注解
光看单词就觉得 Composition 会是一个重要的概念
所以我想多谈谈这方面的内容
其实 我们想说的是 我们的 Composition 模型
不同于 Inheritance 遵循的 Composition 模型
而它们都是 Composition 类型
只是属于不同的类型而已
所以 我们也来举一些这方面的例子吧
比方说 我们有一个视图
而且我们想要创建一个输入
所以我们把 View 作为基类
然后我们需要一个 ValidatedInput
于是我们创建了一个 Input 的子类来完成这个任务
我们需要一个 DateInput
我们需要使用日期确认
所以 我们在这里继续继承 ValidatedInput 类
然后 我们就遇上了问题
我们在创建日期范围输入的时候 遇到了两个日期

Indonesian: 
Dengan nama Compose
dan anotasi bernama
Composable, sepertinya
komposisi adalah
konsep penting di sini.
Ini perlu dibahas
lebih lanjut.
Yang kita bahas
di sini adalah
model komposisi kita
berbeda dari
model komposisi yang
diikuti Inheritance.
Keduanya adalah
jenis komposisi.
Yang kita bahas
di sini jenis berbeda.
Mari periksa
contohnya juga.
Anggap ada tampilan (view).
Kita mau membuat input.
Kita menggunakan View
sebagai class dasar.
Kita mau
ValidatedInput,
kita membuat subclass
input untuk itu.
Kita mau DateInput.
Kita mau menggunakan
validasi tanggal,
kita membuat subclass
ValidatedInput juga.
Lalu, terjadi masalah.
Saat membuat input
rentang tanggal, ada 2 tanggal.

Portuguese: 
Com um nome como "Compose"
e uma anotação chamada
"combinável", parece que a composição
é um conceito importante aqui.
Quero falar mais sobre isso.
Realmente, uma das coisas
de que falamos aqui
é que nosso modelo de composição difere
do modelo de composição
que a herança segue.
Ambos são tipos de composição.
Mas estamos falando sobre
um tipo diferente.
Vamos ver um exemplo disso também.
Imaginem que temos uma visualização
e queremos criar uma entrada.
Usamos View como nossa classe básica.
Depois, queremos uma ValidatedInput
e criamos uma subclasse de
entrada para fazer isso.
Queremos uma DateInput
e, como queremos usar a
validação de uma data,
criamos uma subclasse
ValidateInput aqui também.
Depois encontramos um problema.
Quando queremos criar
DateRangeInput, temos duas datas.

Korean: 
Compose란 이름이나 
Composable라는 어노테이션에서
알 수 있듯이 컴포지션도
중요한 개념입니다
더 자세히 말씀드릴게요
제가 여기서 하려는 말은
저희의 컴포지션 모델은
상속이 따라오는
컴포지션과는 다르다는 겁니다
둘 다 컴포지션 종류이지요
오늘 다룰 이 컴포지션은
다른 종류에요
이것도 예시로 한번 살펴보죠
View가 있다고 가정하고
Input을 만들고 싶어요
그래서 View를 
베이스 클래스로 쓰죠
그리고 ValidtedInput도
얻고 싶고요
그래서 Input의 
하위분류도 만듭니다
DataInput도 필요하죠
날짜 유효성 체크도 쓰고 싶으니
여기에도 ValidatedInput
하위분류를 만듭니다
이때 문제가 생기죠
DateRangeInput을 만들 때
날짜가 두 개인 겁니다

Spanish: 
Con un nombre como "Compose" y una anotación
llamada componible, parece que la composición
es un concepto importante.
Quiero explayarme un poco más.
Una de las cosas de las que estamos hablando
es que nuestro modelo de composición difiere
del modelo de composición
que sigue la herencia.
Ambos son tipos de composiciones.
Lo que mencionamos aquí es un tipo diferente.
Pasemos a un ejemplo.
Supongamos que tenemos una vista
y queremos crear una entrada.
Usamos View como la clase de base.
Queremos una ValidatedInput,
y creamos una subclase de entrada para esto.
Queremos una DateInput.
Usaremos la validación de una fecha,
así que creamos una subclase
de ValidatedInput aquí también.
Pero ocurre un problema.
Cuando queremos crear una entrada
de rango de fechas, tenemos dos fechas.

Japanese: 
Composeのようなネームや
Composableと呼ばれるアノテーションが
使われるので Compositionというのは 何だか
重要な概念のようです
そこで これについてお話しします
ここでお話ししているのは
compositionのモデルというのは
インヘリタンスが従うcompositionのモデルとは
違います
両方ともcompositionタイプです
ここで取り扱っているのは
違うタイプです
これも例を使って説明します
ビューがあるとします
そこでインプットを生成します
ビューをベースクラスとして
使います
ValidatedInputが必要なので
入力のサブクラスを作って
対応します
また DateInputも必要です
日付けの検証もします
ここでValidationInputを
サブクラス化します
しかし ここで問題が生じます
日付けの入力範囲を制限しようとすると
2つの日付の入力が必要になります

Chinese: 
所以 我们想要分别确认两个日期
也许我们想要把再做一个 DateInput 的子类
但是需要处理的日期有两个 所以做不到
所以 我们遇到了这个 Inheritance 局限
而必须找出一个母项用作继承源头
在 Compose 中 这个问题更简单一些
我们在创建 ValidatedInput 的时候
只要在方法主体内部调用 Input 即可
我们可以使用一些代码来修饰它 并完成确认
然后 当我们创建 DateInput 的时候
我们也会调用 ValidatedInput
然后 当我们遇到日期范围输入的时候 
就没有问题了 只需要调用两次即可
所以 在 Compose 的构成模型中
我们没有在单一母项上生成代码
于是 问题就这样解决了
另一个 Composition 问题是我所谓的“抑制”现象
我们想构建出一个漂亮的框体
它本质上是一个用来装饰其他视图的视图

Spanish: 
Queremos validarlas de forma separada.
Podríamos crear una subclase de DateInput.
Pero hay dos, así que no es posible.
Encontramos esta limitación en la herencia,
y es que necesitamos tener
un elemento superior del cual heredar.
En Compose, el problema es más sencillo.
Cuando creamos nuestra ValidatedInput,
simplemente llamamos a Input
en el cuerpo de la función.
Podemos usar alguna decoración
para la validación.
Luego, al crear una entrada de datos,
también llamamos a ValidatedInput.
Ahora, al encontrar la entrada
del rango de fechas,
ya no ocurre el problema.
Son solo dos llamadas.
Y no componemos ningún elemento superior
en el modelo de composición de Compose.
Así se resuelve el problema.
Otro tipo de error de composición
es lo que yo llamaría "contención".
Queremos un cuadro sofisticado,
que es una vista que decora otras vistas.

Korean: 
그래서 두 날짜의 유효성 체크를 
따로 합니다
DateInput 하위분류로
할 수도 있지만
날짜가 두 개니까
그렇게는 할 수가 없겠네요
그래서 상속해 줄
부모 클래스가 필요하다는
상속 관련 한계에 부딪히게 되죠
Compose에서는 문제가 더 간단합니다
ValidatedInput을 만들 때
함수의 Body에 
Input을 호출하기만 하면 되죠
그리고 유효성 체크 부분을
추가하면 됩니다
그리고 DateInput을 만들면
ValidatedInput도 
호출하게 되는 거죠
이제 DateRangeInput이네요
여긴 문제가 없어요
그냥 두 개의 호출이니까요
따라서 Compose의 
컴포지션 모델에다가
구성해야 할 부모 클래스가
하나도 없습니다
그럼 문제가 해결되네요
또 다른 컴포지션 문제는 바로
제가 방지라고 부르는 것입니다
FancyBox를 하나
갖고 싶다고 가정해 봅시다

Portuguese: 
Então, queremos validar as duas
datas separadamente.
Podemos criar a subclasse DateInput,
mas há duas delas.
Não podemos fazer isso.
Encontramos esta limitação na herança:
temos que ter um item pai para herdar.
No Compose, o problema é mais simples.
Quando criamos nossa ValidateInput,
apenas chamamos a entrada
no corpo da nossa função.
Podemos decorá-la com
algo para validação.
Quando criamos uma entrada de dados,
acabamos chamando ValidateInput também.
Quando vamos para a
entrada de intervalo de datas,
não temos mais um problema.
São apenas duas chamadas.
Não há um item pai para
composição no modelo do Compose.
Isso resolve esse problema.
Outro tipo de problema de composição
é o que eu chamaria de "contenção".
Queremos uma caixa bonita,
FancyBox, uma visualização que

English: 
So we want to validate
two dates separately.
So maybe we want to
subclass DateInput,
but there are two of them.
So we can't really do that.
And so we run into this
limitation around inheritance
that we have to have one
parent that we inherit from.
In Compose, the
problem is simpler.
So when we create
our ValidatedInput,
we just call Input in
the body of our function.
And we can decorate it with
something for validation.
Then when we create
a data input,
we end up calling
ValidatedInput as well.
And now, when we run into
the date range input,
we no longer have a problem.
It's just two calls.
And so there is no
single parent that we
compose onto in Compose's
composition model.
And that solves this problem.
Another type of
composition problem
is what I would
call containment.
So we want to have this fancy
box, which is a view that

Japanese: 
そこで 2つの日付けを別々に検証する
ことにします
DateInputをサブクラス化しようと
思いますが
2つあるので
できません
インヘリタンスに関するこの制限に
当たってしまいます
継承する親クラスが一つなければ
なりません
Composeでは
問題は簡単になります
ValidateInputを作成するとき
関数の本体でInputを呼ぶだけです
検証にはそれを修飾するだけです
そうすればデータ入力を
作ったときに
ValidatedInputを呼ぶだけで
済みます
そうすれば 日付けの入力範囲を検証するときに
問題は生じません
2回呼ぶだけです
Composeのcompositionモデルでは
コンポーズする親はありません
これで問題は解決されます
Compositionのもう一つのタイプの
問題は
いわゆるcontainmentです
この想像上の箱を使いたいとします
ほかのビューを

Indonesian: 
Kita mau memvalidasi
2 tanggal secara terpisah.
Kita mau membuat
subclass DateInput,
tapi ada 2 DateInput
jadi itu mungkin.
Terdapat pembatasan
inheritance sehingga
harus ada induk yang
turunannya kita gunakan.
Di Compose, masalahnya
lebih sederhana.
Saat membuat
ValidatedInput,
cukup panggil Input
di body fungsi.
Kita bisa mendekorasinya dengan
sesuatu untuk validasi.
Lalu, kita membuat
input tanggal,
serta memanggil
ValidatedInput.
Saat menemukan input
rentang tanggal,
tidak ada masalah lagi.
Ini hanya dua panggilan.
Tidak ada induk yang
kita gunakan untuk mengomposisi
dalam model komposisi
di Compose.
Masalah terpecahkan.
Jenis masalah
komposisi lain
disebut containment.
Kita ingin memiliki fancy box,
berupa tampilan

Korean: 
이 것은 다른 뷰들을
꾸며주는 뷰입니다
그리고 또 다른 뷰들도 있죠
Story나 EditFrom 같은 것들이요
그럼 FancyStory나 
FancyEditForm을 만들려면
무엇을 해야 할까요?
FancyBox에서 상속할까요?
혹은 Story에서요?
확실하지 않은 게,
여기서도 상속 체인에는
한 부모 클래스가 필요하니까요
Compose는 이런 문제도
잘 해결해주지요
Composable lambda가 
자식 클래스로 있습니다
이게 다른 것을 포함하게 하는 것을
정의할 수 있게 해주죠
따라서 FancyStory를 만들 때
FancyBox의 자식 안에 있는
Story만 호출하면 됩니다
FancyEditForm도 마찬가지죠
이게 Compose의 컴포지션 모델입니다
Compose가 또 잘하는 것은
캡슐화입니다
Composable 함수로
공개 API를 만들 때
생각해야 할 부분이죠
Composable 함수의 공개 API는
자신이 수신하는 매개변수 세트에요

Indonesian: 
yang mendekorasi
tampilan lain.
Mungkin ada tampilan
lain di sini,
seperti Story dan
EditForm.
Kita ingin membuat fancy story dan
fancy edit form.
Kita harus bagaimana?
Kita turunkan dari
FancyBox?
Atau turunkan dari
Story?
Ini tidak jelas karena
kita perlu satu induk
untuk rantai inheritance itu.
Compose menanganinya
dengan baik.
Ada lambda Composable
sebagai turunan.
Ini memungkinkan kita
menentukan sesuatu
yang membungkus hal lain.
Kini kalau mau membuat
FancyStory,
kita cukup memanggil Story di
dalam turunan FancyBox --
sama juga untuk
FancyEditForm.
Ini model komposisi
di Compose.
Masalah lain yang
diselesaikan Compose
dengan baik adalah
encapsulation.
Ini perlu dipikirkan saat
membuat API publik
dari fungsi composable.
API publik dari sebuah composable
adalah serangkaian parameter
yang diterimanya.

English: 
decorates other views.
And we might have
some other views here,
like Story and EditForm.
And then we want to make a fancy
story and a fancy edit form.
But what do we do?
Do we inherit from FancyBox?
Or do we inherit from Story?
It's unclear because,
again, we need one parent
for that inheritance chain.
And so Compose handles
this really well.
We have a Composable
lambda as children.
And that allows us
to define something
that wraps another thing.
So now when we want
to create FancyStory,
we just call Story inside of
the children of FancyBox--
same with FancyEditForm.
And this is Compose's
composition model.
Another thing that Compose
accomplishes really
well is encapsulation.
This is what you
should be thinking
about when you make public
APIs of composable functions.
And the public API
of a composable
is really the set of
parameters that it receives.

Portuguese: 
decora outras visualizações.
Podemos ter outras visualizações aqui,
como Story e EditForm.
Queremos criar FancyStory
e FancyEditForm.
Mas o que fazemos?
Herdamos de FancyBox?
Ou herdamos de Story?
Não está claro, porque,
de novo, precisamos de um item pai
para essa cadeia de herança.
O Compose gerencia isso muito bem.
Temos um lambda do Compose
como um item filho.
Isso nos permite definir algo
que une outro elemento.
Para criar FancyStory,
temos apenas que chamar Story
dentro dos filhos de FancyBox...
o mesmo acontece com FancyEditForm.
Este é um modelo de composição do Compose.
Outra coisa que o Compose faz realmente
bem é o encapsulamento.
É nisso que devem pensar
quando criam APIs públicas
de funções combináveis.
A API pública de uma função combinável
é o conjunto de
parâmetros que ela recebe.

Japanese: 
修飾するビューです
ほかにもビューがあります
StoryやEditFormです
StoryやEdit Formを作ります
どうやって作ればよいのでしょうか？
FancyBoxから継承するのでしょうか？
Storyから継承するのでしょうか？
継承チェーンを使う場合
親が一つ必要となるので
はっきりしません
Composeを使えば
非常にうまく処理できます
子としてComposableラムダが
使えます
もう一つのものをラップするものを
定義できます
したがって
FancyStoryを作成しようとする場合
FancyBoxの子の中で
Storyを呼ぶだけです
FancyEditFormと同じです
これがComposeの
compositionモデルです
Composeでできる
もう一つのこととして
カプセル化があります
composable関数の
パブリックAPIをつくるときに
考える必要があります
composableのパブリックAPIは
実は それが受取るパラメータのセットです

Chinese: 
其他视图 比如 Story 和 EditForm 也可能会出现
然后 我们想要制作一个漂亮的故事 (FancyStory)
和一个漂亮的编辑表单 (FancyEditFOrm)
那么要怎么做呢？
要从 FancyBox 那里继承 还是从 Story 那里继承？
答案并不清楚 因为我们需要一个母项
用来提供给 Inheritance 链条
Compose 很好地解决了这个问题
我们使用一个 Composable lambda 作为子项
让我们定义一个能够封装其他代码的东西
现在 当我们想要创建 FancyStory 的时候
我们就在 FancyBox 子项内部调用 Story
在 FancyEditForm 这边也是一样
这就是 Compose 的 Composition 模型
Compose 的另一个拿手好戏就是封装
当你在用 composable 方法制作公共 API 的时候 
这就是你应该考虑的问题
而 Composable 的公共 API 
本质上就是它收到的参数集

Spanish: 
Podemos tener otras vistas aquí,
como Story y EditForm.
Haremos una historia y un formulario
de edición sofisticados.
¿Pero cómo?
¿Heredamos de FancyBox o de Story?
No es claro porque
precisamos un elemento superior
para esa cadena de herencia.
Compose maneja muy bien esto.
Tenemos una lambda componible
como elemento secundario.
Eso nos permite definir algo
que une otra cosa.
Ahora queremos crear FancyStory.
Llamamos a Story en los elementos
secundarios de FancyBox…
Lo mismo con FancyEditForm.
Este es el modelo de composición de Compose.
Otra cosa que Compose logra muy bien
es la encapsulación.
Es lo que deben pensar
cuando crean API públicas
de funciones componibles.
La API pública de una función componible
es el conjunto de parámetros que recibe.

Indonesian: 
Parameter tersebut diberikan,
jadi API itu tidak punya kontrol.
Parameter hanya disediakan
sebagai data.
Di sisi lain, composable bisa
membuat dan mengelola state,
lalu memasukkan state
beserta beberapa data
yang diterimanya ke
composable lain
sebagai parameter.
Karena composable
mengelola state itu --
Adam membahasnya
kemarin --
jika mau membuat
perubahan pada state itu,
Anda dapat memungkinkan
composable turunan untuk memberikan
sinyal perubahan
kepada Anda melalui callback.
Terakhir, saya mau
berbicara tentang
Recomposition.
Pada dasarnya,
ini menjelaskan bahwa
fungsi Composable punya
kemampuan khusus
untuk dipanggil ulang
kapan saja.
Artinya, jika Anda punya
hierarki Composable
yang sangat besar --
saat ada bagian hierarki
yang berubah,
Anda tidak perlu mengubah
seluruh hierarki.
Jadi artinya, fungsi Composable
bisa dimulai ulang.
Anda bisa
memanfaatkannya untuk

Korean: 
그건 그냥 주어지는 거니까,
그걸 조작할 수는 없습니다
그저 데이터로 주어지는 거죠
반면에 Composable은 상태를
관리하거나 만들어낼 수 있어요
그리고 그 상태를
자신이 받은
데이터와 함께
다른 Compsoable에게
매개변수로 전달합니다
상태를 관리할 수 있기 때문에
애덤이 어제 말한 것처럼
만약 상태를 바꾸고 싶다면
자식 composable이 그러한 변화를
콜백을 통해서 신호를 보내도록
할 수 있습니다
끝으로 Recompostion에 대해
말씀드리고 싶네요
Recomposition이란 
Composable 함수는 기본적으로
언제든 다시 호출될 수 있는
특수한 능력이 있음을 나타내는 말입니다
가령, 아주 거대한
Composable 계층구조가 있다면
만약 그 일부가 바뀌었을 때
이 전체 계층구조를 다시 
만들고 싶진 않으실 거예요
Composable 함수는
이런 방식으로 다시 시작할 수가 있죠
이 능력을 활용하면
강력한 일을 할 수 있도록

Japanese: 
パラメータはそれに渡されますが
コントロールすることはできません
データとして渡されるだけです
一方 composableは状態を
管理し 生成することができます
生成した状態は 受取ったデータと一緒に
別のcomposableに
パラメータとして
渡すこともできます
さて
その状態を管理するので
これについては
Adamが昨日話しましたが
その状態を変更したい場合は
変更について
コールバックを使って
子のcomposableに伝えさせる
ことができます
最後に
Recompositionについて
話そうと思います
これは基本的に
どのComposable関数でも いつでも
再呼び出しができるという
特別な能力を
持っているということです
どういう意味かと言うと
巨大なCompsable階層が
あるとして
階層の一部に変更を加えたい場合
階層全体を再構築はしたくないと
思います
Composable関数というのは
このようなときに再起動可能な関数です
これを使うと 大変強力なことが

Spanish: 
Le son proporcionados a la API
para que no pueda controlarlos.
Solo se brindan como datos.
Por otro lado, una función componible
puede administrar y crear un estado.
Luego, pasa ese estado
junto con, posiblemente,
algunos datos que recibió
a otra función componible
como parámetros.
Ahora, como administra ese estado…
Adam lo mencionó ayer…
Si quieren cambiar ese estado,
pueden permitir que las funciones
componibles secundarias
indiquen el cambio
mediante devoluciones de llamadas.
Por último, quiero hablar
sobre algo llamado "recomposición".
Es básicamente una forma de decir
que cualquier función componible
tiene esta habilidad especial
de volver a invocarse en cualquier momento.
Significa que, si tienen una gran jerarquía
de funciones componibles…
Cuando cambian partes de su jerarquía,
no sería conveniente
reinventar toda la jerarquía.
Eso hace que las funciones componibles
sean reiniciables.
Pueden aprovechar esto

Chinese: 
它只能接收这些数据 而无法控制这些参数
而 Composable 是可以管理并创建状态的
然后它会把这个状态 可能还连同它收到的一些数据
一并作为参数 传给其他 Composable
因为它在管理这些状态
Adam 昨天谈过这个问题
如果你想改变这个状态
你可以让你的子 Composable 项
把改动信号通过回调发给你
最后 我想谈谈 Recomposition 
我们想通过这个概念表明
任何 Composable 功能都可以
在任意时刻被重新调用
这意味着 如果你的 Composable 层级非常大
那么当你的层级中的某些部分更改的时候
你是不想重新构建整个层级的
Composable 功能在这个意义上讲 是可重启的
你可以利用这个功能来做很多事

Portuguese: 
Eles são fornecidos à API,
então ela não tem controle deles.
Eles são fornecidos apenas como dados.
Por outro lado, uma função combinável
pode gerenciar e criar um estado.
Depois, ela transmite esse estado,
possivelmente com dados recebidos,
a outras funções combináveis
como parâmetros.
Como ela gerencia esse estado...
Adam falou sobre isso ontem...
Se você quer fazer uma
mudança nesse estado,
pode permitir que as
funções filhas combináveis
sinalizem essa mudança via callbacks.
E gostaria de falar sobre algo
chamado "recomposição".
Essa é, basicamente, nossa maneira
de dizer que qualquer função
combinável tem essa capacidade especial
de ser invocada novamente
a qualquer momento.
Isso significa que se você
tem uma hierarquia de
funções combináveis muito grande...
quando partes da sua hierarquia mudam,
não é conveniente ter que
recriar toda a hierarquia.
Então, as funções combináveis são
reiniciáveis nesse sentido.
Você pode aproveitar para fazer

English: 
And those are given to it, so it
doesn't have control over them.
They're just provided as data.
On the other hand, a composable
can manage and create state.
And then it passes that state
along with, potentially,
some data that it received
down to other composable
as parameters.
Now, because it's
managing that state--
Adam talked about
this yesterday--
if you want to make a
change to that state,
you can allow your
children composables
to signal that change up
towards you via callbacks.
And finally, I want to
talk about something
called Recomposition.
And this is basically our way
of saying that any Composable
function has this
special ability
to get re-invoked at any time.
And so what this means is that,
if you have this very large
Composable hierarchy--
what happens is, when parts
of your hierarchy change,
you don't want to have to
reinvent the entire hierarchy.
And so Composable
functions are sort of
restartable in this way.
And you can actually
leverage this to do

Spanish: 
para hacer cosas muy potentes.
Aquí tenemos una función Bind
que tal vez verían hoy
en el desarrollo de Android actual.
Tenemos datos en vivo
a los que queremos suscribir nuestra vista.
Para hacerlo, llamamos al método Observe
con un propietario del ciclo de vida,
y le pasamos esta lambda.
Se llamará a esa lambda cada vez
que se actualicen los datos en vivo.
Cuando eso suceda, quizás queramos
actualizar nuestras vistas.
Con Compose, podemos invertir
esta relación.
En Compose, tendríamos una función
componible de mensajes similar
que recibiría datos en vivo.
Aquí, llamamos al método Observe de Compose.
Observe hace dos cosas.
Primero, desune los datos en vivo
y muestra el valor actual
como su valor de retorno.
Significa que pueden usarlo en el cuerpo
que rodea la función.
También hace otra cosa.
De forma implícita… suscribe

Korean: 
이용할 수도 있습니다
여기 여러분이 오늘날
Android 개발에서
보실 수 있을법한 Bind 함수가 있습니다
뷰에다가 구독시킬 LiveData도 있고요
그러기 위해서 우리는
Observe 메서드를
LifecycleOwner와 함께
호출해야 합니다
그리고 lambda에 집어넣죠
이 lambda는 이제 LiveData가
업데이트될 때마다
호출될 겁니다
그러면 그때 뷰도
업데이트해야죠
Compose에서는 이러한 관계를
뒤집을 수 있습니다
Compose에는 비슷한 Messages
Composable이 있는데
이게 LiveData를 수신하게 되죠
그리고 여기서 Composer의 
Observe 메서드를 호출해요
Observe는 여기서
두 가지 일을 하는 거죠
첫째, LiveData를 언랩하고
현재 값을 반환 값으로 돌려보냅니다
즉, 함수의 주변 body에서도
사용할 수 있다는 뜻이죠
기능이 또 있는데요
언랩되는 Composable에

Chinese: 
这个 bind 方法在如今的 Android 开发中比较常见
我们想让我们的视图订阅到 LiveData
所以 我们最后调用了 observe 方法
其中带有一个生命周期所有者
然后我们传入这个 lambda
这个 lambda 每次在 LiveData 更新时都会被调用
这时 我们就需要更新我们的视图了
我们可以使用 Compose 来转化这个关系
在 Compose 中 我们会有一个类似的 Messages Composable
它会接收 LiveData
这里 我们会调用 Compose 的 observe 方法
Observe 的作用有两个
第一 它会解封 LiveData
并将当前值作为返回值进行返回
这意味着 你可以在方法的主体范围使用它
它的功能还不止于此

English: 
some pretty powerful things.
So here's a Bind
function that is maybe
something you would see
today in Android development.
So we have a live data that we
want to subscribe our view to.
And so to do that, we end up
calling the Observe method
with a lifecycle owner.
And then we pass in this lambda.
And that lambda is going to
get called every single time
the live data updates.
And when that
happens, we might want
to go and update our views.
With Compose, we can
actually kind of invert
this relationship.
So in Compose, we would have
a similar Messages Composable.
And it would
receive a live data.
And here, we call
Compose's Observe method.
And Observe does
two things here.
First, what it does is
it unwraps that live data
and returns the current
value as its return value.
And that means you can
use it in the surrounding
body of the function.
But it also does something else.
It implicitly--
well, it subscribes

Japanese: 
できます
ここに bind関数がありますが
Androidの開発では最近使うようになりました
ビューをサブスクライブしたい
ライブデータがあるとします
そのためには
ライフサイクルオーナーを用いて
Observeメソッドを
呼ぶことになります
このラムダの中に入れて渡します
そのラムダはライブデータが
更新されるたびに毎回
呼び出されることになります
それが起こると
ビューを更新します
Composeではこの関係を実際に
逆転させることができます
Composeでは似たような
メッセージComposableがあります
ライブデータを受け取ります
ここで
ComposeのObserveメソッドを呼び出します
ここでObserveは2つのことを行います
まず ライブデータをアンラップして
戻り値として現在の値を返します
それは 関数のまわりのbodyで
使えるということです
他にやることは

Indonesian: 
melakukan berbagai hal
yang luar biasa.
Berikut ini fungsi Bind
yang mungkin
bisa Anda lihat dalam
pengembangan Android saat ini.
Ada data live yang ingin kita
subscribe untuk tampilan.
Untuk itu, panggil metode Observe
dengan pemilik siklus hidup.
Lalu, masukkan lambda ini.
Lambda itu akan dipanggil
setiap kali
data live diperbarui.
Saat itu terjadi,
kita mungkin perlu
memperbarui tampilan.
Dengan Compose,
kita bisa membalik hubungan ini.
Di Compose ada 
Composable Message yang serupa,
yang dapat menerima data live.
Di sini kita memanggil
metode Observe pada Compose.
Observe melakukan
dua hal di sini.
Pertama, membuka
data live tersebut
dan menampilkan nilai saat ini
sebagai nilai yang dihasilkannya.
Artinya, ini bisa digunakan
di body di sekitar fungsi itu.
Observe juga
melakukan hal lain.
Secara implisit --
ia men-subscribe

Portuguese: 
coisas muito interessantes.
Temos uma função Bind que, talvez, seja
algo que você veria hoje
no desenvolvimento em Android.
Temos dados ao vivo em que
queremos inscrever nossa visualização.
Para fazer isso,
chamamos o método Observe
com um proprietário de ciclo de vida.
Depois, passamos este lambda.
Ele será chamado toda vez que os
dados ao vivo forem atualizados.
Quando isso acontece, queremos
atualizar nossas visualizações.
Com o Compose,
podemos inverter essa relação.
No Compose, temos uma função 
combinável de mensagens semelhante.
Ela recebe dados ao vivo.
Aqui, chamamos o método
Observe do Compose.
Esse método tem duas funções.
A primeira é separar esses dados ao vivo
e retornar o valor atual
como o valor de retorno.
Isso significa que você pode
usá-lo no corpo adjacente da função.
Ele também faz algo mais.
Implicitamente, ele se inscreve

English: 
that live data to the Composable
that it's being unwrapped in.
And so that means that,
instead of providing a lambda,
you just now know that this
Composable function will
recompose every time
live data changes.
Looking at a simpler
example of this,
let's imagine that we have
a simple counter composable.
And so here we introduce a piece
of state, which is our count.
And State is as a
function in Compose
that returns an instance
of this state class.
And the state class is
annotated with @Model.
And what @Model does
is it means that
every property of that class--
now the reads and writes to
that property are observable.
And so what Compose does
is, when you're executing
your Composable function, if
you read one of these model
instances, Compose
will automatically

Japanese: 
そのライブデータを
アンラップしているComposableに
サブスクライブします
したがって
ラムダを使うのではなく
ライブデータが変化するたびに
Composable関数が再composeします
もっと簡単な例として
単純なカウンターComposableがあるとします
ここでstate状態を導入します
カウンターの計数値です
このstateクラスのインスタンスを返す
Compose内の関数です
stateクラスは@Modelで
アノテートされています
@Modelが何をするかというと…
そのクラスのすべてのプロパティへの
リードとライトはobservableだと
いうことを意味します
したがって
Composeが何をするかと言うと
Composable関数を実行中に
これらのモデルインスタンスのうちのどれかを
リードすると
Composeは自動的に

Spanish: 
esos datos en vivo a la función
componible que se está desuniendo.
Significa que, en vez de darle una lambda,
esa función componible se recompondrá
cada vez que cambien los datos en vivo.
Para pensar un ejemplo más sencillo,
supongamos que tenemos
una función componible de contador.
Ingresamos un estado, que es nuestro conteo.
State es una función en Compose
que muestra una instancia
de esta clase de estado.
La clase de estado se anota con @Model.
La función de @Model
es hacer que cada propiedad de esa clase…
Ahora se pueden observar las lecturas
y escrituras sobre la propiedad.
En cuanto a Compose, cuando ejecutan
la función componible,
si leen una de esas instancias
de modelo, Compose suscribirá automáticamente

Indonesian: 
data live ke Composable
yang sedang dibuka.
Artinya, bukannya
memberikan lambda,
fungsi Composable akan
dikomposisi ulang setiap
data live berubah.
Untuk melihat contoh
yang lebih sederhana,
bayangkan ada composable
penghitung yang sederhana.
Kita memperkenalkan sebuah state,
yaitu hitungan.
State adalah fungsi
di Compose
yang menghasilkan instance
dari class state ini.
Class state
beranotasi @Model.
@Model artinya
tiap properti dari
class tersebut --
yaitu operasi membaca dan menulis ke
properti itu, bisa diamati.
Yang dilakukan Compose adalah
saat Anda mengeksekusi
fungsi Composable, jika
Anda membaca salah satu instance model,
Compose akan otomatis
membuat

Portuguese: 
nos dados ao vivo na função
combinável que está sendo separada.
Isso significa que, em vez de
fornecer um lambda,
você sabe que essa função 
combinável será
recomposta toda vez que os
dados ao vivo mudarem.
Analisando um exemplo mais simples,
vamos imaginar que temos uma
função combinável de contagem simples.
Aqui, introduzimos um estado, 
que é nossa contagem.
State é uma função no Compose
que retorna uma instância
desta classe de estado.
A classe de estado é
anotada como @Model.
O que @Model faz é que...
em cada propriedade dessa classe...
as leituras e as gravações
nessa propriedade podem ser observadas.
O que o Compose faz é: quando
você está executando
sua função combinável, se você lê uma
dessas instâncias de modelo,
ele inscreverá automaticamente

Chinese: 
它会订阅 LiveData 到 它被解封的那个 Composable
也就是说 无需提供 lambda
现在你知道 这个 Composable 方法
会随着 LiveData 的每次更新而重构
来看一个更简单一些的例子
假如我们现在有一个简单的 Counter Composable
这里我们加入一个状态 也就是 count
状态在这里作为 Compose 的一个方法
其作用是返回一个此状态类的实例
而状态类是用 @Model 注解的
@Model 的含义是 那个类的所有属性
那个属性的读取和写入 现在都是可观察的
Compose 的作用是 当你执行 Composable 方法时
如果你读取了一个这样的模型实例

Korean: 
LiveData를 구독시킵니다
따라서, lambda를 제공하지 않고도
LiveData가 바뀔 때마다 
Composable 함수가
recompose된다는 것을
알 수 있겠네요
더 단순한 예시를 들어서
간단한 Counter
Composable이 있다고 가정합니다
여기에서 하나의 상태를 넣는데,
이게 카운트죠
그리고 State는 Compose의 
함수 역할로
State 클래스의 인스턴스를 돌려보냅니다
State 클래스는 @Model이라고
어노테이션되어 있고요
여기서 @Model이 하는 일은
그 클래스의 모든 프로퍼티에서
이 프로퍼티의 모든 read와 write가
관찰 가능하게 됩니다
여기서 Compose의 역할은,
Composable 함수를 실행할 때
만약 이 모델 인스턴스 중
하나를 read했다면
Compose가 자동으로

Japanese: 
まわりのスコープをそのモデルのライトに
サブスクライブします
つまり
この例は自己完結型です
Counterは
モデルの値が変化するたびに
再composeされます
ここまで
Composable関数が持つ
いろいろな機能について
話して来ました
次は実際にどう実装するかについて
紹介していきます
その前に 水を一杯
さて
お断りしておくと
これから私がしゃべることは
実装時の詳細で
変更されることがあります
変更される可能性の方が高いです
ですが面白いので紹介します
ただし 重要なことは
これを理解しなくても
Composeは使えます

Spanish: 
el ámbito adyacente
a las escrituras en ese modelo.
Significa que este ejemplo es autónomo.
Tenemos un contador
que se recompondrá cada vez
que cambie el valor de ese modelo.
Ya mencionamos muchas capacidades
que tienen las funciones componibles.
Pasemos a cómo se implementan.
Primero, voy a beber agua.
Un pequeño aviso.
Todo lo que voy a decir
son detalles de implementación
que están sujetos a cambios.
Es muy posible que cambien.
Pero es divertido hablar de ellos.
Lo que sí quiero destacar
es que no necesitan entender esto
para usar Compose.

Portuguese: 
o escopo adjacente para
gravações nesse modelo.
Isso significa que esse exemplo
é autossuficiente.
Temos um contador que será
recomposto toda vez que
o valor desse modelo muda.
Falamos sobre vários recursos
das funções combináveis.
Vamos falar sobre como
isso é realmente implementado.
Antes de fazer isso, vou pegar uma água.
Uma pequena exoneração
de responsabilidade:
tudo que vou dizer é
um detalhe da implementação,
e está sujeito a mudanças.
De fato, é muito propenso a mudanças.
Mas, é legal falar sobre isso.
O que eu tenho de importante a dizer
é que não é necessário saber
isso para usar o Compose.

English: 
subscribe the surrounding
scope to writes to that model.
So that means that this
example is self-contained.
We have a counter that will
get re-composed every time
the value of that
model is changed.
OK, so we just talked
about a lot of capabilities
that Composable functions have.
Let's start talking about how
it's actually implemented.
Before we do that, I'm
going to get some water.
OK-- small disclaimer--
everything I'm about to say
is an implementation detail.
And it's subject to change.
In fact, it's very
likely to change.
But it's fun to talk about.
But the important thing
that I want to say
is that understanding this is
not required to use Compose.

Indonesian: 
cakupan di sekitarnya men-subscribe
operasi menulis ke model itu.
Artinya, contoh ini
bisa bekerja mandiri.
Ada penghitung yang
dikomposisi ulang
setiap nilai model itu
berubah.
Kita baru membahas
banyak kemampuan
fungsi Composable.
Mari membahas
cara implementasinya.
Sebelumnya,
saya minum air dulu.
Oke -- ini penafian --
yang akan saya katakan adalah tentang
detail implementasi.
Dan bisa berubah.
Bahkan, sangat
mungkin berubah.
Tapi, ini menarik untuk
dibahas.
Hal penting yang ingin
saya katakan adalah bahwa
memahami hal ini tidaklah wajib
untuk dapat menggunakan Compose.

Chinese: 
Compose 就会自动订阅周边作用域 写入那个模型
也就是说 这个是独立的
每当模型数值更改的时候
这个 counter 都会被重构
好 我们谈了很多 Composable 方法可以做到的事情
下面我们来谈谈它是如何被实现的
我先喝口水
先做一个小小的免责声明
我下面讲的所有东西都是实现细节 
是可能会改变的 非常可能 
不过聊起来还是很有意思
我想说的是 如果你想使用 Compose 
那么你并不是非要理解这个细节不可

Korean: 
주변 범위를 구독하여 그 
모델에 write하게 합니다
즉 이 예시가 독립적이라는 뜻이고
모델의 값이 달라질 때마다
re-compose되는
카운터를 가지게 된 거죠
이렇게 Compsable 함수의
여러 가지 기능에 대해
얘기해봤는데요
이제 실제 구현 방법에 대해
말씀드리겠습니다
일단 물 좀 마실게요
한 가지 말씀드릴 것은
제가 지금부터 말씀드리는 건 세부적인
구현 방법이라는 겁니다
충분히 바뀔 수 있지요
사실, 바뀔 가능성이 크죠
하지만 재미있을 겁니다
중요한 것은
꼭 이것을 이해해야만 Compose를
사용할 수 있는 게 아니라는 겁니다

Chinese: 
我只是想满足大家的好奇心而已
而且 如果你真的想深入研究 理解这些东西
从这个细节入手 也是个不错的开始
我们在很多幻灯片里见过这个 @Composable 注释
它实际的作用是什么？
我想在这里重点指出一下
Compose 并不是注解处理器
Compose 是通过 Kotlin 编译器插件来运行的
我们在 Kotlin 中的 tight checking 阶段
和代码生成阶段进行工作
这期间不涉及注解
这里的注解其实更接近语言关键词
我想用类比的方式来描述它 也就是 suspend 关键词
Kotlin 的 suspend 关键词作用于方法类型
也就是说 你的方法可以声明为 suspend
我们可以有 lambda 也可以有类型
Compose 的工作原理也是类似的
我们可以转变方法类型

Korean: 
그저 여러분의 지적 호기심을 채워드리는
정도의 역할이에요
또한, 만약에 이에 대해서 더 깊이
알고 싶으시다면
입문하시기에 적절한 내용이 될 겁니다
슬라이드를 보시면 @Composable
어노테이션이 많이 보이죠
과연 이것의 역할이 무엇일까요?
중요한 점을 짚어드리자면
Composer는 어노테이션
프로세서가 아니라는 겁니다
Composer는 Kotlin 
컴파일러 플러그인으로 작동합니다
그리고 Kotlin의 엄격한 체크 단계와
코드 생성 단계에서 작업이 수행되죠
따라서 어노테이션 프로세스는 없습니다
여기서의 어노테이션은 사실 
언어 키워드와 좀 더
관련이 있는데요
비유적 측면에서 설명해드리겠습니다
suspend 키워드입니다
Kotlin의 suspend 키워드는
함수 타입으로 작동합니다
이는 suspend인 함수선언이
있다는 뜻인데요
lambda도 있고
type도 있어요
Compose도 같은 방법으로 작동합니다
함수의 종류를 바꿀 수 있죠

Portuguese: 
Vou fazer isso para satisfazer
a curiosidade intelectual de vocês.
Além disso, se vocês
quiserem se aprofundar
e conhecer o que está acontecendo,
esse é um começo.
Vemos essa anotação @Composable
em vários slides.
O que ela realmente faz?
Quero destacar um ponto importante aqui.
O Compose não é um
processador de anotações.
O Compose trabalha por meio de um
plug-in do compilador do Kotlin.
Nós trabalhamos na fase
de verificação
e na fase de geração de código do Kotlin.
Não há nenhum processo de
anotação acontecendo.
A anotação aqui está
mais relacionada
a uma palavra-chave da linguagem.
Vou descrevê-la em termos de
uma analogia, que
é a palavra-chave "suspend".
Ela opera em tipos de função.
Você pode ter uma declaração de função
com "suspend".
Podemos ter um lambda.
Podemos ter um tipo.
O Compose funciona da mesma forma.
Podemos alterar tipos de função.

Japanese: 
やろうとしていることは
ここにいる皆さんの知的好奇心を
満たすことです
また 真剣に取り組んで
中味を理解しようとしてくれるのは
良いきっかけになると思います
この@Composableアノテーションが
スライドにたくさん出てきます
実際どのような働きを
するのでしょうか？
重要なことですが Composeが
アノテーションを処理するのでは
ありません
Composeが働くのは
Kotlinコンパイラプラグインを通してです
Kotlinの厳しい型チェックフェーズと
コード生成フェーズで
Composeを使います
ここでは
アノテーション処理は起こりません
アノテーションは
言語のキーワードとより密接に
関係しています
そこで アナロジーとして
「suspend」というキーワードを
考えてみます
Kotlinのキーワードsuspendは
関数タイプに作用します
関数の宣言でsuspendが
使えるということです
lambdaもあります
typeもあります
Composeも同じように
働きます
関数タイプを変更できます

Indonesian: 
Saya hanya mencoba
memuaskan
keingintahuan
intelektual Anda.
Jika kita mau belajar
lebih lanjut dan
memahami prosesnya,
ini bisa menjadi awal yang baik.
Anotasi @Composable
ada di banyak slide.
Apa sebenarnya fungsinya?
Poin penting perlu
disampaikan di sini,
Compose bukan
pemroses anotasi.
Compose bekerja melalui
plugin compiler Kotlin
Kita bekerja di
fase pemeriksaan ketat
dan fase pembuatan kode Kotlin.
Jadi tidak terjadi
pemrosesan anotasi.
Anotasi di sini
lebih terkait dengan
kata kunci bahasa.
Saya akan menjelaskannya
melalui analogi, yaitu
kata kunci "suspend".
Kata kunci suspend Kotlin
bekerja pada jenis fungsi.
Artinya, Anda dapat memiliki
deklarasi fungsi yang adalah suspend.
Kita bisa punya lambda.
Kita bisa punya jenis.
Cara kerja Compose sama.
Kita bisa mengubah
jenis fungsi.

English: 
What I'm trying to
do is to satisfy
your intellectual
curiosity here.
And also, if you really
want to dive into this
and understand what's happening,
this is a good primer.
So we see this @Composable
annotation in a lot of slides.
What is it actually doing?
I want to make an
important point here,
which is that Compose is
not an annotation processor.
How Compose works is through
a Kotlin compiler plugin.
And we work in the
tight checking phase
and in the code generation
phase of Kotlin.
So there's no annotation
processing happening.
The annotation here is
actually more closely related
to a language keyword.
So I'm going to describe it
in terms of an analogy, which
is the "suspend" keyword.
Kotlin's suspend keyword
operates on function types.
This means that you can have
a function declaration that's
a suspend.
We can have a lambda.
We can have a type.
Compose works in the same way.
We can alter function types.

Spanish: 
Mi objetivo es satisfacer
su curiosidad intelectual.
Si quieren profundizar sobre el tema
y comprender los procesos,
esta es una buena introducción.
Vemos esta anotación "@Composable"
en muchas diapositivas.
¿Para qué sirve?
Aquí quiero dejar algo en claro.
Compose no es un procesador de anotaciones.
Compose trabaja mediante
un complemento de compilación de Kotlin.
Nosotros trabajamos
en la fase de verificación limitada
y en la de generación de código de Kotlin.
Así que no se procesan anotaciones.
Esta anotación tiene más que ver
con una palabra clave del lenguaje.
Voy a describirla con una analogía,
que es la palabra clave "suspend".
La palabra clave "suspend"
de Kotlin opera en tipos de función.
Es decir, pueden tener una declaración
de función que es una suspensión.
Podemos tener una lambda o un tipo.
Compose funciona igual.
Podemos alterar tipos de función.

English: 
And the important point
here is that, when
you annotate a function
type with that composable,
you're changing that type.
So the same function type
without the annotation
is not compatible with the
type with the annotation.
It's a different type.
Additionally, suspend
requires a calling context.
This means that you can only
call Suspend functions inside
of another Suspend function.
Composable works
the exact same way.
And this is because
there's a calling
context object that we
need to thread through all
of the invocations.
And so I'm going to talk
about what that object is.
What is this calling
context thing
that we're passing around?
And why do we need to do it?
Well, the implementation
of this object
actually has some
data structures in it
that are very closely related
to an existing data structure
called the "gap buffer."
Most of you probably aren't
familiar with gap buffers.
But if you work with text
editors, you might know them.
They're commonly used there.
So to describe what
a gap buffer is--

Spanish: 
Lo importante es que,
cuando anotan un tipo de función
con esa función componible,
están cambiando ese tipo.
El mismo tipo de función sin la anotación
no es compatible con el tipo
que tiene la anotación.
Es otro tipo.
Además, la suspensión requiere
un contexto de llamada.
Es decir, solo pueden llamar
a funciones de suspensión
dentro de otra función de suspensión.
La función componible funciona igual.
Se debe a que hay un objeto
de contexto de llamada que debemos encadenar
mediante todas las invocaciones.
Voy a explicar qué es ese objeto.
¿Qué es ese contexto de llamada
que estuvimos pasando?
¿Y por qué debemos hacerlo?
La implementación de este objeto
contiene algunas estructuras de datos
que están muy relacionadas
con una estructura de datos existente
llamada "búfer de espacio".
Quizás no muchos
conozcan los búferes de espacio.
Si trabajan con editores de texto,
tal vez sí los conozcan.
Se suelen usar allí.
Para describir el búfer de espacio…

Chinese: 
这里的重点在于 当你使用 Composable 
来为功能类型进行注解时
你实际上是在改变这个类型
没有注解的情况下 同样的方法类型
是无法和有注解的类型兼容的 类型不同
此外 suspend 还要求有一个调用语境
也就是说 你只能在一个 suspend 方法内部调用另一个 suspend 方法
Composable 的工作原理也是类似的
这是因为 我们需要把一个调用语境对象穿过所有调用
下面我就来谈谈 这个对象是什么
我们来回传递的这个调用语境是什么
为什么我们需要这么做
这个对象的实现内部其实有一些数据结构
非常接近现有的一个数据结构 gap buffer
很多人可能还不熟悉 gap buffer 是什么
使用过文本编辑器的人可能会知道它
因为它在文本编辑器中比较常用
下面我来解释一下 gap buffer 是什么

Japanese: 
ここで重要な点は
関数タイプを
composableでアノテートとすると
そのタイプを変更していることに
なります
したがって 同じ関数タイプで
アノテーションのないものは
アノテーションがあるものとの
互換性がありません
違うタイプです
また suspendには
呼び出しコンテキストが必要です
つまりsuspend関数は
別のsuspend関数からしか
呼べません
Composableも
全く同じように働きます
これは
呼び出しすべてで
呼び出しコンテキストオブジェクトを
スレッドする
必要があるからです
そのオブジェクトがどのようなものか
説明します
この呼び出しコンテキストオブジェクトとは
どんなものでしょうか？
そして なぜ必要なのでしょうか？
このオブジェクトの実装には
実はその中に
すでにあるデータ構造と密接に
関連した
データ構造があります
「gap buffer」です
gap bufferのことを知っている人は
あまりいないと思います
テキストエディタを扱ったことのある人は
ご存知かもしれません
そこでよく使われます
gap bufferについて説明しましょう

Korean: 
여기서 중요한 점은
함수의 종류를 composable로
어노테이션하면
종류를 바꾸게 된다는 거죠
따라서 같은 종류의 함수라도
어노테이션이 없으면
어노테이션이 있는 종류와
호환되지 않습니다
다른 종류가 되는 거예요
그리고 suspend에는
호출 컨텍스트가 필요합니다
즉 또 다른 suspend 함수에서만
suspend 함수를 호출할 수 있어요
Composable도 바로 그러한
방식으로 작동합니다
이는 모든 인보케이션을 통해
thread해야 하는
호출 컨텍스트 객체가
있기 때문이죠
그럼 이제 객체가 무엇인지 말씀드릴게요
우리가 보내고 있는 호출 컨텍스트란
무엇일까요?
그리고 왜 필요한 걸까요?
객체 구현에는 데이터 구조가 있는데
이는 "gap buffer"라고 불리는
기존 데이터 구조와
상당히 관련되어 있습니다
gap buffer가 생소한 분들도
많으실 텐데요
Text Editor로 작업하신다면
아마 아실 겁니다
그 분야에서 종종 사용되니까요
gap buffer를 설명해 드리자면

Portuguese: 
O importante aqui é que, quando
anota um tipo de função
com a função combinável,
você está mudando esse tipo.
O mesmo tipo de função sem a anotação
não é compatível com o
tipo, com a anotação.
É um tipo diferente.
Além disso, "suspend"
exige um contexto de chamada.
Isso significa que você só pode
chamar funções "suspend" dentro
de outra função "suspend".
Uma função combinável funciona
da mesma foma,
porque há um objeto de contexo
de chamada que precisamos encadear
por meio de todas
as invocações.
Vou falar, então, sobre esse objeto.
O que é esse contexto de chamada
que estamos passando?
E por que precisamos fazer isso?
A implementação desse objeto
contém estruturas de dados
que estão muito relacionadas a
uma estrutura de dados já existente
chamada "buffer de lacunas".
Muitos talvez
não conheçam os buffers de lacunas.
Se trabalha com
editores de texto, talvez conheça.
Eles são usados lá com frequência.
Vou descrever
o que é um buffer de lacunas.

Indonesian: 
Poin pentingnya adalah
saat menganotasi jenis fungsi
dengan composable itu,
Anda mengubah
jenis tersebut.
Jenis fungsi yang sama
tanpa anotasi
tidak kompatibel dengan
jenis yang beranotasi.
Jenisnya berbeda.
Suspend juga perlu
konteks pemanggilan.
Anda hanya bisa
memanggil fungsi Suspend
dalam fungsi Suspend lain.
Cara kerja Composable
persis sama.
Ini karena ada objek
konteks panggilan
yang perlu diteruskan
ke semua
pemanggilan.
Saya akan membahas
apa objek itu.
Apa itu konteks panggilan
yang sering kita masukkan?
Kenapa itu perlu dilakukan?
Implementasi objek ini
punya beberapa
struktur data di dalamnya
yang terkait erat dengan
struktur data yang ada
yang disebut "gap buffer".
Mungkin Anda tidak
tahu gap buffer.
Mungkin Anda tahu jika
bekerja dengan editor teks
bahwa ini umum digunakan.
Untuk menjelaskan gap buffer --

English: 
a gap buffer really
implements a list.
It's a collection interface.
And it has a current
index or cursor.
And the way we implement this
is with a flat array in memory.
And so that flat array
is necessarily larger
than the collection of
data that it represents.
And so the space in that
array that's unused we
refer to as the gap.
Now, as we execute our
Composable hierarchy,
we can appeal to
this data structure.
And we can insert
things into it.
And so you can think of the
cursor as your current point
of execution in your hierarchy.
And so as we go
through execution,
we can insert items, insert
another one, insert items.
So now, let's imagine that we're
done executing the hierarchy.
At some point, we're
going to go and we're
going to re-compose something.
And so we're going to reset
the cursor to the top.
And then we're going to go
through execution again.

Portuguese: 
Ele implementa uma lista.
É uma interface de coleta.
Ele tem um índice ou cursor atual.
Implementamos isso com
uma matriz fixa na memória.
Essa matriz fixa é necessariamente maior
do que a coleta de
dados que ela representa.
Chamamos de lacuna o espaço nessa
matriz que não é usado.
Quando executamos nossa
hierarquia combinável,
podemos usar essa estrutura de dados.
Podemos inserir coisas nela.
Pensem no cursor como o ponto de
execução atual da sua hierarquia.
Conforme avançamos na execução,
podemos inserir itens, inserir outro...
Agora, vamos imaginar que acabamos
de executar a hierarquia.
Em algum ponto, vamos ter que
recombinar algo.
Vamos redefinir o cursor
na parte superior.
Depois, vamos para a execução novamente.

Korean: 
리스트를 구현하는 역할을 합니다
이건 컬렉션 인터페이스인데요
현재 인덱스, 즉 커서가 있습니다
메모리의 flat 배열로 이걸 구현합니다
따라서 보이는 컬렉션 데이터보다
flat 배열이 더 커야겠죠
이 배열에서 사용되지 않는 부분을
gap이라고 부릅니다
Composable 계층을 실행함에 따라
이 데이터 구조를 호출할 수 있는데요
여기에 항목을 입력할 수 있어요
커서가 있는 곳이 현재 계층에서 실행되고
있는 지점으로 보면 됩니다
실행하면서
항목을 차례로 넣을 수 있죠
이제 계층을 실행하는 걸 끝냈다고 
가정해볼게요
어떤 시점에서인가 어느 부분을
recompose하게 되었습니다
커서를 다시 맨 위로 리셋합니다
그리고 다시 실행을 시작하죠

Chinese: 
它是用来实现列表的
它可以算是集合接口
它有一个当前索引或指针
我们通过在内存中使用扁平数组来实现它
这个扁平数组自然要比它所代表的数据集要大一些
数组中未使用的空间就被我们称为 gap
当我们执行 Composable 层级的时候
我们可以启动这个数据结构
可以在它之中插入一些东西
你可以把指针看作层级中的当前执行点
随着我们开始执行
我们可以在其中插入多个项 
现在 假如我们已经把层级执行完毕了
那么我们总要在某个时候开始重构某些东西
我们要把指针重新设定到顶部
然后再走一遍执行流程

Japanese: 
gap bufferはリストをインプリメントします
インターフェースのコレクションです
また 現在のインデックスあるいは
カーソルがあります
インプリメントの方法は
メモリにフラットな配列をつくるだけです
フラット配列の大きさは 
格納するデータコレクションの長さより
必ず長くします
配列のうち
使われていない部分のことを
gapと呼んでいます
Composable階層を実行するとき
このデータ構造を活用することが
できます
ここにものを入れることが
できます
カーソルが実行中の現在位置を
を示していると
考えることができます
実行していく中で
アイテムを次々に挿入できます
階層の実行が終わったとします
ある時点で 何かを
再composeします
そこで カーソルを先頭に
リセットします
そしてまた 実行します

Spanish: 
En realidad, implementa una lista.
Es una interfaz de colección.
Tiene un índice o cursor actual.
Lo implementamos
con un arreglo plano en la memoria.
Ese arreglo plano
es necesariamente más grande
que la colección de datos que representa.
Así, al área sin usar en el arreglo
la llamamos el espacio.
A medida que ejecutamos
la jerarquía de funciones componibles,
podemos recurrir
a esta estructura de datos
y podemos insertar cosas en ella.
Piensen que el cursor es el punto actual
de ejecución en su jerarquía.
Mientras avanzamos con la ejecución,
podemos insertar elementos,
insertar otro, insertar elementos.
Supongamos que terminamos
de ejecutar la jerarquía.
En algún punto, tendremos
que recomponer algo.
Vamos a restablecer el cursor
en la parte superior
y a repetir la ejecución.

Indonesian: 
gap buffer menggunakan daftar.
Ini antarmuka koleksi.
Dan punya indeks atau
kursor saat ini.
Cara implementasinya dengan
array datar di memori.
Array datar lebih besar
dari koleksi data
yang diwakilinya.
Ruang di array
yang tidak digunakan
disebut gap.
Saat eksekusi
hierarki Composable,
kita bisa menggunakan
struktur data ini.
Kita bisa menyisipkan
berbagai hal ke dalamnya.
Bayangkan kursor
sebagai titik eksekusi saat ini
di dalam hierarki.
Saat eksekusi dilakukan,
item bisa disisipkan
beberapa kali.
Bayangkan kita sudah
mengeksekusi hierarki.
Di titik tertentu,
kita akan
mengomposisi ulang sesuatu.
Kita akan menyetel ulang
kursor ke bagian atas.
Lalu, kita melakukan
eksekusi lagi.

Portuguese: 
Neste ponto, podemos fazer algumas coisas.
Podemos analisar os dados que estão lá.
Podemos não fazer nada, se quisermos.
Podemos atualizar o valor.
Ou decidir que a estrutura
da IU precisa ser alterada.
Depois queremos fazer uma inserção.
Isso é importante.
Neste ponto, queremos mover a lacuna
para a posição atual.
Agora, podemos fazer
inserções neste ponto.
Continuamos a fazer inserções.
Sobre a estrutura de dados,
é importante saber
que todas as operações de
que acabamos de falar,
receber, mover, inserir, excluir,
todas elas são operações constantes,
com exceção do movimento da lacuna,
que é algo caro.
Escolhemos esta estrutura de dados
porque estamos fazendo uma aposta:
apostamos que IUs, na média,
não mudam muito de estrutura.
Quando temos IUs dinâmicas, elas
mudam em termos
dos valores que incluem.
A estrutura não muda.

Japanese: 
この時点で いくつかのことが
できるようになります
そこにあるデータを
見ることができます
何もしなくてもよいし
値の更新もできます
あるいは UIの構造を変えることも
できます
挿入することもできます
重要なところです
この時点で gapを
現在の位置まで
動かせます
そのポイントに
挿入することができます
続けて 挿入することができます
このデータ構造に関して
理解しておかなければならないのは
get move insert deleteなどの操作はすべて
一定時間操作であると言うことです
gapを動かすこと以外です
gapを動かすのは大変です
このデータ構造を選んだ理由は
賭けをしているからです
UIは平均的に あまり構造が変化しない
と予想しています
ダイナミックなUIでは
値という点では変わります
しかし 実際には構造は
変化しません

English: 
And at this point, we're
able to do a few things.
We can look at the
data that's there.
And we can do
nothing, if we decide.
We can update the value.
Or we can decide that the
structure of the UI is changed.
And then we want
to make an insert.
So this is the important thing.
At this point, what we
do is we move the gap
to the current position.
And now, we're able to
make inserts at that point.
So we keep going,
keep making inserts.
Now, the important thing to
understand about this data
structure is that all of the
operations that we just talked
about-- get, move,
insert, delete--
all of those are
constant time operations,
except for moving the gap.
Moving the gap is
the expensive thing.
So the reason we chose
this data structure
is because we're making a bet.
The bet is that UIs, on
average, don't actually
change structure very much.
When we have dynamic
UIs, they change in terms
of the values that are there.
But they don't actually
change in structure.

Spanish: 
En este punto, tenemos algunas opciones.
Podemos observar los datos
o no hacer nada, si no queremos.
Podemos actualizar el valor.
O podemos decidir que la estructura
de la IU cambió.
Entonces, hacemos una inserción.
Lo importante es que,
en este punto, movemos el espacio
a la posición actual.
Ahora podemos hacer inserciones en ese punto.
Sigan avanzando y haciendo inserciones.
Lo que deben entender
sobre esta estructura de datos
es que todas las operaciones que mencionamos,
como obtener, mover, insertar, borrar,
son operaciones de tiempo constantes,
excepto mover el espacio,
que es lo costoso.
Elegimos esta estructura de datos
porque tenemos una apuesta.
Apostamos que las IU, en promedio,
no cambian tanto de estructura.
Cuando tenemos IU dinámicas,
cambian en términos
de los valores que incluyen,
pero no en estructura.

Chinese: 
这次 我们就可以做到几件事
我们可以观察那里的数据
也可以什么都不做
我们可以更新数值
也可以决定 UI 结构改变了 并插入新项
重点是 现在 我们可以把 gap 移动到当前位置
现在我们可以在那个点所在的位置插入项了
于是 我们不断执行 不断插入新项
这个数据结构的一个重点在于
我们刚才提到的所有操作
包括获取 移动 插入 删除 
这些都属于恒定时间操作
只有移动 gap 这个操作例外
移动 gap 的代价很大
我们选择这个数据结构的原因是
我们在赌
我们认定 UI 的结构通常不会发生大的变动
动态 UI 更改的是其中的数值
结构是不变的
更改结构的时候 会一次更改很多

Indonesian: 
Di sini, kita bisa
melakukan beberapa hal.
Bisa melihat data
yang ada di sana.
Tidak melakukan apa pun,
jika mau.
Bisa memperbarui nilai.
Atau bisa memutuskan
untuk mengubah struktur UI.
Lalu, kita melakukan
penyisipan.
Jadi ini penting.
Di titik ini, kita
memindahkan gap
ke posisi saat ini.
Kini kita bisa melakukan
penyisipan pada titik ini.
Kemudian,
kita terus melakukan penyisipan.
Sekarang, yang perlu dipahami
tentang struktur data ini,
adalah semua operasi tadi,
yaitu mengambil, memindah,
menyisipkan, dan menghapus
adalah operasi waktu konstan,
kecuali memindahkan gap.
Memindahkan gap adalah
operasi yang mahal.
Alasan kami memilih 
struktur data ini adalah
karena kami bertaruh.
Kami bertaruh bahwa
UI rata-rata tidak banyak
mengubah struktur.
Ada UI dinamis,
yang mengubah nilai
yang ada di sana,
tapi tidak mengubah
struktur.

Korean: 
이때 우리가 할 수 있는 것이 
몇 가지 있는데요
그 자리에 있는 데이터를 볼 수 있습니다
아무것도 하지 않을 수도 있죠
값을 업데이트할 수도 있고요
혹은 UI 구조를 바꿀 수도 있습니다
그 다음 삽입을 합니다
이건 상당히 중요한데
이 시점에서 우리는 gap을 현재 위치로
옮깁니다
그러면 이제 그 지점에 삽입을
할 수 있어요
계속 삽입을 해보죠
이 데이터 구조를 이해하는데 중요한 점은
방금 언급한 모든 활동이
이를테면 데이터를 얻고 움직이고
삽입하고 삭제하는
이 모든 것이 지속적인 time
operation이라는 겁니다
gap을 움직일 때를 제외하고요
gap을 움직이는 건 값이 비싸죠
따라서 이 데이터 구조를 선택한 이유는
우리가 베팅을 하고 있기 때문입니다
이 베팅이란 평균적으로 UI가 거의
구조 변화를 하지 않는다는 겁니다
동적 UI가 있다면 거기 있는 값에
따라 변화를 하게 되죠
하지만 구조는 변화가 없어요

Indonesian: 
Jika struktur diubah, biasanya
dalam potongan besar.
Memindahkan gap saat itu
adalah suatu kompromi.
Oke -- lihat
contoh ini.
Ada penghitung di sini.
Ini kode yang akan ditulis.
Ini contoh dari
sebelumnya.
Mari lihat fungsi
compiler.
Saat melihat anotasi
Composable ini,
kita menyisipkan
parameter tambahan.
Kita memasukkan
objek Composer ini.
Objek Composer berisi
buffer gap ini.
Saya juga menyebutnya
dengan istilah slot table.
Bayangkan ini sebagai
hal yang sama.
Kita menyisipkan panggilan
ke body Composable ini.
Kita menyebutnya
metode composer.start.
Kita memasukkannya
ke dalam kunci ini.
Nanti kita bahas.
Kita juga
memasukkan
objek Composer itu
ke semua pemanggilan
composable yang ada
di body fungsi ini.

Korean: 
만약 변화를 한다 치면, 
아주 큰 규모로 변화합니다
따라서 그 시점에 gap을 움직이는 건
아주 좋은 거래를 하는 것이죠
이 예시를 보도록 할까요
여기에 카운터가 있습니다
이건 우리가 쓰려는 코드고요
이전에 보셨던 예시입니다
컴파일러가 어떤 역할을 하는지 보실까요
이 Composable 
어노테이션을 보시면
사실상 추가적인 매개변수를
이 함수에 삽입하는 거죠
그래서 이 Composer 객체를
보내고요
이 Composer 객체는 
이를테면 gap buffer를
포함하는 거나 마찬가집니다
제가 slot table이라고 
부르기도 하는데요
같은 것으로 생각하시면 됩니다
호출을 이 Composable의
body에 삽입하고
composer.start 메서드를
호출할 겁니다
그리고 이 키로 전달합니다
이건 조금 후에 다시 말씀드리고요
우리가 하는 또 다른 일은
Composer 객체를 
함수 body에 있는 모든
composable 
invocations에
전달하는 겁니다

English: 
And when they do, they
typically change in big chunks.
And so doing this gap move at
that time is a good trade-off.
OK-- so let's look
at this example.
We have the counter here.
And this is the code
that we would write.
This is the example
from earlier.
Well, let's see what
the compiler does.
So when we see this Composable
annotation, what we do
is we actually insert additional
parameters into this function.
And so we pass in this
Composer object through.
And that Composer object
is what kind of contains
this gap buffer thing.
You also might hear me
refer to it as a slot table.
Just think of it
as the same thing.
And so we also insert some calls
in the body of this Composable.
So we're going to call
this composer.start method.
And we're going to
pass it in this key.
And I'm going to talk
about that in a second.
Another thing that
we're doing is
we're passing that
Composer object
into all of the composable
invocations that are
in the body of this function.

Portuguese: 
Quando acontece, a mudança
é em grandes partes.
Esse movimento de lacuna neste
momento é uma boa troca.
Vejamos um exemplo.
Temos o contador aqui.
Este é o código que criaríamos.
Este é o exemplo anterior.
Vamos ver o que o compilador faz.
Quando vemos esta anotação combinável,
inserimos parâmetros
adicionais nesta função.
Passamos esse objeto do Composer.
Ele contém o buffer de lacunas.
Talvez vocês me ouçam chamá-lo
de tabela de slots.
Mas são a mesma coisa.
Também inserimos algumas chamadas
no corpo desta função combinável.
Vamos chamá-la de método composer.start.
Vamos passá-lo nesta chave.
Já vou falar sobre isso.
Outra coisa que vamos fazer é
passar esse objeto do Composer
para todas as invocações que estão
no corpo desta função.

Japanese: 
構造が変わる場合は 普通
大きなかたまりで変化します
したがって その時点でgapを動かすのは
ちょうどよいトレードオフになっています
では この例を見ていきましょう
ここにCounterがあります
コードはこのようになっています
以前の例と一緒のものです
コンパイラが何をするか
見てみましょう
このComposableアノテーションを
見てみると
この関数に追加でパラメータを
挿入しています
そして このComposerオブジェクトを
渡します
そのComposerオブジェクトは
gapバッファを
含んでいます
スロットデーブルと言うこともあります
同じものだと
考えてください
このComposableの本体に
呼び出しをいくつか挿入します
ここでcomposer.startメソッドを
呼びます
このキーで渡します
これについては
すぐ後で話します
もう一つやっていることに
そのComposerオブジェクトを
この関数の本体にあるcomposableな呼び出し
全部に
渡しています

Chinese: 
所以 当时我们认为移动 gap 是划得来的
我们来看这个例子
这里有一个 counter
这是我们要写的代码
这是之前的例子
我们来看看编译器会怎么做
在看到这个 Composable 注解的时候
我们会在这个功能中插入额外的参数
我们传入了这个 Composer 对象
而这个 Composer 对象中包含了这个 gap buffer
我也可能会将其称为 slot table
二者的含义其实是差不多的
我们还在这个 Composable 的主体中插入了一些调用
我们将这个方法命名为 composer.start
我们传入这个 key 这个稍后再讲
我们还把那个 Composer 对象传入了
这个方法主体内部的所有 Composable 调用

Spanish: 
Y cuando sí cambian, lo hacen
en fragmentos grandes.
El movimiento de espacio 
vale la pena en ese momento.
Veamos este ejemplo.
Tenemos el contador.
Este es el código que escribiríamos.
Es el ejemplo anterior.
Veamos qué hace el compilador.
Cuando vemos esta anotación componible,
lo que hacemos es insertar
parámetros adicionales en la función
y pasamos este objeto de Composer.
Ese objeto de Composer es lo que contiene
el búfer de espacio.
Tal vez me escuchen llamarlo
"tabla de ranuras".
Son lo mismo.
También insertamos algunas llamadas
en el cuerpo de esta función componible.
Llamamos al método composer.start
y pasamos esta clave.
Lo explicaré en unos minutos.
Otra cosa que hacemos
es pasar el objeto de Composer
a todas las invocaciones componibles
del cuerpo de esta función.

Japanese: 
全体にスレッドしているのです
ここにキーがあります
任意に見える整数です
これの正しい捉え方は
これらの整数は
この呼び出しサイトが表す
ソース位置のハッシュを表す
ということです
これはそれぞれの呼び出しサイトに
一意のものです
このcomposableの実行を
追っていくと
まずStartを呼び出します
Startはスロットテーブルに
グループオブジェクトを挿入します
そして
Stateを呼び出します
Stateはその独自のグループオブジェクトを
挿入します
そのStateが返す値が
stateのインスタンスになります
それをまたスロットテーブルに
格納します
そしてButtonに移ります
Buttonもまた グループを
格納します
そのパラメータをそれぞれ格納します
Buttonの実装の仕方は
任意です
私たちも詳しくありません

Korean: 
그러니까 thread하는 거죠
여기 키가 있습니다
무작위로 보이는 정수들이죠
하지만 정확히 이해하려면
이 호출 지점이 나타내는
소스 위치의 해시를 
나타낸다고 생각해야 합니다
각 호출 지점마다 고유한 거죠
그래서 이 composable을 실행하면
Start를 호출하게 됩니다
그럼 Start가 slot table에 
그룹 객체를 삽입해요
실행합니다
State를 호출하고요
State가 고유한 그룹 객체를
삽입합니다
그럼 state가 돌려보내는 값이
state 인스턴스죠
이것도 slot table에 저장합니다
이제 Button으로 넘어가죠
Button도 그룹을 저장합니다
그리고 각 매개변수도 저장하죠
Button은 또한 이런 임의 구현을
할 수도 있습니다
확실히 알 수는 없지만요

Portuguese: 
Então, nós as agrupamos.
E temos estas chaves aqui.
Estes são os números inteiros
que parecem arbitrários.
A maneira de pensar nisso de forma correta
é como uma representação, por exemplo,
de um hash da posição de origem
que este local de chamada representa.
É exclusiva a cada local de chamada.
Quando passamos pela execução
desta função combinável,
chamamos Start,
que insere um objeto de grupo
na tabela de slots.
Avançamos, chamamos State.
State insere o próprio objeto de grupo.
Depois, o valor que State retorna
é uma instância de estado.
Isso também é armazenado
na tabela de slots.
Depois passamos para Button.
Button vai armazenar um grupo também.
Ele vai armazenar cada um dos parâmetros.
Button pode ter essa
implementação arbitrária.
Não sabemos ao certo.

Chinese: 
把它散布到各处
这里还有一些 key
这些看起来像是随机的整数
但其实它们代表的是这个调用点所代表的源位置的哈希值
每个调用点对应的值都不同
当我们仔细查看这个 Composable 的执行情况时
我们会调用 Start
然后 Start 会把一组对象插入到 slot table
然后 我们再调用 State
State 会插入它自己的群对象
随后 这个状态返回的数值就被叫做状态实例
它也会把它保存到 slot table 里
下面我们来看看 Button
Button 也会储存一个群组
它会存储每个参数
Button 可能会进行随机实现 我们不太了解
它还会在这个时间段内使用 slot table

Indonesian: 
Jadi, kita seperti
menyisipkannya.
Ada kunci ini di sini.
Ini bilangan bulat
yang tampak acak.
Bayangkan
ini mewakili hash
dari posisi sumber
yang diwakili situs
panggilan ini.
Ini unik untuk
tiap situs panggilan.
Saat mengeksekusi
composable ini,
kita memanggil Start.
Start menyisipkan
objek grup ke slot table.
Selanjutnya,
kita memanggil State.
State menyisipkan
objek grup sendiri.
Lalu nilai yang dihasilkan state itu
adalah instance state,
yang juga menyimpannya
ke slot table.
Kita melanjutkan ke Button.
Button juga menyimpan grup.
Lalu, menyimpan 
tiap parameternya.
Button mungkin punya
implementasi arbitrer.
Kita kurang tahu.

Spanish: 
Lo vamos pasando.
Y tenemos estas claves.
Son enteros que parecen arbitrarios, pero,
más precisamente,
el entero representa un hash
de la posición original
que representa el sitio de llamada.
Es único para cada sitio de llamada.
Cuando avanzamos por la ejecución
de esta función componible,
seguimos y llamamos a Start.
Start inserta un objeto de grupo
en la tabla de ranuras.
Llamamos a State.
State inserta su propio objeto de grupo.
Luego, el valor que muestra State
es una instancia de estado.
Eso también se almacena
en la tabla de ranuras.
Pasamos a Button.
Button también almacenará un grupo.
Luego, almacenará cada uno de sus parámetros.
Quizás Button tenga
esta implementación arbitraria.
No lo sabemos.

English: 
So we're threading it through.
And we have these keys here.
So these are these
arbitrary looking integers.
But the way to think
about this correctly
is that this represents, like,
a hash of the source position
that this call site represents.
So this is sort of
unique to each call site.
So when we go through the
execution of this composable,
we go through and we call Start.
And Start inserts a group
object into the slot table.
We go through.
We call State.
State inserts its
own group object.
And then the value that state
returns is a state instance.
That also stores that
into the slot table.
Then we move onto Button.
Button is going to
store a group as well.
And then it's going to store
each of its parameters.
And Button might have this
arbitrary implementation.
We don't really know.

Korean: 
그 과정에서 slot table도 
사용합니다
작업이 끝나면 
composer.end를 호출합니다
보시면 이 데이터 구조가 
전체 컴포지션으로부터의
모든 객체를 보유하고 있다는 걸
알 수 있어요
실행 명령의 전체 구조라고 볼 수 있죠
마치 깊이 우선 순회 구조 같이요
그럼 우리가 본 모든 그룹 객체들은
무슨 용도일까요?
공간을 많이 차지하잖습니까?
사실 이 그룹 객체는
동적 UI에서 일어나는 이동과 삽입을
관리하는데 무척 중요합니다
하지만 우린 컴파일러죠
따라서 여러분의 UI 구조를 바꾸는
코드가 어떻게 생겼는지
사실 알고 계실 겁니다
따라서 때에 따라 이 그룹을 
삽입할 수 있습니다
대부분의 경우 이게 필요하지 않다고
느끼게 되죠
따라서 slot table에
그렇게 많은 그룹을
삽입할 필요는 없어요

English: 
And it's going to also use the
slot table during that time.
And when it's done, we're going
to then call composer.end.
And so you can see here
that this data structure
is holding all of these objects
from this whole composition.
And it's sort of the entire
tree in execution order.
It's like a depth first
traversal of the tree.
Now, all of those group
objects that we just saw--
what are they there for?
They're taking up a
lot of space, right?
So actually, those
group objects are really
important to manage the moves
and the inserts that might
happen with the dynamic UI.
But we're a compiler.
So we actually know what
code looks like that changes
the structure of your UI.
So we can conditionally
insert those groups.
And most of the time, we
find that we don't actually
need them.
So we don't actually have
to insert that many groups
into the slot table.

Japanese: 
その間 スロットテーブルも
使います
終わると composer.endを
呼びます
このデータ構造で
このコンポジション全体の
オブジェクトが全部
保持されていることがわかります
実行の順番のツリー全体の
ようなものです
ツリーのトラバーサルのようなものです
では 今まで見てきたグループオブジェクトは
すべて
何のためにあるのでしょうか？
スペースもたくさんとっていますよね？
実際 これらのグループオブジェクトは
ダイナミックUIで生じるmoveやinsertを
管理するのに重要な役目を果たします
しかし コンパイラです
UIの構造を変えるコードが
どんなものかは分かっています
したがって 条件付でそのような
グループを挿入できます
大抵の場合 必要になることは
あまりありません
スロットテーブルにグループをたくさん
挿入する必要はあまりありません

Indonesian: 
Ini juga menggunakan
slot table saat itu.
Jika selesai, kita
memanggil composer.end.
Lihat bahwa struktur data ini
menyimpan semua objek
dari seluruh komposisi.
Ini semacam struktur pohon
urutan eksekusi,
seperti algoritme
depth first traversal dari pohon ini.
Semua objek grup yang
baru kita lihat --
apa gunanya di sana?
Semua objek itu
menghabiskan ruang.
Sebenarnya,
objek grup itu sangat penting
untuk mengelola
pemindahan & penyisipan
yang mungkin terjadi
dengan UI dinamis.
Tapi kita adalah compiler.
Kita tahu seperti apa
kode yang akan mengubah
struktur UI Anda.
Kita bisa menyisipkan grup
itu secara bersyarat.
Biasanya, kita tidak
memerlukannya.
Kita tidak harus
menyisipkan grup sebanyak itu
ke slot table.

Portuguese: 
Ele também pode usar a tabela
de slots nesse ponto.
Quando isso é feito, chamamos
composer.end.
Vocês podem ver aqui que
esta estrutura de dados
mantém todos esses objetos
de toda essa composição.
É quase toda a árvore
em ordem de execução.
É como a primeira travessia da árvore.
Todos esses objetos de grupo
que acabamos de ver...
para que eles servem?
Eles ocupam muito espaço.
Na verdade, esses objetos de grupo são
importantes para gerenciar os movimentos
e as inserções que podem
acontecer com a IU dinâmica.
Mas somos compiladores.
Sabemos como é o código que muda
a estrutura da sua IU.
Podemos inserir, condicionalmente,
esses grupos.
Na maior parte do tempo, descobrimos que
não precisamos deles.
Não temos que inserir esses vários grupos
na tabela de slots.

Chinese: 
在完成后 我们会调用 composer.end
大家可以看到 这个数据结构
把所有对象和整个 Composition 隔离开了
它有点像是执行序列的整个代码树
像是深度优先的树遍历
我们刚刚看到的这些群组对象
它们存在的意义是什么？
它们占用的空间可真不少 对吧？
其实 这些群组对象是用来管理那些
可能在动态 UI 中发生的动作和插入
但是 我们现在是编译器
我们知道那些能够改变你的 UI 结构的代码是什么样子
所以 我们可以依照特殊条件插入群组
大多数时候 我们发现 我们其实不需要它们
我们不需要在 slot table 中插入那么多的群组

Spanish: 
También usará la tabla de ranuras
durante ese tiempo.
Cuando haya terminado,
llamaremos a composer.end.
Pueden ver que esta estructura de datos
contiene todos estos objetos
de toda la composición.
Es casi todo el árbol en orden de ejecución.
Es como un recorrido en profundidad.
Ahora, todos los objetos de grupo que vimos…
¿Para qué sirven?
Ocupan mucho espacio, ¿no?
De hecho, esos objetos de grupo
son muy importantes para administrar
los movimientos y las inserciones
que podrían ocurrir con la IU dinámica.
Pero somos un compilador.
Sabemos cómo es el código que cambia
la estructura de la IU.
Podemos insertar esos grupos con condiciones.
La mayoría del tiempo,
vemos que no los necesitamos realmente.
Así que no tenemos que insertar tantos grupos
en la tabla de ranuras.

Indonesian: 
Sebagai contoh kasus,
mari lihat logika
kondisional di sini.
Ini Composable.
Ada fungsi getData yang
menampilkan hasil
dan merender composable
pemuatan di satu kasus,
serta header dan body
di kasus lain.
Di sini, kita menyisipkan
kunci terpisah
untuk cabang pertama
pernyataan if
dan cabang kedua.
Selanjutnya,
kita mengeksekusinya
-- saat pertama berjalan,
hasilnya nihil.
Lalu, kita menjalankan
layar pemuatan.
Saat kedua kali dijalankan,
anggap item feed
adalah hasilnya.
Jadi, tidak nihil.
Di titik ini,
kita masuk cabang kedua
pernyataan if.
Di sini terjadi
hal menarik.
Di titik ini,
panggil composer.start.
Dan objek ini punya grup
dengan kunci 456.
Objek ini juga melihat bahwa
grup 123 di slot table tidak cocok.

Korean: 
그런 예시를 하나 보죠
조건부 로직이 있습니다
Composable도 있고요
이 getData 함수는 
결과를 돌려 보내주고
하나의 케이스에서는 loading 
composable을 렌더링하고
또 다른 케이스에서는 header와
body를 렌더링합니다
여기 보시면 별개의 키들을 
if 명령문의
첫 번째 가지에 넣고
두 번째 가지에도 넣어요
그리고 실행시키면
첫 번째 결과는 null이라고 합시다
그리고 loading screen을 
실행하면
두 번째에서는
저 FeedItem이 결과라고 해보죠
null이 아니에요
이 지점에서 if 명령문의 두 번째
가지로 가보죠
여기서 재미있는 일이 발생했는데
composer.start를
호출합니다
키 456이 있는 그룹이 있네요
그리고 slot table의 123 그룹과는
맞지 않아 보입니다

Spanish: 
Para ver un ejemplo de un caso
donde sí lo hacemos,
observemos esta lógica condicional.
Una función componible.
Tiene esta función getData
que muestra un resultado
y renderiza una función componible
de carga en un caso
y un cuerpo y un encabezado en otro.
Vemos que estamos insertando claves separadas
para la primera rama de la instrucción if
y la segunda rama.
Cuando vamos a ejecutar…
En la primera ejecución el resultado es nulo.
Entonces, ejecutamos la pantalla de carga.
En la segunda ejecución,
imaginemos que ese elemento
del feed es el resultado.
No es nulo.
En este punto, iremos a la segunda rama
de la instrucción if.
Aquí es donde se pone interesante.
Llamamos a composer.start.
Tiene un grupo con la clave 456.
Ve que el grupo en la tabla de ranuras de 123
no coincide.

Portuguese: 
Para mostrar um exemplo
em que fizemos isso,
temos uma lógica condicional aqui.
Aqui está uma função combinável.
Ela tem esta função getData
que retorna um resultado
e processa uma função combinável
de carregamento em um caso e um
cabeçalho e um corpo em outro.
Aqui, vemos que estamos inserindo
chaves separadas
para o primeiro branch
da instrução "If"
e o segundo branch.
Quando executamos...
na primeira execução, o resultado é nulo.
Então, executamos a tela de carregamento.
Na segunda execução, vamos
imaginar que esse item de feed
seja o resultado aqui.
Ele não é nulo.
Neste ponto, vamos para o segundo branch
da instrução "if".
Aqui é onde fica interessante.
Chamamos composer.start.
Ela tem um grupo com a chave 456.
E vê que o grupo na tabela
de slots de 123
não corresponde.

English: 
To show an example of
a case where we do,
let's look at some
conditional logic here.
So here's a Composable.
It has this getData function
that returns some result
and renders a loading composable
in one case and a header
and a body in another case.
So here, we see that we're
inserting separate keys
for the first branch
of the if statement
and the second branch.
And when we go
through and execute
it-- let's say, the first time
this runs, the result is null.
And so then we go and we
run the loading screen.
Now the second time
we run it, let's
pretend that feed item
is the result here.
So it's not a null.
And at this point, we're going
to go into the second branch
of the if statement.
And so this is where the
interesting thing happens.
At this point, we
call composer.start.
And it has a group with key 456.
And it sees that the group
in the slot table of 123
doesn't match.

Japanese: 
挿入する必要がある場合の例として
ここの条件付きロジックを見てみましょう
Composableがあって
このgetData関数は 何らかの
結果を返し
ある場合は
composableをロードし
また ある場合は ヘッダーやボディを
ロードします
すなわち if文の最初の分岐と
2番目の分岐で
別々のキーを
挿入していることが
わかります
その後 それを実行すると
これが初めて実行されたとき
結果はnullです
そこで ロード画面に行って
2回目に これを走らせると
フィードアイテムが
ここの結果だとします
nullでない結果です
この時点で if文の2番目の分岐に
入ります
ここで面白いことが起こります
ここで composer.startを
呼び出しています
キーが456であるグループがあります
スロットテーブルのキーが123の
グループとは
マッチしません

Chinese: 
举一个我们采取的动作的例子
我们来看几个条件逻辑
这里是一个 Composable
它的这个 getData 方法可以返回一些结果
有时 它会渲染一个加载 Composable
有时 它会渲染出数据头和本体
这里我们可以看到 我们在为 if 语句的
首个分支和第二个分支添加几个 key
当我们执行时 比方说 它第一次运行时 结果为空
然后 我们运行加载屏幕
第二次运行时 我们假装 feed 项就是结果吧
它不是空值
此时 我们可以进入这个语句的第二个分支
然后 有意思的事发生了
这时 我们调用 composer.start
它有一个群组 外加一个 key 456
它发现 slot table 123 中的群组无法适配

Korean: 
따라서 UI에 구조 변화가 생겼음을
알게 되죠
그럼 이제 gap을 현재
커서가 있는 자리로 옮깁니다
그리고 UI가 있었던 자리로 gap을
확장시킵니다
지우는 거죠
그리고 새로운 UI와 header, 
body를 삽입합니다
이 경우에 if 명령문의
오버헤드가 slot table의
단일 slot entry였던 겁니다
이 그룹이었죠
이 단일 그룹을 삽입하게 되면
우리가 UI를 실행시키면서
UI 내부에
임의의 제어 흐름을 갖고서
관리하게 해주며
캐시와 비슷한 데이터 구조를 
호출하도록
만들어주는 겁니다
이 개념은 우리가
Positional Memoization
이라고 부르는 것입니다
이는 새로운 개념이죠
하지만 이 개념은 Composer가
만들어진 처음부터 
그 토대 역할을 했어요

Japanese: 
それで UIが構造を変えたことが
わかります
そこで gapを現在のカーソルの
位置まで動かします
そして UIがあった場所に
ギャップを拡張します
処分するわけです
新しいUI Header Bodyを挿入します
この場合if文のオーバーヘッドが
スロットテーブルの
単一のスロットエントリだったと
見ることもできます
このグループでした
この一つのグループを
挿入することによって
UIの任意のフローを
コントロールできるようになり
UIを実行する中で
UIの管理や
キャッシュのようなデータ構造に
アピールできるようになります
このコンセプトを
位置的メモ化（Positional Memoization）と
呼んでいます
位置的メモ化は新しいコンセプトです
Composeはこのコンセプトをもとに
新規に作られました

Spanish: 
Ahora, sabe que la IU
cambió en la estructura.
Entonces, movemos el espacio
a la posición actual del cursor.
Luego, extendemos el espacio por la IU
que estaba antes.
La eliminamos.
Insertamos la nueva IU,
el encabezado y el cuerpo.
Una forma de analizar esto
es la sobrecarga de la instrucción if.
En este caso, fue una entrada
de ranura simple en la tabla
y fue este grupo.
La inserción de este grupo simple
nos permite tener un flujo de control
arbitrario en nuestra IU,
y administrarla y recurrir
a esta estructura de datos similar a la caché
a medida que avanzamos
por la ejecución de la IU.
Este concepto es algo que llamamos
"memorización posicional".
La memorización posicional
es un concepto nuevo,
pero es a partir del cual
se creó Compose.

Chinese: 
现在它知道 UI 的结构已经改变了
我们把 gap 移动到当前的指针所在位置
然后 我们把 gap 延伸到之前的 UI 的内部各处
从而抛弃之前的 UI
现在我们插入新的 UI 数据头和主体
可以这么说 在这里 if 语句的开支
是 slot table 中的那个 slot 项
它就是这个群组
通过插入这一个群组 它就可以让我们
在 UI 中拥有任意控制流
并让我们管理它 并向这个像缓存一样的数据结构进行展示
同时执行 UI
我们把这个概念称为 Positional Memoization 
Positional Memoization 是新生事物
但是 其实 Compose 就源于这个概念

Indonesian: 
Jadi ia sekarang tahu bahwa
UI telah berubah struktur.
Kita memindahkan gap ke
posisi kursor saat ini.
Kita meluaskan gap
di UI
yang ada di sana
sebelumnya.
Kita menyingkirkannya.
Lalu kita menyisipkan UI,
header, dan body baru.
Kita bisa melihat bahwa
overhead pernyataan if,
dalam hal ini,
adalah satu entri slot
di slot table.
Itulah grup ini.
Dengan menyisipkan
satu grup ini,
kita punya alur kontrol arbitrer
di UI dan bisa
mengelolanya dan menggunakan
struktur data yang
seperti cache ini,
saat melanjutkan
eksekusi UI.
Konsep ini
disebut Positional Memoization.
Positional Memoization
adalah hal baru.
Namun inilah konsep yang
mendasari pembangunan Compose,
dari bawah ke atas.

Portuguese: 
Ela sabe que a estrutura da IU mudou.
O que fazemos é mover a lacuna
para a posição atual do cursor.
Depois, estendemos a lacuna pela IU
que já estava lá.
Nós nos livramos dela.
Agora, inserimos a nova
IU, o cabeçalho e o corpo.
Uma forma de analisar isso é
a sobrecarga da instrução "if".
Nesse caso, foi uma
entrada de slot simples
na tabela de slots.
Foi esse grupo.
Com a inserção desse grupo simples,
é possível ter um fluxo de controle
arbitrário na IU, gerenciá-lo e usar
esta estrutura de dados
semelhante a cache,
enquanto avançamos
na execução da IU.
Esse conceito é algo que chamamos
de "memoização posicional".
Isso é algo novo.
Mas foi a partir
desse conceito que o Compose
foi criado.

English: 
So now it knows that the UI
has changed in structure.
So what we do is we move the gap
to the current cursor position.
And then we extend
the gap across the UI
that was there before.
So we kind of get rid of it.
And now we insert the new
UI, the header and the body.
And so one way to look at
this is the overhead of the if
statement, in this case,
was a single slot entry
in the slot table.
And it was this group.
And by just inserting this
single group, what this does
is this allows us to
have arbitrary control
flow in our UI and allows
us to manage it and appeal
to this cache-like
data structure,
while we move through
the execution of the UI.
And so this concept
is something that we
call Positional Memoization.
And Positional Memoization
is a new thing.
But this is the concept
that Compose is built from,
from the ground up.

Portuguese: 
Quero falar sobre isso.
Memoização parece uma palavra sofisticada.
Vou explicar o significado dela.
Normalmente, temos memoização global.
Memoização significa que estamos
colocando em cache o
resultado de uma função
com base nas entradas dessa função.
Um exemplo de memoização posicional
aqui poderia ser... temos este cálculo
que fazemos em vez de
uma função combinável.
Pegamos alguns items de
string e uma consulta.
E executamos um tipo de
operação de filtro.
Podemos unir este cálculo
em uma chamada para memo.
Podemos passar os itens e a
consulta para essa chamada.
Com a memoização, é possível saber
como usar a tabela de slots.
Ela analisa os itens.
E não há nada ali.
É a primeira vez que a executamos.
Então, ela só a armazena.
Analisamos a consulta e a armazenamos.
Depois executamos o cálculo.
Armazenamos o resultado
e o retransmitimos.

Indonesian: 
Saya mau membahas
artinya.
Memoization terdengar
agak keren.
Biasanya, ada
global memoization.
Memoization artinya
menyimpan cache
hasil fungsi
berdasarkan input
fungsi tersebut.
Contoh
positional memoization
adalah -- ada komputasi
yang kita kerjakan,
bukan fungsi Composable.
Kita mengambil beberapa
item string dan kueri.
Kita melakukan
operasi filter di situ.
Kita bisa menggabungkan
kalkulasi ini dalam panggilan ke memo.
Kita bisa memasukkan item
dan kueri ke panggilan itu.
Memo tahu cara
menggunakan slot table.
Memo melihat item.
Dan tidak ada apa-apa
di sana.
Ini pertama kali kita
menjalankannya.
Jadi ia hanya menyimpannya.
Kita melihat kueri.
Kita menyimpannya.
Lalu, kita menjalankan
kalkulasi.

English: 
And I want to talk
about what this means.
So memoization is kind
of a fancy sounding word.
Normally, we have
global memoization.
And what memoization
means is that we
are caching the
result of a function
based on the inputs
of that function.
So an example of
positional memoization
here might be-- we
have this computation
that we're doing instead
of a Composable function.
We're taking in some
string items and a query.
And we're performing some sort
of a filter operation on it.
We can wrap this calculation
in a call to memo.
And we can pass in items
and query to that call.
And so memo is
something that knows how
to appeal to the slot table.
And what it does is
it looks at items.
And there's nothing there.
This is the first
time we're running it.
So all it does is just store it.
And we look at query.
We store that.
And then we run the calculation.

Chinese: 
我来讲解一下它的含义
Memoization 这个词听起来很厉害
但是它的意思其实就是
通常 我们有的是全局化的 Memoization
Memoization 的含义就是
我们基于方法的输入 对方法的结果进行缓存
Positional Memoization 的一个例子就是
我们正在这个 Composable 方法里进行一个运算
我们在引入一些字符串和查询
我们在其基础上进行一些过滤操作
我们可以把这个运算封装进 memo 调用里
我们可以把 items 和 query 传入这个调用
memo 知道如何使用 slot table
它会观察若干个项
但那里什么都没有 我们才第一次运行它
所以它只是储存而已
我们观察查询 储存它
然后我们运行运算 并储存结果 再将其传回

Japanese: 
これがどういう意味か説明します
メモ化というのは 何か
空想的な響きのある言葉ですが
グローバルなメモ化というのが
普通です
メモ化の意味は
その関数の入力に基づいて
結果をキャッシュする
ということです
したがって
位置的メモ化というのは
Composable関数のかわりに
この計算を私たちがやるということです
文字列やクエリに対して
フィルター操作のようなことを
行います
メモへの呼び出しの中で
この計算をラップします
そして アイテムやクエリの中に入れて
呼び出しに渡します
したがって メモは
スロットテーブルにアピールする
方法が分かっているものです
それが何をするかというと
アイテムを見ることです
最初に実行したときには
何もありません
やることは
それを格納することだけです
そして クエリを見て
それを格納します
そして 計算を実行します
結果を格納したら
それを返します

Spanish: 
Voy a hablar sobre qué significa eso.
"Memorización" es una palabra elegante.
Normalmente, tenemos la memorización global.
Memorización quiere decir
que almacenamos en caché
el resultado de una función
según las entradas de esa función.
Un ejemplo de memorización personal…
Tenemos este cómputo que hacemos
dentro de una función componible.
Tomamos algunos elementos
de string y una consulta.
Ejecutamos un tipo de operación de filtro.
Podemos unir este cálculo
en una llamada a memo,
y podemos pasar elementos
y una consulta a esa llamada.
Memo es algo que sabe
cómo recurrir a la tabla de ranuras.
Lo que hace es analizar los elementos.
No hay nada.
Es la primera vez que la ejecutamos.
Entonces, solo los almacena.
Analizamos la consulta y la almacenamos.
Luego, ejecutamos el cálculo.

Korean: 
이게 무슨 뜻인지 말씀드릴게요
Memoization은 멋진 단어로 들리죠
일반적으로 global
memoization이 있습니다
Memoization은 다시 말해 
함수의 input에 기반해서
그 함수의 결과를
캐시해준다는 뜻이에요
positional 
memoization의 예를 들어보면
여기 Composable 함수 대신에
계산한 값이 있죠
문자열 아이템과 쿼리가 있네요
여기에 필터를 작동시켜볼까요
메모로 보내는 호출에서 
계산을 래핑할 수 있습니다
그 호출로 아이템과 쿼리를 전송하죠
따라서 메모는 어떻게 
slot table로
호출할지 알고 있습니다
이제 메모는 아이템을 보고
그 안에 아무것도 없다는 걸 알게 되죠
이게 첫 번째로 실행한 거예요
따라서 메모는 그냥 저장만 합니다
이제 쿼리를 보고
저장을 합니다
그리고 계산을 돌려요

Chinese: 
这没问题
不过 我们第二次运行它的时候 有意思的事发生了
我们再次运行它的时候 memo 查看了传入的新数值
并比较了之前传入的旧数值
如果二者均未改变 我们就可以跳过运算
直接返回之前的结果
这就是 Positional Memoization 
有意思的是 这个功能的开销很低
我们只需存储一个之前的调用
这个运算可能会发生在你的 UI 内部的各处
而你会定点 (Positionally) 储存它
也就是说 只会在那个位置储存它
这里是 memo 方法的签名
memo 可以取用任意数量的输入
以及某种运算方法
这里还有一个有趣的退化案例
它涉及了当输入为零时发生的情况
我们可以刻意误用这个 API

Korean: 
결과를 저장한 다음
다시 전달합니다
아무런 문제가 없었죠
하지만 두 번째로 실행할 때에는
아주 재미있는 일이 벌어집니다
다시 실행하면 메모는
전달되는 새로운 값을 보고서는
이전 값과 비교를 해요
만약 둘 중에 어느 것도 바뀌지 않았다면
계산을 생략하고 이전 결과를 보내는데
이게 positional
memoization입니다
흥미로운 점은 이 비용이
무척 저렴하다는 거죠
그저 이전 인보케이션
하나만 저장하면 됩니다
이러한 계산은 여러분의 UI 전체에서
일어날 수 있어요
위치에 따라 저장하는 겁니다
다시 말해 그 위치에 맞게만
저장하는 거죠
이것이 Memo 함수의 특징입니다
Memo는 여기에 있는
어떤 숫자의 input이나
어떤 종류의 계산 함수도 
수행할 수 있죠
하지만 흥미롭게도 별 도움이 안 되는
경우도 있는데요
바로 input이 zero일 때입니다
이때 우리는 API를 고의적으로
오용하면 됩니다

Japanese: 
こんな感じです
しかし 2回目に実行したときには
面白いことが起こります
もう一度実行すると
メモは
渡されている値が
違うのがわかり
古い値と比較します
どちらも変化していなければ
計算をスキップして
ただ 前の値を返すだけです
これが位置的メモ化です
面白いことは
本当にチープなところです
前の呼び出しを１個だけ
記憶しておくだけでよいのです
この計算はUIすべてで起こる
可能性があります
そして 位置的にそれを格納します
その位置専用に格納するのです
これがメモ関数のシグネチャーです
ここのメモは入力の数は何でもよく
計算関数の一種です
ただし おもしいろい縮退例が
あります
入力がない場合です
このAPIの
間違った使い方をわざと
やることがあります

Portuguese: 
Tudo certo aqui.
Na segunda execução,
algo interessante acontece.
Quando executamos novamente, memo
analisa os novos valores que
estão sendo transmitidos
e os compara com os valores antigos.
Se nenhum valor mudou,
podemos ignorar o cálculo e voltar
para o resultado anterior.
Essa é a memoização posicional.
O interessante aqui é que
isso é realmente barato.
Evitamos ter que armazenar uma
invocação anterior.
Esse cálculo pode acontecer
em toda a sua IU.
O armazenamento está ligado à posição,
é apenas para aquele local.
Essa é a assinatura da função Memo.
Ela aceita qualquer número de entradas
e um tipo de função de cálculo.
Há um caso de degeneração
interessante aqui,
que é quando há zero entradas.
Uma das coisas que podemos fazer é usar
indevidamente a API de maneira deliberada.

Spanish: 
Almacenamos el resultado
y lo volvemos a pasar.
Funcionó.
Pero en la segunda ejecución,
ocurre algo interesante.
En una nueva ejecución, memo
analiza los nuevos valores que se pasan
y los compara con los valores antiguos.
Si ninguno cambió,
podemos omitir el cálculo y mostrar
el resultado anterior.
Eso es la memorización posicional.
Lo interesante
es que fue muy económico hacerlo.
Solo tuvimos que almacenar
una invocación previa.
Este cálculo puede ocurrir en toda su IU.
Lo almacenan de forma posicional,
por lo que solo se almacena
para esa ubicación.
Esta es la característica de la función memo.
Puede tomar cualquier cantidad de entradas
y algún tipo de función de cálculo.
Hay un caso degenerado interesante aquí,
que ocurre cuando hay cero entradas.
Podemos hacer un uso inadecuado
de esta API deliberadamente.

English: 
And we store the result.
And then we pass it back.
So that was fine.
But the second
time we execute it,
that's when the
interesting thing happens.
So when we execute
it again, memo
goes and looks at the new
values that are being passed in
and compares them
with the old values.
And if neither of them
have changed, then
we can skip the
calculation and just return
the previous result. And so
that's positional memoization.
But the interesting thing here
is that it was really cheap.
We only had to store
one previous invocation.
And this calculation could
happen all over your UI.
And you're storing
it positionally.
So it only stores it
for that location.
And this is the signature
of the Memo function.
Memo here can take
any number of inputs
and then some sort of
calculation function.
But there is an interesting
degenerate case here,
which is when there
are zero inputs.
One of the things we can
do is we can deliberately
misuse this API.

Indonesian: 
Kita menyimpan hasil.
Lalu kita memasukkannya kembali.
Proses ini tidak masalah.
Tapi saat kedua kita
mengeksekusinya,
terjadi hal menarik.
Saat kita mengeksekusinya lagi,
memo melihat nilai baru
yang dimasukkan
dan membandingkannya
dengan nilai lama.
Jika tidak ada yang
berubah,
kita bisa melewati
kalkulasi dan hanya
menampilkan hasil sebelumnya.
Inilah positional memoization.
Yang menarik, ini
sangat murah.
Kita hanya menyimpan
satu panggilan sebelumnya.
Kalkulasi ini bisa
terjadi di seluruh UI.
Anda menyimpannya
sesuai posisi.
Penyimpanan dilakukan
hanya untuk lokasi itu.
Inilah ciri khas
fungsi Memo.
Memo bisa mengambil
berapa pun jumlah input
dan suatu
fungsi kalkulasi.
Tapi ada kasus degenerasi
yang menarik,
yaitu saat tidak ada input.
Kita bisa dengan sengaja
menyalahgunakan API ini.

Japanese: 
わざと インピュアな計算を
メモ化します
たとえばMath.randomです
グローバルなメモ化で
これを行うのは
意味がありません
位置的メモ化で行うと
新しく意味を持ちます
Math.randomがここにあって
メモ化します
このxに値を保存します
composable階層でAppを用いるごとに
新しいMath.randomの値がそこに返されます
そのcomposableが再composeするごとに
同じMath.randomの戻り値になります
これにより パーシステンス（永続性）が
もたらされます
そして そのパーシステンスはstateを
生み出します
これが State関数のやっていることです
StateはStateコンストラクタまわりの
メモの呼び出しにすぎません
どういうことかと言うと
その呼び出しごとに
Stateの同じインスタンスを得ます
これがやりたいことです

Chinese: 
去保存一个刻意加入的非“纯净”运算
例如 math.random
如果你使用全局函数记忆来做这件事的话
就完全行不通
但是如果你使用 Positional Memoization 
它在语义上就行得通
现在我们有一个已经被函数记忆的 math.random
我们保存进一个数值 x
每次我们在 Composable 层级中使用这个时
都会有一个新的 math.random 值被返回到那里
但是 每当那个 Composable 重构的时候
都会返回相同的 math.random 值
从而导致持续性 而持续性会导致 state 
State 方法的真实作用就是这个
State 只是在 State 构造函数周围调用 memo 
也就是说 你会在它的每个调用中得到相同的实例状态
而这可以说就是我们想要的

Korean: 
의도적으로 impure한 계산을
memoize하는 건데요
예를 들어 math.random으로 
할 수 있겠네요
만약 global memoization을
사용하고 있었다면
성립되지 않았을 겁니다
하지만 positional 
memoization을 쓴다면
새로운 의미구조를 갖게 되죠
여기 보시면 memoize된
math.random이 있습니다
x값에 저장하죠
우리가 composable 계층에서 
앱을 실행할 때마다
새로운 math.random이 
돌아오게 됩니다
하지만 composable이
recompose할 때마다
같은 math.random 값이 
돌아오게 될 것이고
따라서 지속성이 올라가게 됩니다
지속성은 상태를 올리게 되죠
이게 바로 State 함수의
실제 역할이에요
State는 State 생성자의 주변에 
있는 메모에 호출할 뿐인데
이는 다시 말해
같은 인스턴스를 상태의 매 인보케이션마다
받게 될 거라는 뜻이에요
바로 우리가 원하는 것이죠

Portuguese: 
Podemos memoizar um cálculo
impuro intencionalmente,
por exemplo, math.random.
Se fizesse isso com essa
memorização global,
não faria sentido.
Mas, com a memoização posicional,
temos uma nova semântica.
Aqui, temos math.random, que é
memoizada.
Armazenamos nesse valor x.
Todas as vezes que usarmos App
na hierarquia combinável,
haverá um novo valor math.random
retornado aqui.
Toda vez que a função combinável
for recomposta,
teremos o mesmo valor de retorno
math.random.
Isso dá origem a uma persistência.
Essa persistência dá origem a um estado.
E isso é a função State,
apenas uma chamada para memo
no construtor State.
Isso significa que temos
a mesma instância de State em cada
invocação dele.
É isso o que nós queremos.

Spanish: 
Podemos memorizar
un cálculo impuro a propósito,
como math.random.
Si lo hicieran con la memorización global,
no tendría sentido.
Pero con la memorización posicional,
tenemos una nueva semántica.
Tenemos math.random, que se memorizó.
Almacenamos ese valor x.
Por cada vez que usemos
App en la jerarquía componible,
se mostrará un nuevo valor math.random aquí.
Pero cada vez que esa función
componible se recomponga,
tendremos el mismo
valor de retorno math.random.
Eso origina una persistencia.
La persistencia origina un estado.
Realmente, esto es la función State.
State es una llamada
para memorizar el constructor State.
Significa que obtendrán
la misma instancia de State
en cada invocación.
Es lo que buscamos.

Indonesian: 
Kita bisa mememoisasi kalkulasi
yang sengaja tidak murni,
seperti math.random.
Jika Anda melakukannya
dengan global memoization,
ini tidak masuk akal.
Dengan positional memoization,
ini seperti mengambil semantik baru.
Di sini ada math.random,
yang dimemoisasi.
Kita menyimpan nilai x.
Tiap kali menggunakan App
di hierarki composable,
akan ada nilai math.random baru
yang ditampilkan di sini.
Tiap kali composable itu
mengomposisi ulang,
nilai math.random yang
ditampilkan sama.
Yang dimunculkannya
adalah persistensi.
Persistensi akhirnya
memunculkan state.
Inilah sebenarnya
fungsi State.
State hanya panggilan ke memo
di seputar konstruktor State.
Artinya, Anda akan
mendapat instance state
yang sama tiap kali dipanggil.
Itulah yang kita inginkan.

English: 
We can memoize an intentionally
impure calculation,
like, say, math.random.
And if you were doing this
with global memoization,
this would make no sense.
But with positional
memoization, it
ends up taking a new semantic.
So here we have math.random,
which is memoized.
And we store in this value x.
And for every time we use App
in our composable hierarchy,
there will be a new math.random
value that's returned there.
But every single time that
composable re-composes,
it will be the same
math.random return value.
So what this gives rise
to is a persistence.
And that persistence ends
up giving rise to state.
And this is what the State
function actually is.
State is just a call to memo
around the State constructor.
And so what that
means is that you'll
get the same instance the state
across every invocation of it.
And that's what we want.

Japanese: 
それでは
Composable関数に
パラメータを保存する方法について
お話します
Google Composableがあります
数字を入力として持ちます
意味のある例ではありませんが
アドレスcomposableを呼びます
ここではアドレスだけを扱います
その下のテキストノードを
いくつか呼び出します
このデータが最終的に
どのようにスロットテーブルに
格納されるかを見ると
いくつか冗長性があることが
わかります
カリフォルニア マウンテンビューを
アドレスの呼び出しに加えると
下のテキスト呼び出しにも
格納されます
この冗長性をなくすには
Composable関数に
別のパラメータを
コンパイラレベルで
加えればよいことが
わかります
静的なパラメータに
なります
ビットフィールドで
与えられたパラメータが
ランタイムによって変化するかどうかが
示されています

Korean: 
그럼 이제 Composable 함수에
매개변수를 저장하는 방법으로
넘어가 볼까요
여기 Google Composable이
있습니다
숫자를 입력할 수 있는데요
웃긴 예시긴 하지만요
우리는 이걸 어드레스 
composable이라고 부릅니다
여기에 어드레스를 렌더링하고
아래에 있는 몇 개의 
텍스트 노드를 호출해요
이 데이터가 어떻게 slot table에
저장되는지 보면
불필요한 것들이 있다는 걸 알게 되지요
우리가 어드레스 인보케이션에 추가한
캘리포니아의 마운틴 뷰가
하단에 있는 텍스트 인보케이션에
저장됩니다
따라서 우리가 또 다른 매개변수를
Composable 함수에 
컴파일러 수준으로 추가하여
이러한 불필요한 부분을 
없앨 수 있다는 게 드러나죠
여기 정적 매개변수가 있습니다
런타임이 변화하지 말아야 하는 
매개변수로 인식하는지 여부를
가리키는 비트 구조체입니다

Spanish: 
Ahora, hablemos sobre cómo almacenamos
los parámetros de las funciones componibles.
Tenemos una función componible de Google
que toma un número.
Es un ejemplo simple.
Llamamos a una función
componible de dirección
y renderizamos una dirección.
Llamamos a unos nodos de texto debajo.
Cuando vemos cómo los datos
se almacenan en la tabla de ranuras,
notamos algunas redundancias.
"Mountain View", en "California",
que agregamos en la invocación de dirección,
se vuelve a almacenar
en las invocaciones del texto subyacente.
Resulta que podemos
eliminar esa redundancia
si agregamos otro parámetro
a las funciones componibles
en el nivel del compilador.
Tenemos el parámetro estático.
Este es un campo de bit que indica
si el tiempo de ejecución sabe
que un parámetro determinado no cambia.

Indonesian: 
Berikutnya, kita
membahas cara
menyimpan parameter ke
fungsi Composable.
Di sini ada Google 
Composable,
yang memasukkan nomor.
Contoh ini agak konyol.
Namun, kita memanggil
composable alamat.
Kita hanya merender
alamat di sini.
Kita memanggil beberapa
node teks di bawahnya.
Jika melihat data ini
akhirnya disimpan
di slot table,
kita melihat beberapa
redundansi.
Mountain View
di California
yang ditambahkan di
pemanggilan alamat
disimpan lagi dalam
pemanggilan teks
yang mendasarinya.
Ternyata kita bisa
menghilangkan redundansi
dengan menambahkan paramater lain
ke fungsi Composable
di tingkat compiler.
Di sini ada parameter statis.
Ini kolom bit yang
menandakan apakah
parameter tertentu diketahui
tidak berubah oleh runtime.

Portuguese: 
Vamos agora falar sobre como
armazenamos os parâmetros nas
funções combináveis.
Temos uma função combinável Google,
que recebe um número.
É um exemplo simples.
Chamamos uma
função combinável de endereços.
Processamos um endereço aqui.
Chamamos alguns nós de texto abaixo dele.
Quando analisamos como esses dados
são armazenados na tabela de slots,
vemos algumas rendundâncias.
Mountain View e Califórnia,
que adicionamos na invocação de endereço,
acabam sendo armazenados novamente
nas invocações de texto subjacentes.
Então, podemos
remover essa redundância
adicionando outro parâmetro
às funções combináveis no
nível do compilador.
Adicionamos o parâmetro Static.
Este é um campo de bits que
indica se um parâmetro
é reconhecido pelo ambiente
de execução como imutável.

English: 
So let's move into
talking about the way
that we store the parameters
to Composable functions.
So here, we have a
Google Composable,
which takes in a number.
This is kind of a silly example.
But we're calling an
address composable.
And we're just rendering
an address here.
So we're calling a few
text nodes underneath it.
When we look at how
this data ends up
getting stored in
the slot table,
we end up seeing
some redundancies.
So the Mountain
View in California
that we added in the
address invocation
ends up getting stored
again in the underlying text
invocations.
So it turns out
that we can actually
get rid of this redundancy
by adding another parameter
to Composable functions
at the compiler level.
So here we have the
static parameter.
And this is a bit field that
indicates whether or not
a given parameter is known
by the runtime to not change.

Chinese: 
下面我们来谈谈我们是如何将参数存储到 Composable 方法中的
这里我们有一个 Google Composable
它会引入一个数字
这个例子看起来有点傻
我们现在调用一个 Address Composable
然后我们在这里渲染一个地址
在它下面调用几个文本节点
我们来看看这个数据最后是如何被储存在 slot table 里的
我们可以看到一些冗余
我们在地址调用中添加的加州 Mountain View 
最后再次被储存在基础文本调用里
我们可以消除这个冗余
具体做法就是 在编译器层级上
向 Composable 方法中添加另一个参数
这里是静态参数
这个字段可以表明 运行环境是否了解 
某个特定的参数是无法更改的

English: 
And if it's known to
not change, then there's
no need for us to store it.
So we can see here in
this Google example,
we can pass a bit field that
says, none of these parameters
are ever changing.
And then in Address, we
can do the same thing
and pass it into text.
Now all of this bit wise
logic is hard to read.
It's confusing.
And there's no intention
of you understanding this.
Compilers are good at this.
Humans aren't.
And this is exactly
the kind of thing
you want a compiler doing.
So let's go back to our
top level example here.
And we can see this
redundant information
that we no longer need to store.
But additionally, there
are all these values
that are constant here.
These are static values.
It turns out, we don't
need to store them either.
And so this entire hierarchy
is actually purely determined
by this one number parameter.

Portuguese: 
Se for reconhecido, não haverá
necessidade de armazená-lo.
Neste exemplo do Google, podemos
passar um campo de bits que diz que
nenhum desses parâmetros muda.
Em Address, podemos
fazer a mesma coisa
e passar no texto.
Toda essa lógica de bits é difícil de ler.
É confusa.
Vocês não precisam entender isso.
Os compiladores são bons nisso.
Os humanos, não.
Esse é exatamente o tipo de coisa
que vocês querem que um compilador faça
Vamos voltar para nosso exemplo aqui.
Podemos ver essas informações redundantes
que não precisamos mais armazenar.
Além disso, há todos esses valores
que são constantes aqui.
São valores estáticos.
O que acontece é que também
não temos que armazená-los.
Toda esta hierarquia é, 
na verdade, determinada
por este único parâmetro.

Japanese: 
変化しないことがわかってれば
格納する必要はありません
このGoogleの例でわかるのは
これらのパラメータはすべて
変化しないことを示している
ビットフィールドの
受け渡しができることです
アドレスでも同じことが可能で
テキストに渡すことができます
このビットごとのロジックは読みにくくて
紛らわしいものです
皆さんもわざわざ苦労して
理解したくもないと思います
コンパイラは得意です
人間は苦手です
このようなことは
コンパイラに
任せればよいのです
一番上の例に戻りましょう
この冗長性のある情報は
もう格納する必要はありません
ほかにも変わらない値が
あります
これらは静的な値です
これも格納する必要がないことが
わかっています
その結果 この階層全体は実は
この一つの数字パラメータで
決定されています

Indonesian: 
Jika diketahui tidak
berubah, kita tidak
perlu menyimpannya.
Di contoh Google ini,
kita bisa memasukkan
kolom bit yang menunjukkan,
tidak ada parameter
yang berubah.
Di Address, kita bisa
melakukan hal yang sama
dan memasukkannya
ke teks.
Semua logika bit ini
sulit dibaca.
Ini membingungkan.
Ini tidak dimaksudkan
untuk Anda pahami.
Compiler ampuh
dalam hal ini.
Manusia tidak.
Inilah tugas yang
perlu dilakukan compiler.
Mari kembali ke
contoh utama kita.
Kita bisa melihat
info redundan ini
yang tidak perlu lagi
disimpan.
Selain itu, ada nilai-nilai
yang konstan di sini.
Ada nilai statis.
Ternyata kita juga tidak
perlu menyimpannya.
Seluruh hierarki ini
sepenuhnya ditentukan
oleh parameter
satu nomor ini.

Spanish: 
Si no cambia,
no necesitamos almacenarlo.
Como vemos en este ejemplo de Google,
podemos pasar un campo de bit
que indica que ningún parámetro
va a cambiar.
En Address, podemos hacer lo mismo
y pasar el texto.
Toda esta lógica de bits es difícil de leer.
Es confusa.
No necesitan entender esto.
Los compiladores lo hacen muy bien,
pero los humanos, no.
Esto es precisamente
lo que un compilador debe hacer.
Volvamos a nuestro ejemplo.
Pueden ver esta información redundante
que no necesitamos almacenar.
Pero también tenemos todos estos valores
que son constantes.
Son valores estáticos.
Tampoco hay que almacenarlos.
Toda esta jerarquía
está determinada exclusivamente
por este parámetro de número.

Chinese: 
如果得知它是无法更改的 我们就无需保存它
我们可以在这个 Google 例子中看到
我们可以传入一个位字段 
其内容为 这些参数都不会改变
然后 在 Address 中 我们可以做同样的事
将其传入文本
这些逐位逻辑都很难读懂 令人迷惑
不过大家也不必搞懂它们
编译器擅长这项工作 人类不行
而这正是我们要交给编译器去做的工作
我们回到顶层范例
我们可以看到这条无需再保存的冗余信息
不过 此外 这些数值都是恒定的 都是静态值
其实 我们也不必储存它们
整个层级完全是通过这一个数字参数决定的

Korean: 
변화하지 말아야 한다고 인식한다면
저장할 필요가 없죠
이 Google 예시를 통해 알 수 있듯
매개변수가 변화하지 않는다고
알려주는 비트 구조체는
그냥 넘겨도 됩니다
그럼 Address에서 똑같이 해보고
텍스트로 전달해보죠
이 모든 비트 단위 로직은 
읽기가 어렵습니다
복잡하죠
이걸 이해하시려는 분은
안 계실 것 같네요
컴파일러야 물론 잘하겠지만
우리는 사람이니까요
바로 이럴 때 컴파일러가
필요할 겁니다
그럼 가장 좋은 예시로 돌아가 볼까요
저장할 필요가 없는 불필요한 정보들이
보이실 겁니다
하지만 또한 지속적인 값들도
있죠
이것이 정적 값입니다
이것도 저장할 필요가 없다는 게 드러나요
따라서 전체 계층은 순전히
이 하나의 매개변수로
확인할 수 있습니다

Chinese: 
而我们也只需存储这一个数值
不过 我们其实可以更进一步
我们可以生成一种代码
这种代码能够理解 数字是唯一将会改变的东西
我们可以这样说 如果数字没有改变
就不要做其他的任何操作 
只要跳过这个调用即可
Composer 完全知道要把执行快进到什么程度
才能在最合适的地点实现恢复
我最后想讲的一个概念是 
之前我们提到过的 Recomposition 是如何运作的
回到这个 counter
我们为这个 counter 生成的代码
如我们所见 有一个 composer.start 和 .end 
我之前提到过 无论我们何时执行 counter
运行时都会理解 当我调用 count.value 的时候

English: 
And that ends up being the only
value that we need to store.
But we can actually go further.
So we can generate
code that understands
that number is the only
thing that's going to change.
And so what we can say is,
well, if number hasn't changed,
don't bother doing
anything else.
Just skip this invocation.
And the composer
knows exactly how far
to fast forward the
execution to resume
exactly where it needs to.
So the final concept
I want to talk about
is explaining how this
recomposition happens
that we talked about earlier.
So going back to this
counter, the generated code
that we would create
for this counter
has a composer start and
end, like we've seen.
And what I mentioned earlier
is that, whenever we execute
Counter, the runtime
understands that when

Portuguese: 
É o único valor que precisamos armazenar.
Mas podemos ir mais adiante.
Podemos gerar um código que saiba
que esse número é a única
coisa que vai mudar.
Se o número não mudar,
não faça mais nada.
Basta ignorar essa invocação.
O Composer sabe exatamente o quanto
avançar na execução para retomar
exatamente onde é necessário.
O conceito final que quero mostrar
é como essa recomposição acontece,
conforme falamos anteriormente.
Voltando para esse contador,
o código gerado
que criamos para esse contador
tem um início e um final para o Composer,
conforme nós vimos.
O que eu mencionei mais cedo
é que sempre que executamos
o contador, o ambiente de execução
entende que, quando

Korean: 
이게 우리가 저장해야 하는 유일한 값이죠
한 발자국 더 나아가서
이 숫자가 변화할 수 있는 
유일한 요소임을
이해하는 코드도 만들 수 있습니다
숫자가 안 바뀌면
아무것도 하지 말고
이 인보케이션은 그냥 건너뛰어요
그럼 composer는
다시 실행해야 할 때까지
얼마나 건너뛰어야 하는지
정확히 알게 됩니다
말씀드리고 싶은 마지막 개념은
아까 보여드렸던 
recomposition이
어떻게 일어나는지에 관한 것입니다
이 카운터로 돌아가서,
이 카운터를 위해 생성한 코드엔
composer start와
end가 있죠
우리가 봤던 것처럼요
전에 말씀드렸듯이,
Counter를 실행하게 되면
런타임은 내가 그 값의 카운트를 호출하면

Spanish: 
Ese es el único valor que debemos almacenar.
Aunque podemos ir más allá.
Podemos generar código que entienda
que el número es lo único que va a cambiar.
Entonces, podemos decir que,
si el número no cambió,
no hay que hacer nada más.
Se omite esta invocación.
Composer sabe exactamente
cuánto avanzar la ejecución para reanudar
en el punto necesario.
El último concepto del que quiero hablar
es cómo ocurre la recomposición
que mencionamos antes.
Volviendo al contador, el código generado
que crearíamos para el contador
tiene un inicio y un final
para el Composer, como ya vimos.
Lo que mencioné antes es que,
cuando ejecutamos el contador,
el tiempo de ejecución
entiende que, cuando llamo
al conteo de ese valor, leo la propiedad

Indonesian: 
Nilai ini satu-satunya
yang perlu disimpan.
Tapi kita bisa
bertindak lebih lanjut.
Kita bisa membuat
kode yang memahami
bahwa hanya nomor
yang akan berubah.
Artinya, jika
nomor tidak berubah,
tidak perlu melakukan
hal lain.
Lewati saja
pemanggilan ini.
Composer tahu persis
cara mempercepat eksekusi
untuk kemudian
mulai menjalankan
operasi yang perlu.
Konsep terakhir yang
ingin saya bahas adalah
menjelaskan bagaimana
komposisi ulang yang
yang kita bahas sebelumnya
terjadi.
Kembali ke penghitung ini,
kode yang dihasilkan
yang perlu kita buat
untuk penghitung ini
punya awal dan akhir 
composer, seperti yang kita lihat.
Saya tadi mengatakan
bahwa setiap kali mengeksekusi
Counter, runtime
memahami bahwa saat

Japanese: 
この値さえ保存しておけば
よいことになります
さらに前に進みましょう
変化するのは数字だけだということを
理解するコードを生成することができます
すると 数字が変わっていなかったら
何もしなくてよいことになります
これを呼び出すのをやめることができます
また composerは
どこまで実行を先延ばしにして
どこで再開する必要があるかが
正確にわかっています
さて 最後にお話しするコンセプトは
少し前に話したrecompositionが
どのように起こるかということで
これについて説明します
このCounterの例に
戻ります
さっきも見ましたが
このCounterのコードには
composer startとendがあります
前に言ったのは
Counterを実行するときは常に
アプリのモデルインスタンスの
プロパティを読んで Counter値を

English: 
I call count that value, I'm
reading the property of an app
model instance.
And so at runtime, what happens
is whenever we call end,
we optionally return a value.
And then we can call an update
scope method on that value,
basically, with a lambda
that tells the runtime,
here's how to restart this
Composable if you need to.
And so this is sort of
equivalent to that lambda
that that live data would
be receiving otherwise.
And the reason that this
question mark is here--
the reason that
this is nullable--
is because, if we don't
actually read any model
objects during the
execution of Counter, then
there's absolutely no reason
to teach the runtime how
to update this, because we
know it never will update.
So some closing thoughts--
I want to emphasize again
that this is still really,
really early and, more
importantly, that this
isn't production ready.

Japanese: 
呼び出すと ランタイムは
それがわかるということです
そこで ランタイムで起こることは
endが呼ばれると
オプションで値を返すことです
その値に関してUpdate Scopeメソッドを呼びます
基本的にはLamdaを使ってランタイムに知らせます
必要に応じて このComposableを再起動します
ライブデータが受けるLambdaと
似たようなものです
ここにクエスチョンマークがある理由は
これがヌル化できる理由は
カウンターの実行中に
モデルオブジェクトを何も
読込まなかった場合
ランタイムにこれを更新する方法を
教える必要が全くないからです
更新されることは決してありません
最後に言っておきたいことですが…
まだ非常に初期段階にあって
まだ 製品段階には至っていない
ということを強調しておきたいと思います

Indonesian: 
memanggil count.value,
saya membaca
properti instance
model aplikasi.
Pada runtime, tiap kali
kita memanggil end,
kita secara opsional
menampilkan nilai.
Kita bisa memanggil metode
update scope di nilai itu,
dengan lambda yang
memberi tahu runtime
cara memulai ulang
Composable ini jika perlu.
Ini seperti lambda yang
diterima oleh data live.
Alasan adanya
tanda tanya ini --
penyebab nilai ini
bisa dinihilkan --
adalah jika kita tidak
membaca objek model
selama eksekusi Counter,
sama sekali tidak ada alasan
untuk mengajari runtime
cara mengupdate, karena
kita tahu ini tidak akan diupdate.
Sebagai penutup --
saya mau menekankan lagi
bahwa ini masih sangat awal
dan, yang lebih penting lagi,
ini belum siap untuk produksi.

Spanish: 
de una instancia de app modelo.
En el tiempo de ejecución,
cuando llamamos a end,
podemos mostrar un valor y llamar
a un método updateScope en ese valor
con una lambda que le indica
al tiempo de ejecución
dónde reiniciar la función
componible si es necesario.
Esto es equivalente a esa lambda
que recibirían los datos en vivo.
La razón por la que este signo
de interrogación es anulable
es que, si no leemos ningún objeto
de modelo durante la ejecución del contador,
no hay motivo para enseñarle
al tiempo de ejecución
como actualizarlo,
ya que sabemos que no se actualizará.
Algunas conclusiones…
Quiero volver a enfatizar que esto está
en una fase muy preliminar y que,
sobre todo, no está listo para producción.

Chinese: 
我是在读取一个应用模型实例的属性
在运行时中 无论我们何时调用 end
我们都可以选择返回一个数值
随后 我们可以针对这个数值调用一个更新范围方法
也就是 使用 lambda 告诉运行时
如果你需要的话 要这样重启 Composable 
这就相当于另一种情况下 LiveData 会收到的那个 lambda
至于这里为什么会出现问号 这里为什么是可空的
这是因为 如果我们不在执行 counter 的时候读取任何模型对象
那么就没必要告诉运行时应该如何更新它
因为我们知道 它永远不会更新的
最后的一些想法
我想再次强调一下 这些东西都还处于早期状态

Korean: 
앱 모델 인스턴스의 
프로퍼티를 읽는다는 걸
이해합니다
따라서 런타임에서는 우리가 
end를 호출할 때마다
선택적으로 값을 돌려보내죠
또한 그 값에 관한
업데이트 스코프 메서드 역시
런타임에게 어떻게 필요할 때마다 
Composable을 재시작할 수 있는지
알려주는 lambda를 통해서 
호출할 수 있습니다
따라서 이는 그렇게 하지 않았을 경우
lambda가 받았을
LiveData에 상응하는 것이라고
할 수 있겠네요
여기에 물음표가 있는 이유는
즉 이게 nullable인 이유는
우리가 Counter 실행 중 어떤 
모델 객체도 읽지 않는다면
런타임이 업데이트를 하지 않을 테니
어떻게 업데이트를 하는지 알려줄 필요가
전혀 없기 때문입니다
마지막으로 다시 강조하고 싶은 것은
오늘 다룬 내용은 정말 초기형이고
더 중요한 것은
출시될 준비가 되지 않았다는 점입니다

Portuguese: 
eu chamo a contagem para esse valor,
estou lendo a propriedade de uma
instância de modelo.
No ambiente de execução, sempre
que chamamos end,
podemos retornar um valor.
Depois, chamamos um método
de escopo de atualização nesse valor
basicamente com um lambda que
informa ao ambiente de execução
como reiniciar essa função
combinável, se precisar.
É equivalente a esse lambda
que os dados ao vivo receberiam.
Este ponto de interrogação
está aqui
e isto é anulável
porque, se não lermos nenhum objeto
de modelo durante a execução do
contador,
não haverá motivos para ensinarmos
o ambiente de execução a
fazer esta atualização, porque
sabemos que ela nunca ocorrerá.
Para encerrar...
Quero reforçar que isso ainda está
bem no começo e, o mais importante, que
não está pronto.

English: 
And we really mean that.
This is a really
big undertaking.
And we're really still exploring
a lot of these options.
And a lot of the things
I just talked about
are pretty new
explorations on our side.
And so I think it's
pretty interesting.
But just know that a
lot of these things
are still happening.
And we think there are some
really, really powerful ways
that we can really gain
some performance in a world
where we have
Composable functions.
But we're still exploring that.
The other thing I
want to point out
is that everything
we just talked
about that's being
done by the compiler
is required for correctness.
And there's an
interesting oversight
where code that uses
@Composable and things like that
compiles just fine with
the old Kotlin compiler.
There are some blogs
out on the internet
that say, hey, you don't
need Android Studio for--
and all that.
They're wrong.
[LAUGHTER]

Korean: 
정말입니다
아주 큰 규모의 작업이기 때문에
아직 여러 가지 선택을 고려하고 있어요
오늘 제가 말씀드린 것 대부분은 
저희 입장에서는
굉장히 새로운 부류의
탐험이라고 할 수 있습니다
그래서 여러분께 흥미로우리라 생각했고요
하지만 이 중에 많은 부분이
아직 진행 중이라는 점이 중요하죠
저희는 Composable 
함수를 사용할 때
상당히 강력한 퍼포먼스를 얻을
방법이 있을 거라 생각합니다만
아직 알아보고 있는 단계입니다
강조하고 싶은 또 하나의 점은
오늘 논의한 것들 가운데
컴파일러가 수행하는 일들은 모두
정확성을 위해 요청되었다는 점입니다
@Composable이나 그와 비슷한
것을 사용하는 코드에 대한
흥미로운 실수가 있었는데 그런 코드가
구형 Kotlin 컴파일러에서
문제없이 compile했다는 겁니다
인터넷에 보면 그것 때문에 
Android Studio를
쓸 필요가 없다고 하는 블로거들이
많은데요
잘못된 정보입니다
(웃음)

Indonesian: 
Kami serius.
Ini pekerjaan besar.
Kami masih mempelajari
banyak opsi ini.
Banyak hal yang baru
saya bicarakan
adalah eksplorasi baru
di pihak kami.
Menurut saya ini menarik.
Perlu diketahui,
masih banyak
yang perlu dilakukan.
Menurut kami ada
beberapa cara efektif
untuk mencapai
performa yang bagus
dengan fungsi Composable.
Tapi kami masih
mempelajarinya.
Hal lain perlu
disampaikan,
semua yang baru dibahas
yang sedang dilakukan
oleh compiler,
diperlukan untuk ketepatan.
Ada kekeliruan yang menarik
di mana kode yang menggunakan
@Composable dan semacamnya
dapat melakukan kompilasi tanpa masalah
dengan compiler Kotlin lama.
Ada beberapa blog
di internet
yang bilang, Anda tidak
perlu Android Studio --
karena berbagai hal.
Mereka salah.
[SUARA TAWA]

Spanish: 
Lo decimos en serio.
Es un gran proyecto.
Aún estamos explorando
muchas de estas opciones.
Varias cosas que mencioné
son investigaciones nuevas que realizamos.
Si bien es muy interesante,
sepan que muchos de estos conceptos
están en desarrollo.
Creemos que hay algunas formas muy poderosas
de obtener rendimiento en un mundo
donde tenemos las funciones componibles.
Pero seguimos explorando.
Otra cosa que quiero destacar
es que todo lo que dijimos
que realiza el compilador
necesita corrección.
Hubo un descuido interesante
en el que el código
que usa @Composable y similares
se compila bien con el antiguo
compilador de Kotlin.
En algunos blogs de Internet,
afirman que no se necesita Android Studio.
No es cierto.

Chinese: 
更重要的是 说老实话 这些东西还没有做好投产准备
这是一个雄心勃勃的项目
我们还在摸索很多选项
刚才我谈到的东西 很多都是最近的探索成果
我认为这些东西相当有趣
请大家注意 探索工作仍在进行中
我们认为 大家可以通过一些强有力的方式
在多种 Composable 方法存在的环境中获取性能表现的提升
不过我们目前仍在摸索之中
我想指出的另一点是 
我们刚刚提到的所有由编译器完成的工作
都是达成正确性所必须的
有一个有趣的意外
使用 @Composable 的代码
在旧版的 Kotlin 编译器中能够流畅地进行编译
网上的一些博客文章声称
开发者不需要 Android Studio (就能使用这个功能)
这种说法是错误的

Japanese: 
本当です
本当に大掛かりな仕事です
まだ いろいろなオプションを
試している段階です
いろいろと お話しして来た内容は
私たちにとっても全く新しい
試みばかりです
面白いことばかりです
いろんなことがたくさん
起こっている最中です
私たちが考えているのは
Composable関数を使えば
何かすごく性能があがるような
強力な方法があるのではないか
ということです
しかし まだ検討段階です
もう一つ 言っておきたいことは
コンパイラで行われたことについて
私たちがお話したことはすべて
正確性が求められるということです
面白いミスとして
@Composableを用いたコードを
古いKotlinコンパイラで
コンパイルすると通ってしまうことです
ネット上のブログには
そんなことをするのに
Android Studioなど必要ないという
ものもあるようですが
それは 間違いです

Portuguese: 
É sério.
É um grande projeto.
Ainda estamos explorando as opções.
Muitas das coisas das quais eu falei
são novas empreitadas de nossa parte.
Acho isso muito interessante.
Muitas dessas coisas
ainda estão acontecendo.
Achamos que há maneiras muito eficientes
de ter desempenho em um mundo
em que temos funções combináveis.
Mas ainda estamos analisando isso.
Outra coisa que quero destacar
é que tudo o que falamos
e que está sendo feito pelo compilador
é necessário para termos precisão.
Há um equívoco interessante
em que o código que usa
@Composable e coisas afins
é compilado muito bem com
o antigo compilador do Kotlin.
Há alguns blogs na Internet
que dizem que não precisamos
do Android Studio...
e coisas assim.
Eles estão errados.

English: 
So what I ask is that
you all be careful.
This was an oversight
on our part,
and we're exploring how to
make this less of a foot gun.
But really, your
code is not correct
unless you're using
this compiler,
basically, a new version of
Android Studio 4 or higher.
So just be very
careful with that.
And then finally, I want to give
a shout out to the Kotlin Lang
slack channel.
There's a Compose channel
in that community.
It's very active.
A lot of folks from
the Compose team
are on there, including myself.
And if you do want
to get involved
and learn more about these
things or even help out,
that's a great place to start.
Also, another shout
out-- we do a lot
of UX studies around Compose
and APIs we're choosing.
And we're really looking for
more volunteers to help us out.
So upstairs at the
Compose sandbox,
there's a way to sign
up if you're interested.
And that's it.
Thank you.

Indonesian: 
Saya meminta
Anda berhati-hati.
Ini kekeliruan di 
pihak kami,
kami sedang mempelajari
cara menguranginya.
Kode Anda tidak tepat
kecuali Anda menggunakan
compiler ini,
versi baru Android Studio 4
atau yang lebih tinggi.
Jadi, berhati-hatilah.
Terakhir, saya mau
menyebut slack channel
Kotlin Lang.
Ada channel Compose
di komunitas itu.
Mereka sangat aktif.
Banyak orang dari
tim Compose
ada di sana, termasuk saya.
Jika Anda mau terlibat
dan mempelajari lebih lanjut
atau bahkan membantu,
channel itu tempat yang tepat.
Selain itu -- kami
melakukan banyak
studi UX tentang Compose
dan API yang kami pilih.
Kami sedang mencari
sukarelawan untuk membantu.
Di lantai atas,
di sandbox Compose,
ada cara untuk mendaftar
jika Anda tertarik.
Sekian.
Terima kasih.

Portuguese: 
Então, tenham cuidado.
Não foi um descuido nosso.
Estamos verificando como
não tornar isso um tiro no pé.
De fato, o código só está correto
se você usa este compilador,
basicamente, uma nova versão do
Android Studio 4 ou posterior.
Então, tenham muito cuidado com isso.
E, por fim, quero anunciar
o canal do Kotlin no Slack.
Há um canal do Compose nesta comunidade.
Está bem ativo.
Muitos colegas da equipe do Compose
estão lá, inclusive eu.
Se vocês quiserem se envolver
e saber mais sobre essas coisas
ou até mesmo ajudar,
esse é um ótimo lugar para começar.
Outra coisa: realizamos muitos
estudos de UX sobre o Compose
e as APIs que estamos escolhendo.
Estamos procurando
voluntários para nos ajudar.
No andar de cima, temos
o sandbox do Compose.
Vocês podem se inscrever, se quiserem.
É isso.
Obrigado.

Spanish: 
Solo les pido que tengan cuidado.
Fue un descuido de nuestra parte.
Estamos explorando
la forma de que esto los perjudique.
Pero, en serio, su código no será correcto
a menos que usen este compilador.
Es decir, una nueva versión
de Android Studio 4 o posterior.
Así que tengan cuidado.
Por último, quiero mencionar
el canal de Slack de Kotlin.
Hay un canal de Compose en esa comunidad.
Tiene mucha actividad.
Muchos miembros del equipo de Compose
están allí, yo incluido.
Si quieren involucrarse
y aprender más sobre estos temas o ayudar,
es un gran lugar para empezar.
Otra mención: realizamos
muchos estudios de UX
en Compose y API que elegimos.
Estamos buscando más voluntarios.
Arriba, en la zona de pruebas de Compose,
pueden inscribirse si están interesados.

Korean: 
부탁드리는 건 신중해지시라는 겁니다
이건 저희 입장에서의 실수이긴 하지만
foot gun을 최대한 줄일 방법을
모색하고 있답니다
하지만 여러분이 이 컴파일러를
즉 Android Studio 4 혹은
그 이상의 버전을 쓰지 않는 한
코드가 정확하지 않을 수 있으니
무척 신중하셔야 합니다
마지막으로 Kotlin 언어의 
Slack 채널에 대해
드리고 싶은 말씀이 있습니다
그 커뮤니티에는 Compose 
채널이 있죠
아주 활발합니다
저를 포함해서 Compose 팀의 수많은
사람들이 거기에서 활동합니다
만약 이러한 것들에 대해 
더 알고 싶으시거나
혹은 도움이 필요하시다면
시작해 볼 만한 곳입니다
또 하나 알려드리고자 하는 부분으로
저희는 Compose와 API에서
많은 UX 연구를 하고 있는데
더 많은 자원자분들이 저희를 도와주시길
기대하고 있습니다
위층의 Compose 샌드박스에 가시면
관심 있는 분들이 지원하실 수 있답니다
그럼 이상입니다
감사합니다

Japanese: 
お願いしたいことは
気をつけてくださいということです
これは 私たちの方の手落ちですが
自業自得にならないように
努力しています
しかし 本当にこのコンパイラを
使わないと
正しいコードは書けません
基本的はAndroid Studio 4の最新バージョンか
それ以降のコンパイラです
これには十分気をつけてください
最後に Kotlin Lang Slackチャンネルで
大声で叫びたいと思います
Compose チャネルがあります
とてもアクティブです
Composeチームから多くの人たちが
参加しています 私もです
今日の話題について
さらに詳しく知りたかったり
開発に貢献したい人は
ぜひ 参加してみてください
もうひとつ
私たちはComposeや選んだAPIまわりのUXを
詳しく調べています
私たちに協力してくれるボランティアを
募集中です
興味のある方は
上の階のComposer Sandboxまで
いらしてください。参加方法を
お教えします
これで私の話は終わりです

Chinese: 
请大家在操作时多加小心
这是我们工作中的一个疏忽
我们正在摸索 如何把它的不利影响降到最低
总之 如果你不使用这个编译器 
也就是较新版本的 Android Studio 4 或更高版本
你的代码正确性就会出问题
所以 请大家多加小心
最后 请大家多多关注 Kotlin Lang Slack 频道
那个社区中还设置了一个 Compose 频道
频道非常活跃
很多来自 Compose 团队的成员也在那里 包括我自己
如果你想亲自参与 并了解更多这方面信息
甚至帮我们一把 那在这个地方起步 再合适不过
另外 请大家注意 我们会针对我们选择的
Compose 和 API 进行大量的 UX 研究
非常期待能有更多的志愿者来帮忙
楼上就是我们的 Compose 体验区
如果有人感兴趣 可以在那里加入
就讲这么多吧 谢谢大家

Spanish: 
Eso es todo. Gracias.

Korean: 
[박수]
[음악 재생]

Indonesian: 
[SUARA TEPUK TANGAN]
[SUARA MUSIK]

English: 
[APPLAUSE]
[MUSIC PLAYING]

Japanese: 
ありがとうございました
