Developer diary · Day 8

I sat down to test payments and got off the train with twelve languages

Yesterday I signed off saying I'd sit down to the purchase screen today. And that deciding what to ask for it frightened me more than building it.

Today's story isn't about the price at all.

It's about how I talked myself into translations.

But it did start, as promised, with payments.

💳 Pretend money

On day one I wrote that you don't stand up an environment on a train, and you don't run an app on it.

Today I'm sitting in the carriage buying my own app. Again and again.

Not with real money, obviously. Xcode can pretend to be the store: you describe the product in one file, and the whole purchase plays out — the sheet, the confirmation, the store's answer. No network, and not one real dollar.

I've had very little to do with Apple's platform directly. So I was genuinely curious what this would look like.

It looks great. Everything clear and well put together, and I got to know Xcode a little better along the way.

Tested it. Made a few pretend purchases. Took them back again. Ran it back and forth to see how it all works in both directions.

Added a counter while I was at it, to hint that the limit is getting close. It only shows up once you're down to eight — not before.

Nothing out of the ordinary. Half an hour of fun.

And yesterday's fear hasn't gone anywhere.

The price itself has been on the landing page since day one: $9.99, once. The number isn't what scares me. What scares me is whether it works.

Is it too much? Too little? Where is the balance between how much you give away free and what people will find fair to pay?

I don't have an answer. I only have the other side of it.

I'm the good guy here.
I don't reach into your pocket with a subscription.
I don't ask you to pay up front.
I give you a fair limit to try it properly.
I'm not greedy about platforms.

All in all, top value for the money.

And about that limit. The same landing page has carried one more number since day one. Back then I asked you to remember it and promised to come back to it.

Here it is.

The screenshot of all that fun I sent a friend today. This is where the free plan runs out: twenty-four snippets, then $9.99 — once.
The screenshot of all that fun I sent a friend today. This is where the free plan runs out: twenty-four snippets, then $9.99 — once.

Twenty-four snippets, free, forever. As of today that number lives in the code, not just on a page.

And a couple of details I like more than I probably should.

The limit doesn't sit on a button. It sits where a snippet is created — anywhere else, some other path would walk round it.

And the snippets aren't read to be counted, only counted. Whatever is in a vault stays encrypted; the only thing that comes out is a number.

A counter that doesn't read what it counts.

And a refusal doesn't wipe anything. Before, you'd type a line, press add — and get a window about buying instead of a snippet, and lose the line. Now creating a snippet says honestly whether it was saved, and whatever didn't fit stays in the field.

👹 iddqd

I was done with payments somewhere between Niagara and Hamilton.

Through Hamilton I already had something else on my mind. I got the itch to play.

You can't make an app without easter eggs, can you.

And what could be better than reaching for something ancient. As ancient as Doom.

As far as I can tell, codes like this often aren't there for fun. They're used to test distribution: who came from where, which code they typed, what worked.

I have no telemetry like that.

From the very start I built one rule into the app: we have no access to the user's data on their side. No backend, no analytics.

I just really don't like that sort of trick.

Where you don't know how far your data is still yours, and where the hard abuse begins.

Where somebody can change the data collection policy any time they like, just by emailing you an update.

I don't like that crap.

So here the easter egg is just a bit of fun. And for you, reading this, it'll be amusing.

And while I was in that frame of mind, I rethought the limits.

Twenty-four stays. But type the cheat code from Doom and you get ten more.

Or fewer. There were different cheats.

Let me know how it lands.

It is built properly, though.

The ten aren't added, they're set. Type the code a hundred times and you get exactly ten on top, no more. And the bonus is saved in the settings, so it survives a relaunch.

If you type it after buying, there's nothing left to give. So the app just answers: "You bought god mode. The lightning is on the house."

Because, yes, lightning also trails the cursor.

It's of zero use. But it's built carefully too. The bolts are spawned by watching the mouse, not by a transparent layer over everything — a layer like that would swallow the clicks meant for every block underneath it. And the drawing goes to sleep by itself once there are no bolts left, so a still cursor costs nothing at all.

I spent time making a useless thing properly.

What I didn't look into is how the whole easter egg fits with the rest of the app. The idea was worth it on its own.

Another half hour.

🎮 Half an hour of The Witcher

My train ride is two hours.

So today I did allow myself half an hour of The Witcher.

The remaster came out yesterday. The one that was sitting on my Switch on Monday, waiting for its magic date.

And you know what…

My first language isn't English.

And it is so much fun to play a proper game in your own language.

It's like a comfortable pair of slippers. Yours, and in your language.

That thought came to me as the train was already coming into Toronto.

