7: 翻译

Phlo 将翻译视为渲染问题:您在源语言中编写视图文本,进行标记,lang 资源在请求时提供正确的语言,并在后台翻译缺失的条目。在本章中,投票在 /nl 前缀下学习荷兰语。

7.1: Source-language markers

Static view text gets a marker keyed by the language the text is written in. This app's source language is English, so the key is en:

view:
<main#app.poll>
	<h1>{en: Which stack wins?}</h1>
	{{ $this->results }}
	{{ $this->choices }}
</main>

{en: ...} transpiles to a call to the en() helper, which asks the translation layer for the text in the active language. If the active language is English, the text passes through untouched. If you were writing a Dutch-source app you would use {nl: ...} with the same mechanics; the marker always names the source language of that specific string. Outside views, the same helpers work in code: method title => en('Phlo Poll').

Update the <h1> in poll.phlo now; the page still renders identically, because the active language is still English.

7.2: Configure the language layer

Three small pieces of configuration. First, the resources in data/app.json (the lang resource brings cookie detection, INI file caching, and AI-backed translation):

{
    "resources": [
        "DB/DB",
        "DB/model",
        "DB/JSONDB",
        "DB/JSON.result",
        "payload",
        "phlo.async",
        "DOM/form",
        "lang",
        "cookies",
        "files/INI",
        "AI/AI",
        "AI/OpenAI",
        "security/creds"
    ]
}

Here phlo.async is the backend resource used by the translation layer to schedule its CLI backfill. It is not the SPA request handler from the previous chapter; frontend navigation and forms are handled by the generated frontend runtime and their DOM resources.

Second, tell the runtime where translation files live, in www/app.php:

phlo_app(
	id:    'Poll',
	host:  'localhost',
	build: true,
	debug: true,
	app:   dirname(__DIR__).'/',
	langs: dirname(__DIR__).'/langs/',
);

Every named argument to phlo_app() becomes an app-wide constant, so langs is now a path you (and the lang resource) can use anywhere. Create the folder: mkdir app/langs.

Third, declare the app's languages in app.phlo:

prop lang = 'en'
prop langs = ['en' => 'English', 'nl' => 'Nederlands']

Rebuild and lint; both end at [].

7.3: 一个 /nl 路由前缀

活动语言存储在 %app->lang 中。可以通过在 poll.phlo 中设置第二个路由来从 URL 中设置它:

route GET poll => $this->home

route GET $lang:nl poll {
	%app->lang = $lang
	$this->home
}

$lang:nl 是一个值列表段:只有当第一个路径段字面上是 nl 时,它才会匹配。要添加更多语言,可以扩展列表:$lang:nl,de,fr。英语路由保持干净的 URL;带前缀的路由设置语言并渲染相同的页面。

打开 http://localhost/nl/poll。<html lang="nl"> 属性遵循 %app->lang,但标题仍然是英语:尚未有荷兰语翻译。

7.4: 翻译缓存

翻译存储在 langs/<lang>.ini 中,每个字符串占一行,按源文本的哈希值进行键控。当一个标记字符串在活动语言中没有条目时,页面会显示源文本并通过 OpenAI 安排后台翻译;下一个请求会读取缓存结果。为了使该回填工作正常,请在 data/creds.ini 中放入 API 密钥:

OpenAI = sk-...

没有密钥?一切仍然可以正常工作,缺失的字符串将保持在源语言中。您也可以自己编写文件;在第一次回填后,langs/nl.ini 看起来像这样:

enWhichStad3 = "Welke stack wint?"

该键编码了源语言加上确切文本的哈希值,因此更改的源文本会获得一个新的条目。条目存在后,请重新加载 http://localhost/nl/poll:

<h1>Welke stack wint?</h1>

相同的视图,相同的路由逻辑,第二种语言。投票距离完成还有一章:它仍然无法将结果推送给其他查看者。

最近更新于 2026年10月7日

我们使用必要的cookie来使该网站正常工作。在您的许可下,我们还使用分析工具来改善网站。