Lokalisering av motorn
Motorns text riktad till människor finns på 17 språk vid sidan av engelska: nl, pl, pt-BR, pt-PT, fi, sv, da, nb, cs, uk, ru, de, fr, es, et, ja, zh-Hans. Engelska är källan; en-XA är ett pseudospråk som sätter accenter, hakparenteser och utfyllnad på varje meddelande, så att ett test kan se om text har flyttats till katalogen. Ramverket är Project Fluent (fluent-bundle, unic-langid); koden är src/i18n/.
Vad som lokaliseras och vad som aldrig gör det#
| Lokaliseras (en människa läser det) | Lokaliseras aldrig (ett program läser det) |
|---|---|
| meddelanden och fel på kommandoraden | JSON-nycklar och värden i result.json och report.json |
| sammanfattningsraden för varje körning | CSV-rubriker och rader |
| texten i SVG-diagram (titlar, axlar, förklaringar, bildtexter) | filnamn |
report.html: rubriker, tabeller, anmärkningar, bildtexter |
felkoder (E-CLOCK-VERSION) |
| utfallsord (VALIDATED, MODELLED, PARTIAL) | verifieringsmatrisen, enhetsdefinitioner, proveniens |
beskrivningarna av scenariotyperna (list_kinds(lang)) |
|
rådgivande uttalanden, friskrivningar och meddelanden (engine-legal-*) |
samma texter inuti JSON, som förblir på engelska |
report.html för iq-kampanjen, jämförelsesidan för studier, topplistan för bench, resiliensrapporten |
summary.html för ett bevispaket och observatoriets PNG: båda hashas in i ett manifest (paketets är dessutom signerat), så de byggs på engelska oavsett språk |
Tal i text för människor använder språkets decimaltecken (ett kommatecken i 15 av de 18 språken; en punkt i en, ja, zh-Hans och en-XA). Tal i maskinfiler använder alltid punkt. Ett antal (en variabel som heter n, count, n_*, num_* eller *_count) når Fluent som ett tal, så en översättning får skriva { $n -> [one] ... [few] ... *[other] ... }.
Välja språk#
- Kommandoraden:
--lang <tag>, därefterKSHANA_LANG,LC_ALL,LC_MESSAGES,LANG, därefter engelska.ptär pt-BR; barapt-PTär Portugals.zhär förenklad kinesiska; traditionell avvisas med listan över språkkoder som stöds. - Bibliotek:
api::run_toml_lang(toml, lang),run_toml_bilingual,run_toml_human,run_scenario_lang,list_scenario_kinds_json_lang(lang). - Python:
lang=Nonepårun,run_full,run_typed,validate_toml,error_kind,list_kinds,scenario_kinds;run_human(toml, lang);error_info(toml, lang). - WebAssembly: ett valfritt avslutande
langpårun_typed,run,chart_svg,summary,table_csv,run_all,error_kind,list_kinds,scenario_kinds;run_human(toml, lang);error_info(toml, lang);register_catalogue(tag, ftl_text). - MCP:
langpårun_scenarioochlist_scenario_kinds.
Fel och deras koder#
Varje felmeddelande har en stabil kod, meddelande-id:t med versaler (e-clock-version är E-CLOCK-VERSION), densamma på alla språk. Kommandoradens engelska text är oförändrad. På ett annat språk är raden text [E-CODE]; med --verbose följer en andra rad code: E-CODE på alla språk. API:et ger KshanaError::code() och error_info ({kind, code, message}); MCP-fel bär {kind, code, message} som feldata. Matcha på koden, aldrig på texten.
Hur en körning fungerar på ett annat språk (regeln om körning två gånger)#
En maskinfil får inte bero på språket. En körning på ett annat språk kör därför scenariot två gånger: en gång på engelska, vars result.json, report.json och CSV är maskinfilerna, och en gång på användarens språk, för sammanfattningen, diagrammet och report.html. Engelska är en körning, byte för byte vad den var tidigare.
Uppmätt, nativt, releasebygge, engelska därefter --lang de (sekunder): leo-navmsg-fit-interval-trade 9,2 -> 17,9, cislunar-arc-recovery 7,8 -> 14,1, lunar-station-coverage 7,8 -> 15,0, clock-ensemble 5,8 -> 11,6, leo-navmsg-model-comparison 5,1 -> 10,5, leo-ppp-convergence 2,8 -> 6,2; varje annat medföljande scenario tar under 4 s; de 173 scenarier som medföljde när detta mättes tog tillsammans 64 s på engelska. Kostnaden är exakt dubbel för ett annat språk. WebAssembly mättes inte (ingen wasm-bindgen här); med webbläsarfaktorn omkring 4 blir det en minut för den långsammaste typen.
En sida undviker väntetiden genom att visa det engelska resultatet direkt och därefter anropa run_human(toml, lang): det är enbart den andra körningen, den returnerar {summary, svg}, och Studio kan visa "översätter..." tills den kommer.
Punkt för 0,41: en körning. Rendera båda utifrån en post av (message id, arguments). Det bedömdes och byggdes inte: t!-resultat inspekteras, mäts och hashas efter att de har skapats (bredder på diagramtext, hashar för proveniens över utdatatext), och num() formaterar vid anropsstället, så en post skulle lägga platshållartoken i maskinfiler och göra deras byte beroende av uppspelningen. Det kräver t!/num som returnerar token, en slutbehandlare vid varje skrivare och ett bevis på byteidentitet för varje skrivare.
WebAssembly#
Wasm-bygget bäddar bara in den engelska katalogen. De andra sexton skulle lägga till omkring 150 kB gzip vardera. En sida hämtar i18n/<lang>/engine.ftl vid ett språkval och anropar register_catalogue(tag, text); om hämtningen eller registreringen misslyckas stannar sidan på engelska. Nativt bäddar kommandoraden och Python-hjulet in alla 18.
Storlek, ooptimerad .wasm från cargo build --release --target wasm32-unknown-unknown --features wasm --lib (före wasm-bindgen och wasm-opt), bas bc04e98f mot den här grenen: 18,71 MB -> 19,88 MB rått, 5,43 MB -> 5,79 MB gzip, +357 kB gzip. Den engelska katalogen är 521 kB rå, 153 kB gzip av den; resten är fluent-bundle och dess beroenden. Detta godtas som uppmätt.
Katalogen#
i18n/<tag>/engine.ftl innehåller meddelandena, med id:n med prefixet engine-. i18n/en/engine.ftl är källan; de andra filerna är översättarnas och kan sakna meddelanden (var och en faller tillbaka på engelska per meddelande). Följelistor i i18n/en/: engine-counts.txt (meddelanden med antalsvariabler, för pluralformer), engine-numbers.txt (tal som skickas som placeables), engine-fragments.txt (meddelanden som är delar av en mening som sätts ihop vid körning: ska slås ihop till meddelanden med hela meningar, aldrig bli fler).
Tester#
tests/i18n_catalogue.rs bevisar engelskan: varje meddelande har en registrerad ursprungsmall och renderas till exakt den texten; varje id används; variablerna stämmer; pseudospråket renderar varje meddelande. i18n_api.rs, i18n_kinds.rs, i18n_legal.rs täcker ingångspunkterna, beskrivningarna av typerna och de juridiska texterna. i18n_ratchet.rs misslyckas om en ny strängliteral som en människa skulle läsa går förbi katalogen: tillåtet antal per fil i tests/fixtures/i18n/allow.json, som får sjunka och aldrig stiga. scripts/i18n_compare.py kör hela scenarier med en baslinjebinär och den aktuella och jämför varje utdatafil.
Hur man flyttar en sträng till katalogen: docs/design/i18n-migration.md.
Beroenden och licenser#
Ramverket lägger till fluent-bundle 0,16 (Apache-2.0 OR MIT) och unic-langid 0,9 (MIT OR Apache-2.0), med sina transitiva crates: fluent-syntax och fluent-langneg (Apache-2.0 OR MIT), intl-memoizer (Apache-2.0 OR MIT), intl_pluralrules (Apache-2.0/MIT), type-map (MIT/Apache-2.0), self_cell (Apache-2.0 OR GPL-2.0-only: alternativet Apache-2.0 är det som används, vilket deny.toml tillåter), tinystr och zerovec (Unicode-3.0), rustc-hash, smallvec, thiserror, displaydoc (MIT OR Apache-2.0). Alla är permissiva enligt listan allow i deny.toml; thiserror förekommer i två versioner (1 och 2), vilket multiple-versions = "warn" bara rapporterar. Licenslistan lästes från cargo metadata; cargo deny check är inte installerat i skrivmiljön och körs i integrations-CI.