And I decided to estimate: how long would that take me?

🌍 Twelve languages before the office

Not all that long, as it turned out.

English was there from the start. Twelve were added: Russian, Ukrainian, German, French, Spanish, Portuguese, Italian, Japanese, Chinese, Korean, Bengali and Hindi.

The app takes the system language. Nothing to switch on.

I'm not the one translating, of course — the AI is. The hard part was something else: checking the whole app for text that had been left untranslated.

In 2026 that's not as hard as it sounds. You just take it and try.

It honestly is more a test of attention than of knowledge.

For instance, you can't build the list of strings to translate by searching the files. A search doesn't find strings inside conditions, or strings with a number dropped into them — those had to come from what the compiler itself sees.

And some labels would have stayed English without a word. There are two ways to put text on screen, they look identical, and one of them doesn't translate. Section headings, settings rows, the first-run walkthrough, the labels on the colour sliders — everything around them would have been translated, and they'd have stayed as they were.

This is where the languages themselves help.

Hindi, Bengali, Japanese are the perfect environment for spotting which word or notification didn't get translated. An English word in the middle of Devanagari has nowhere to hide.

Three of the twelve I speak myself, so I'll check those myself. I also asked around among colleagues: there are people who know Hindi, Bengali, Korean and Japanese. So there is someone to check with.

A board's name is fixed at the moment it's created. A board named on a Russian Mac keeps its Russian name, even if the system is switched over later.

And the main thing.

The jokes in the app aren't translated. They're written again, each one for its own language.

Remember "or fewer"? For that case, every language has its own proverb about greed getting what it deserves. Not one proverb in twelve versions — twelve different ones.

The same line in twelve languages. In English it's simply "Too greedy".
The same line in twelve languages. In English it's simply "Too greedy".

And in five languages "god mode" gave way to a local word. In Hindi and Bengali it's a boon. In Japanese, Chinese and Korean it's invincible mode. The English gamer's word sits there like a foreign object, and a joke that needs explaining is no longer a joke.

Oh, and the settings had to get sixty points wider. The slider took a hundred and forty, which left about a hundred and twenty for the label, and the longer languages didn't fit.

Twelve languages aren't twelve files. They're twelve different ideas of how much room a word takes.

Getting off the train, I was that weird guy with an open laptop in his hands.

But before I walked into the office, I had twelve languages.

Yes, they still need reading and checking. Nobody's perfect.

But this is something that can really help with getting the word out. Here's why.

The English-speaking market is the most profitable. It's also the most competitive.

If I'm going to turn my product into something that sells, I'd better reach further.

🔌 Engineer honesty moment

Half an hour of fun went on money today, and half an hour on the easter egg. Here are three things from the same day that weren't fun.

The first — a race. Once a purchase completes, you can ask the system what the person now owns. I asked straight away.

Too straight away. The purchase had gone through, and the answer still said "nothing bought".

Now the unlock is granted from the signed purchase itself, and asking the system again only makes sense in one case — when the purchase has been taken back.

The second — refunds. And this one is funny. Until today, a purchase couldn't be taken back at all.

The "purchased" flag could only say "yes" or "no". "Haven't asked yet" and "asked, nothing bought" both looked like "no". So if someone got their money back, the app simply didn't notice and stayed unlocked forever.

Now the flag has three states. And it's a cache, not the decision. The store always decides.

The difference between a cache and a decision is roughly everything you need to know about money in an app.

The third — changing privacy levels. A board has three: plain, protected by fingerprint, and a vault with a passphrase.

And it was odd that you could just switch between them like that.

Anyone with the app open in front of them could change the level. The board's already unlocked — so it's one of us, so go ahead.

No.

Unlocked isn't proof. It means someone proved the right once, and then went to get a coffee.

A stranger at an unlocked Mac could move your board into a vault with their own passphrase. And lock you out with your own feature.

Now changing the level means proving the level the board is on right now, even when it's open. And the new level takes effect at once: a passphrase gets tested the moment it's invented, not the moment it's forgotten.

Closed, sure. But this whole area feels like a very big thing that still needs testing and testing.

💬 A question

I've been thinking about the price since before there was a single line of code. The languages I did on the way to the office.

How much would you pay, once, for a small thing you use every day? And how much of it do you need for free before you know?

My answer, for now: twenty-four snippets to try it properly, then $9.99 — once, and for good. Whether that works, I don't know.

Tell me how it goes for you 👇

I have twelve languages. Read so far — none.

Tomorrow I want to go through the whole app through the eyes of whoever will check it before the store. And I suspect they won't like my cheat code 😉