[{"data":1,"prerenderedAt":1705},["ShallowReactive",2],{"search-de":3,"content-de-developer\u002Fui-localization":4,"surround-de-\u002Fdeveloper\u002Fui-localization":1696},[],{"id":5,"title":6,"body":7,"description":1689,"extension":1690,"meta":1691,"navigation":837,"path":1692,"seo":1693,"stem":1694,"__hash__":1695},"content_de\u002F3.developer\u002F23.ui-localization.md","UI-Lokalisierung — eine Sprache hinzufügen",{"type":8,"value":9,"toc":1671},"minimark",[10,14,18,85,102,106,113,123,126,132,139,167,172,197,229,233,257,260,271,291,297,303,314,384,405,409,416,473,486,490,511,515,748,752,763,767,776,872,889,915,994,1000,1025,1039,1090,1105,1118,1124,1175,1201,1316,1337,1358,1411,1415,1421,1478,1484,1493,1500,1508,1541,1548,1570,1600,1631,1667],[11,12,6],"h1",{"id":13},"ui-lokalisierung-eine-sprache-hinzufügen",[15,16,17],"p",{},"Owlat hat zwei voneinander unabhängige Übersetzungssysteme. Verwechseln Sie sie nicht:",[19,20,21,37],"table",{},[22,23,24],"thead",{},[25,26,27,31,34],"tr",{},[28,29,30],"th",{},"System",[28,32,33],{},"Was es übersetzt",[28,35,36],{},"Wo es lebt",[38,39,40,64],"tbody",{},[25,41,42,49,56],{},[43,44,45],"td",{},[46,47,48],"strong",{},"Übersetzungen von E-Mail-Inhalten",[43,50,51,52],{},"Die Kampagnen, Templates und Blöcke, ",[53,54,55],"em",{},"die Sie versenden",[43,57,58,59],{},"Pro Workspace, in Convex gespeichert — siehe ",[60,61,63],"a",{"href":62},"\u002Fguide\u002Ftranslations","Übersetzungen in der Produktanleitung",[25,65,66,72,78],{},[43,67,68,71],{},[46,69,70],{},"UI-Lokalisierung"," (diese Seite)",[43,73,74,75],{},"Die Owlat-Oberfläche, ",[53,76,77],{},"die Ihr Team und Ihre Empfänger lesen",[43,79,80,81],{},"Ein Katalog pro App plus einer für die gemeinsame UI-Schicht, mit dem Code ausgeliefert — siehe ",[60,82,84],{"href":83},"#wo-was-liegt","Wo was liegt",[15,86,87,88,97,98,101],{},"Die UI-Schicht ist ",[60,89,93],{"href":90,"rel":91},"https:\u002F\u002Fi18n.nuxtjs.org",[92],"nofollow",[94,95,96],"code",{},"@nuxtjs\u002Fi18n",". ",[94,99,100],{},"en"," ist die Standard-Locale und der Fallback für jede andere, sodass ein nicht übersetzter Schlüssel seinen englischen Text rendert statt eines rohen Schlüsselpfads.",[103,104,84],"h2",{"id":105},"wo-was-liegt",[15,107,108,109,112],{},"Es gibt ",[46,110,111],{},"vier Kataloge",", einen je Nuxt-App plus einen für die Schicht, die alle erweitern. Jeder ist ein eigenes Verzeichnis, und jede App registriert ihre eigene Locale-Liste:",[114,115,120],"pre",{"className":116,"code":118,"language":119},[117],"language-text","apps\u002Fweb\u002Fi18n\u002Flocales\u002F{en,de}.json        # das Produkt: Dashboard, Postbox, Admin, Auth, Empfängerseiten\napps\u002Fmarketing\u002Fi18n\u002Flocales\u002F{en,de}.json  # die öffentliche Website (owlat.app)\napps\u002Fdocs\u002Fi18n\u002Flocales\u002F{en,de}.json       # die Rahmenoberfläche dieser Website — die SEITEN liegen in content\u002F{en,de}\u002F\npackages\u002Fui\u002Fi18n\u002Flocales\u002F{en,de}.json     # die gemeinsame UI-Schicht (`ui.*`), von allen dreien geerbt\n","text",[94,121,118],{"__ignoreMap":122},"",[15,124,125],{},"Eine einzelne App sieht so aus:",[114,127,130],{"className":128,"code":129,"language":119},[117],"apps\u002Fweb\u002F\n├── nuxt.config.ts          # the `i18n` block: locale list, strategy, detection\n└── i18n\u002F\n    ├── i18n.config.ts      # vue-i18n runtime options (fallbackLocale, warnings)\n    └── locales\u002F\n        ├── en.json         # source of truth\n        └── de.json         # a translation\n",[94,131,129],{"__ignoreMap":122},[15,133,134,135,138],{},"Locale-Dateien werden ",[46,136,137],{},"lazy geladen",": Ein Besucher lädt nur den Katalog der Locale herunter, die ihm tatsächlich angezeigt wird.",[15,140,141,142,145,146,149,150,153,154,157,158,161,162,166],{},"In der App sind Routen ",[46,143,144],{},"nicht"," mit einem Präfix versehen (",[94,147,148],{},"strategy: 'no_prefix'","). Jede Owlat-URL dort ist entweder eine Dashboard-Route oder ein Token-Link, der bereits in einer versendeten E-Mail abgedruckt wurde (",[94,151,152],{},"\u002Funsubscribe?token=…","), sodass ein ",[94,155,156],{},"\u002Fde\u002F","-Segment Live-Links zerstören würde. Die Marketing-Website und diese Dokumentationswebsite setzen stattdessen ein Präfix (",[94,159,160],{},"prefix_except_default","); die Begründung steht weiter unten unter ",[60,163,165],{"href":164},"#diese-dokumentationswebsite","Diese Dokumentationswebsite",".",[168,169,171],"h3",{"id":170},"die-gemeinsame-ui-schicht","Die gemeinsame UI-Schicht",[15,173,174,177,178,181,182,185,186,189,190,193,194,196],{},[94,175,176],{},"packages\u002Fui"," ist ein Nuxt-Layer, seine Copy (",[94,179,180],{},"ui.*"," — Schließen-Buttons von Dialogen, Alert-Überschriften, „Erneut versuchen“) kann also in keinem einzelnen App-Katalog leben. Die Schicht steuert ihre eigenen ",[94,183,184],{},"i18n.locales"," aus ",[94,187,188],{},"packages\u002Fui\u002Fnuxt.config.ts"," bei, und @nuxtjs\u002Fi18n merged die Dateilisten pro Locale mit der ",[46,191,192],{},"Datei der Schicht zuerst und der App-Datei zuletzt"," — eine App kann jede ",[94,195,180],{},"-Message also überschreiben, indem sie den Schlüssel in ihrem eigenen Katalog erneut deklariert.",[15,198,199,200,202,203,205,206,209,210,213,214,217,218,221,222,224,225,228],{},"Die Schicht führt ",[94,201,96],{}," ",[46,204,144],{}," in ihren ",[94,207,208],{},"modules",": Das Modul wird von den konsumierenden Apps installiert, und ein Layer darf es einer App, die i18n noch nicht übernommen hat, nicht aufzwingen. Deshalb übersetzen die Komponenten der Schicht über ",[94,211,212],{},"useUiI18n()"," (",[94,215,216],{},"packages\u002Fui\u002Fcomposables\u002FuseUiI18n.ts",") statt direkt über ",[94,219,220],{},"useI18n()"," — es fällt auf den mitgelieferten englischen Katalog zurück, wenn es gar keine vue-i18n-Instanz gibt oder wenn deren Messages kein ",[94,223,180],{}," enthalten (so sieht der Komponententest einer App aus). Der Preis dieses Fallbacks: Eine kaputte Verdrahtung der Schicht liest sich als unübersetztes Englisch, nicht als sichtbare Schlüsselpfade — prüfen Sie die Verdrahtung deshalb ",[46,226,227],{},"an der deutschen Copy",": Der Schließen-Button eines Dialogs muss „Dialog schließen“ heißen.",[168,230,232],{"id":231},"die-marketing-website","Die Marketing-Website",[15,234,235,238,239,241,242,244,245,248,249,252,253,256],{},[94,236,237],{},"apps\u002Fmarketing"," folgt denselben Regeln und registriert ",[94,240,96],{}," als Erstes in ",[94,243,208],{},", damit die SEO-Module (Sitemap, robots, og-image) die Locale-Liste beim Aufsetzen sehen und Einträge pro Locale ausgeben. ",[94,246,247],{},"i18n.baseUrl"," ist die kanonische Website-URL — sie macht die ",[94,250,251],{},"hreflang","-Alternates absolut. Die Browsererkennung ist dort bewusst aus: Die Sprache wird über den Umschalter in der Kopfzeile gewählt, Suchmaschinen werden durch die Alternates auf die richtige Variante gelenkt, und eine automatische Weiterleitung anhand von ",[94,254,255],{},"Accept-Language"," würde einen deutsch konfigurierten Browser von einem Link wegwerfen, der ausdrücklich als englische Seite geteilt wurde.",[103,258,165],{"id":259},"diese-dokumentationswebsite",[15,261,262,263,266,267,270],{},"Die Docs (",[94,264,265],{},"apps\u002Fdocs",") folgen denselben Regeln mit zwei Ergänzungen, weil sie ",[53,268,269],{},"Seiten"," übersetzen, nicht nur die Rahmenoberfläche.",[15,272,273,213,276,279,280,283,284,287,288,290],{},[46,274,275],{},"URLs tragen ein Präfix",[94,277,278],{},"strategy: 'prefix_except_default'","). Englisch behält die URLs, die es immer schon veröffentlicht hat — ",[94,281,282],{},"\u002Fguide\u002Fquick-start"," —, und Deutsch lebt unter ",[94,285,286],{},"\u002Fde\u002Fguide\u002Fquick-start",". Nichts davon wurde je in einer E-Mail abgedruckt, ein Locale-Segment ist also kostenlos, und genau das erlaubt es, eine deutsche Seite zu teilen, zu indexieren und mit einer eigenen ",[94,289,251],{},"-Alternate zu versehen.",[15,292,293,296],{},[46,294,295],{},"Der Markdown-Baum ist pro Locale gespiegelt",", jeweils ein Verzeichnis und eine Content-Collection:",[114,298,301],{"className":299,"code":300,"language":119},[117],"apps\u002Fdocs\u002F\n├── content.config.ts       # one page collection per locale\n├── i18n\u002F\n│   ├── i18n.config.ts\n│   └── locales\u002F{en,de}.json\n└── content\u002F\n    ├── en\u002F1.guide\u002F2.quick-start.md   # → \u002Fguide\u002Fquick-start\n    └── de\u002F1.guide\u002F2.quick-start.md   # → \u002Fde\u002Fguide\u002Fquick-start\n",[94,302,300],{"__ignoreMap":122},[15,304,305,306,309,310,313],{},"Jede Collection entfernt ihr eigenes Locale-Verzeichnis (",[94,307,308],{},"source: { include: 'de\u002F**\u002F*.md', prefix: '' }","), sodass ",[46,311,312],{},"jede Collection dieselben locale-freien Pfade veröffentlicht",". Eine Query benennt nie eine Locale im Pfad — sie wählt stattdessen die Collection:",[114,315,319],{"className":316,"code":317,"language":318,"meta":122,"style":122},"language-ts shiki shiki-themes github-light github-dark-dimmed","const { locale } = useI18n();\nconst page = await queryDocsPage(docsCollection(locale.value), '\u002Fguide\u002Fquick-start');\n","ts",[94,320,321,351],{"__ignoreMap":122},[322,323,326,330,334,338,341,344,348],"span",{"class":324,"line":325},"line",1,[322,327,329],{"class":328},"s7YZ4","const",[322,331,333],{"class":332},"sYgZi"," { ",[322,335,337],{"class":336},"sviXB","locale",[322,339,340],{"class":332}," } ",[322,342,343],{"class":328},"=",[322,345,347],{"class":346},"sPO5f"," useI18n",[322,349,350],{"class":332},"();\n",[322,352,354,356,359,362,365,368,371,374,377,381],{"class":324,"line":353},2,[322,355,329],{"class":328},[322,357,358],{"class":336}," page",[322,360,361],{"class":328}," =",[322,363,364],{"class":328}," await",[322,366,367],{"class":346}," queryDocsPage",[322,369,370],{"class":332},"(",[322,372,373],{"class":346},"docsCollection",[322,375,376],{"class":332},"(locale.value), ",[322,378,380],{"class":379},"s-HuK","'\u002Fguide\u002Fquick-start'",[322,382,383],{"class":332},");\n",[15,385,386,388,389,392,393,396,397,400,401,404],{},[94,387,373],{},", ",[94,390,391],{},"contentPath"," (das die ",[94,394,395],{},"\u002Fde"," entfernt, die ein Router-Pfad mitträgt) und die Query-Helfer liegen allesamt in ",[94,398,399],{},"app\u002Fcomposables\u002FuseDocsContent.ts",". Nutzen Sie diese statt ",[94,402,403],{},"queryCollection"," direkt — dort wohnt der Fallback.",[168,406,408],{"id":407},"eine-übersetzung-darf-hinterherhinken-eine-seite-nicht","Eine Übersetzung darf hinterherhinken; eine Seite nicht",[15,410,411,412,415],{},"Der deutsche Baum ist heute vollständig, und er bleibt auch dann auslieferbar, wenn er es nicht ist: ",[46,413,414],{},"eine fehlende Seite fällt auf ihre englische Quelle zurück, statt einen 404 zu werfen",". Das erlaubt es, eine neue englische Seite zu veröffentlichen, ohne auf ihre Übersetzung zu warten. Die Regel gilt überall dort, wo eine Seite gelesen wird:",[19,417,418,428],{},[22,419,420],{},[25,421,422,425],{},[28,423,424],{},"Oberfläche",[28,426,427],{},"Verhalten",[38,429,430,438,446,458],{},[25,431,432,435],{},[43,433,434],{},"Seiteninhalt",[43,436,437],{},"Die Seite der Locale, sonst die englische Seite — unter der deutschen URL, in deutscher Rahmenoberfläche",[25,439,440,443],{},[43,441,442],{},"Suche",[43,444,445],{},"Die Seiten der Locale, aufgefüllt mit englischen Seiten, für die es noch keine Übersetzung gibt",[25,447,448,451],{},[43,449,450],{},"Zurück \u002F Weiter",[43,452,453,454,457],{},"Die Lesereihenfolge kommt ",[46,455,456],{},"immer"," aus dem Englischen (dem einzigen vollständigen Baum); Titel werden lokalisiert, wo sie existieren",[25,459,460,463],{},[43,461,462],{},"Seitenleiste, Breadcrumb, seiteninterne Links",[43,464,465,466,469,470,472],{},"Locale-freie Pfade laufen durch ",[94,467,468],{},"localePath",", sodass eine Leserin in ",[94,471,395],{}," bleibt",[15,474,475,476,478,479,482,483,166],{},"Die eine Stelle, an der das ",[53,477,144],{}," gilt, ist eine falsche URL: ",[94,480,481],{},"\u002Fde\u002Fnonsense"," ist ein echter 404 und rendert ",[94,484,485],{},"app\u002Ferror.vue",[168,487,489],{"id":488},"beschriftungen-der-seitenleiste","Beschriftungen der Seitenleiste",[15,491,492,495,496,499,500,388,503,506,507,510],{},[94,493,494],{},"app\u002Futils\u002FsidebarConfig.ts"," bleibt die Single Source of Truth für die Navigation, englische Beschriftungen inklusive. Übersetzungen werden unter einem Schlüssel nachgeschlagen, der aus dem Eintrag ",[46,497,498],{},"abgeleitet"," wird — ",[94,501,502],{},"sidebar.groups.\u003Csection>-\u003Clabel>",[94,504,505],{},"sidebar.items.\u003Cpath>",", beide slugifiziert —, und fallen auf die Beschriftung der Konfiguration zurück, sodass eine neue Seite ohne Katalogänderung Englisch statt eines rohen Schlüsselpfads rendert. ",[94,508,509],{},"__tests__\u002FlocaleCatalogs.test.ts"," schlägt bei genau dieser Drift fehl, ebenso bei einem verwaisten Schlüssel und bei zwei Einträgen, die auf denselben Schlüssel zusammenfallen würden.",[103,512,514],{"id":513},"eine-locale-hinzufügen","Eine Locale hinzufügen",[516,517,518,543,672,682,742],"ol",{},[519,520,521,524],"li",{},[46,522,523],{},"Kopieren Sie den Quellkatalog.",[114,525,529],{"className":526,"code":527,"language":528,"meta":122,"style":122},"language-sh shiki shiki-themes github-light github-dark-dimmed","cp apps\u002Fweb\u002Fi18n\u002Flocales\u002Fen.json apps\u002Fweb\u002Fi18n\u002Flocales\u002Ffr.json\n","sh",[94,530,531],{"__ignoreMap":122},[322,532,533,537,540],{"class":324,"line":325},[322,534,536],{"class":535},"sOLd2","cp",[322,538,539],{"class":379}," apps\u002Fweb\u002Fi18n\u002Flocales\u002Fen.json",[322,541,542],{"class":379}," apps\u002Fweb\u002Fi18n\u002Flocales\u002Ffr.json\n",[519,544,545,548,549,552,553,651,654,656,657,660,661,664,665,667,668,671],{},[46,546,547],{},"Registrieren Sie sie"," in ",[94,550,551],{},"apps\u002Fweb\u002Fnuxt.config.ts",":",[114,554,556],{"className":316,"code":555,"language":318,"meta":122,"style":122},"locales: [\n  { code: 'en', language: 'en-US', name: 'English', file: 'en.json' },\n  { code: 'de', language: 'de-DE', name: 'Deutsch', file: 'de.json' },\n  { code: 'fr', language: 'fr-FR', name: 'Français', file: 'fr.json' },\n],\n",[94,557,558,566,595,620,645],{"__ignoreMap":122},[322,559,560,563],{"class":324,"line":325},[322,561,562],{"class":535},"locales",[322,564,565],{"class":332},": [\n",[322,567,568,571,574,577,580,583,586,589,592],{"class":324,"line":353},[322,569,570],{"class":332},"  { code: ",[322,572,573],{"class":379},"'en'",[322,575,576],{"class":332},", language: ",[322,578,579],{"class":379},"'en-US'",[322,581,582],{"class":332},", name: ",[322,584,585],{"class":379},"'English'",[322,587,588],{"class":332},", file: ",[322,590,591],{"class":379},"'en.json'",[322,593,594],{"class":332}," },\n",[322,596,598,600,603,605,608,610,613,615,618],{"class":324,"line":597},3,[322,599,570],{"class":332},[322,601,602],{"class":379},"'de'",[322,604,576],{"class":332},[322,606,607],{"class":379},"'de-DE'",[322,609,582],{"class":332},[322,611,612],{"class":379},"'Deutsch'",[322,614,588],{"class":332},[322,616,617],{"class":379},"'de.json'",[322,619,594],{"class":332},[322,621,623,625,628,630,633,635,638,640,643],{"class":324,"line":622},4,[322,624,570],{"class":332},[322,626,627],{"class":379},"'fr'",[322,629,576],{"class":332},[322,631,632],{"class":379},"'fr-FR'",[322,634,582],{"class":332},[322,636,637],{"class":379},"'Français'",[322,639,588],{"class":332},[322,641,642],{"class":379},"'fr.json'",[322,644,594],{"class":332},[322,646,648],{"class":324,"line":647},5,[322,649,650],{"class":332},"],\n",[652,653],"br",{},[94,655,94],{}," ist die Kennung, auf die die App umschaltet, ",[94,658,659],{},"language"," ist das BCP-47-Tag, das in ",[94,662,663],{},"lang","\u002F",[94,666,251],{}," geschrieben wird, und ",[94,669,670],{},"name"," ist das, was die Sprachauswahl anzeigt. Die Sprachauswahl liest genau diese Liste — eine registrierte Locale erscheint dort ohne weiteres Zutun.",[519,673,674,677,678,681],{},[46,675,676],{},"Übersetzen Sie die Werte, niemals die Schlüssel."," Halten Sie die Objektform identisch zu ",[94,679,680],{},"en.json"," — der Katalog-Guard-Test vergleicht die beiden Schlüsselmengen und schlägt bei einem fehlenden oder erfundenen Schlüssel fehl.",[519,683,684,687,733,735,736,738,739,166],{},[46,685,686],{},"Führen Sie die Guards aus.",[114,688,690],{"className":526,"code":689,"language":528,"meta":122,"style":122},"cd apps\u002Fweb && npx vitest run app\u002F__tests__\u002FlocaleCatalogs.test.ts\ncd apps\u002Fdocs && npx vitest run __tests__\u002FlocaleCatalogs.test.ts\n",[94,691,692,715],{"__ignoreMap":122},[322,693,694,697,700,703,706,709,712],{"class":324,"line":325},[322,695,696],{"class":336},"cd",[322,698,699],{"class":379}," apps\u002Fweb",[322,701,702],{"class":332}," && ",[322,704,705],{"class":535},"npx",[322,707,708],{"class":379}," vitest",[322,710,711],{"class":379}," run",[322,713,714],{"class":379}," app\u002F__tests__\u002FlocaleCatalogs.test.ts\n",[322,716,717,719,722,724,726,728,730],{"class":324,"line":353},[322,718,696],{"class":336},[322,720,721],{"class":379}," apps\u002Fdocs",[322,723,702],{"class":332},[322,725,705],{"class":535},[322,727,708],{"class":379},[322,729,711],{"class":379},[322,731,732],{"class":379}," __tests__\u002FlocaleCatalogs.test.ts\n",[652,734],{},"Das prüft für jede Locale: vollständige Schlüsselabdeckung gegenüber ",[94,737,100],{},", identische Platzhalternamen je Message, kein Markup und kein unescaptes ",[94,740,741],{},"@",[519,743,744,747],{},[46,745,746],{},"Prüfen Sie die langen Strings in der Oberfläche."," Deutsch und Französisch laufen 20–35 % länger als Englisch; Buttons, Schalterzeilen und Karten-Überschriften sind die Stellen, an denen das zuerst auffällt.",[168,749,751],{"id":750},"wählen-sie-ein-register-und-bleiben-sie-dabei","Wählen Sie ein Register und bleiben Sie dabei",[15,753,754,755,758,759,762],{},"Jede Locale sollte sich wie eine Stimme lesen. Der ausgelieferte ",[94,756,757],{},"de","-Katalog verwendet durchgängig das förmliche ",[53,760,761],{},"Sie",", weil die meistgelesenen Oberflächen (Abmeldung, Präferenzzentrum, Double-Opt-in) von Fremden gelesen werden, die sich nie für Owlat entschieden haben. Folgen Sie dem bestehenden Katalog statt den Gewohnheiten einer einzelnen Datei.",[103,764,766],{"id":765},"übersetzbare-strings-schreiben","Übersetzbare Strings schreiben",[15,768,769,775],{},[46,770,771,772,166],{},"Jeder sichtbare String geht durch ",[94,773,774],{},"t()"," Importieren Sie es einmal pro Komponente:",[114,777,781],{"className":778,"code":779,"language":780,"meta":122,"style":122},"language-vue shiki shiki-themes github-light github-dark-dimmed","\u003Cscript setup lang=\"ts\">\nconst { t } = useI18n();\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cp>{{ t('recipient.preferences.noTopics') }}\u003C\u002Fp>\n\u003C\u002Ftemplate>\n","vue",[94,782,783,807,824,833,839,848,863],{"__ignoreMap":122},[322,784,785,788,792,796,799,801,804],{"class":324,"line":325},[322,786,787],{"class":332},"\u003C",[322,789,791],{"class":790},"sIAta","script",[322,793,795],{"class":794},"sMOND"," setup",[322,797,798],{"class":794}," lang",[322,800,343],{"class":332},[322,802,803],{"class":379},"\"ts\"",[322,805,806],{"class":332},">\n",[322,808,809,811,813,816,818,820,822],{"class":324,"line":353},[322,810,329],{"class":328},[322,812,333],{"class":332},[322,814,815],{"class":336},"t",[322,817,340],{"class":332},[322,819,343],{"class":328},[322,821,347],{"class":346},[322,823,350],{"class":332},[322,825,826,829,831],{"class":324,"line":597},[322,827,828],{"class":332},"\u003C\u002F",[322,830,791],{"class":790},[322,832,806],{"class":332},[322,834,835],{"class":324,"line":622},[322,836,838],{"emptyLinePlaceholder":837},true,"\n",[322,840,841,843,846],{"class":324,"line":647},[322,842,787],{"class":332},[322,844,845],{"class":790},"template",[322,847,806],{"class":332},[322,849,851,854,856,859,861],{"class":324,"line":850},6,[322,852,853],{"class":332},"  \u003C",[322,855,15],{"class":790},[322,857,858],{"class":332},">{{ t('recipient.preferences.noTopics') }}\u003C\u002F",[322,860,15],{"class":790},[322,862,806],{"class":332},[322,864,866,868,870],{"class":324,"line":865},7,[322,867,828],{"class":332},[322,869,845],{"class":790},[322,871,806],{"class":332},[15,873,874,875,878,879,882,883,886,887,166],{},"Skriptseitige Strings — Validierungsmeldungen, Fehlertexte, ",[94,876,877],{},"useBackendOperation","-Labels, ",[94,880,881],{},"useHead","-\u002F",[94,884,885],{},"useSeoMeta","-Titel — laufen über dasselbe ",[94,888,774],{},[15,890,891,894,895,898,899,664,901,903,904,907,908,910,911,914],{},[46,892,893],{},"Alles, was einmalig beim Setup erfasst wird, nimmt einen Getter, keinen Wert."," Ein blankes ",[94,896,897],{},"t('…')"," in einem Options-Objekt wird ausgewertet, während die Komponente aufgesetzt wird, und dort eingefroren — es behält also die Locale, die beim Mounten zufällig aktiv war. ",[94,900,881],{},[94,902,885],{}," und das ",[94,905,906],{},"label"," von ",[94,909,877],{}," akzeptieren jeweils ",[94,912,913],{},"() => t('…')"," und lesen es erst, wenn sie es tatsächlich verwenden:",[114,916,918],{"className":316,"code":917,"language":318,"meta":122,"style":122},"useHead({ title: () => t('auth.login.pageTitle') });\n\nconst { run } = useBackendOperation(api.auth.userProfiles.create, {\n  label: () => t('auth.register.createProfileOperation'),\n});\n",[94,919,920,947,951,970,989],{"__ignoreMap":122},[322,921,922,924,927,930,933,936,939,941,944],{"class":324,"line":325},[322,923,881],{"class":346},[322,925,926],{"class":332},"({ ",[322,928,929],{"class":346},"title",[322,931,932],{"class":332},": () ",[322,934,935],{"class":328},"=>",[322,937,938],{"class":346}," t",[322,940,370],{"class":332},[322,942,943],{"class":379},"'auth.login.pageTitle'",[322,945,946],{"class":332},") });\n",[322,948,949],{"class":324,"line":353},[322,950,838],{"emptyLinePlaceholder":837},[322,952,953,955,957,960,962,964,967],{"class":324,"line":597},[322,954,329],{"class":328},[322,956,333],{"class":332},[322,958,959],{"class":336},"run",[322,961,340],{"class":332},[322,963,343],{"class":328},[322,965,966],{"class":346}," useBackendOperation",[322,968,969],{"class":332},"(api.auth.userProfiles.create, {\n",[322,971,972,975,977,979,981,983,986],{"class":324,"line":622},[322,973,974],{"class":346},"  label",[322,976,932],{"class":332},[322,978,935],{"class":328},[322,980,938],{"class":346},[322,982,370],{"class":332},[322,984,985],{"class":379},"'auth.register.createProfileOperation'",[322,987,988],{"class":332},"),\n",[322,990,991],{"class":324,"line":647},[322,992,993],{"class":332},"});\n",[15,995,996,999],{},[46,997,998],{},"Interpolieren Sie Werte, verketten Sie niemals Sätze."," Die Wortstellung unterscheidet sich je Sprache, deshalb ist ein String, der um einen Wert herum in Präfix und Suffix zerlegt wurde, nicht übersetzbar:",[114,1001,1005],{"className":1002,"code":1003,"language":1004,"meta":122,"style":122},"language-json shiki shiki-themes github-light github-dark-dimmed","{ \"intro\": \"Update your email preferences for {organization}.\" }\n","json",[94,1006,1007],{"__ignoreMap":122},[322,1008,1009,1012,1016,1019,1022],{"class":324,"line":325},[322,1010,1011],{"class":332},"{ ",[322,1013,1015],{"class":1014},"snmFh","\"intro\"",[322,1017,1018],{"class":332},": ",[322,1020,1021],{"class":379},"\"Update your email preferences for {organization}.\"",[322,1023,1024],{"class":332}," }\n",[15,1026,1027,1034,1035,1038],{},[46,1028,1029,1030,1033],{},"Wenn ein Satzteil Markup trägt, verwenden Sie ",[94,1031,1032],{},"\u003CI18nT>"," mit einem benannten Slot"," — nicht ",[94,1036,1037],{},"v-html",", das einen ungeescapten Kontakt- oder Organisationsnamen direkt in die Seite rendern würde:",[114,1040,1042],{"className":778,"code":1041,"language":780,"meta":122,"style":122},"\u003CI18nT keypath=\"recipient.preferences.intro\" tag=\"span\" scope=\"global\">\n  \u003Ctemplate #organization>\u003Cstrong>{{ contactInfo.teamName }}\u003C\u002Fstrong>\u003C\u002Ftemplate>\n\u003C\u002FI18nT>\n",[94,1043,1044,1077,1082],{"__ignoreMap":122},[322,1045,1046,1048,1051,1054,1056,1059,1062,1064,1067,1070,1072,1075],{"class":324,"line":325},[322,1047,787],{"class":332},[322,1049,1050],{"class":790},"I18nT",[322,1052,1053],{"class":794}," keypath",[322,1055,343],{"class":332},[322,1057,1058],{"class":379},"\"recipient.preferences.intro\"",[322,1060,1061],{"class":794}," tag",[322,1063,343],{"class":332},[322,1065,1066],{"class":379},"\"span\"",[322,1068,1069],{"class":794}," scope",[322,1071,343],{"class":332},[322,1073,1074],{"class":379},"\"global\"",[322,1076,806],{"class":332},[322,1078,1079],{"class":324,"line":353},[322,1080,1081],{"class":332},"  \u003Ctemplate #organization>\u003Cstrong>{{ contactInfo.teamName }}\u003C\u002Fstrong>\u003C\u002Ftemplate>\n",[322,1083,1084,1086,1088],{"class":324,"line":597},[322,1085,828],{"class":332},[322,1087,1050],{"class":790},[322,1089,806],{"class":332},[15,1091,1092,1097,1098,1100,1101,1104],{},[46,1093,1094,1095,166],{},"Escapen Sie ein wörtliches ",[94,1096,741],{}," Der Message-Compiler liest ",[94,1099,741],{}," als Marker für eine verlinkte Message, ein E-Mail-Platzhalter wird deshalb ",[94,1102,1103],{},"you{'@'}example.com"," geschrieben.",[15,1106,1107,202,1110,1113,1114,1117],{},[46,1108,1109],{},"Kein HTML in Message-Werten.",[94,1111,1112],{},"compilation.strictMessage"," weist es zur Build-Zeit zurück, ein eingeschmuggeltes ",[94,1115,1116],{},"\u003Cstrong>"," ist also ein fehlgeschlagener Build statt eines kaputten Strings.",[15,1119,1120,1123],{},[46,1121,1122],{},"Formatieren Sie Datums- und Zahlenwerte gegen die aktive Locale",", nicht gegen eine fest gepinnte:",[114,1125,1127],{"className":316,"code":1126,"language":318,"meta":122,"style":122},"const { t, locale } = useI18n();\nnew Intl.DateTimeFormat(locale.value, { dateStyle: 'long' }).format(sentAt);\n",[94,1128,1129,1149],{"__ignoreMap":122},[322,1130,1131,1133,1135,1137,1139,1141,1143,1145,1147],{"class":324,"line":325},[322,1132,329],{"class":328},[322,1134,333],{"class":332},[322,1136,815],{"class":336},[322,1138,388],{"class":332},[322,1140,337],{"class":336},[322,1142,340],{"class":332},[322,1144,343],{"class":328},[322,1146,347],{"class":346},[322,1148,350],{"class":332},[322,1150,1151,1154,1157,1160,1163,1166,1169,1172],{"class":324,"line":353},[322,1152,1153],{"class":328},"new",[322,1155,1156],{"class":332}," Intl.",[322,1158,1159],{"class":346},"DateTimeFormat",[322,1161,1162],{"class":332},"(locale.value, { dateStyle: ",[322,1164,1165],{"class":379},"'long'",[322,1167,1168],{"class":332}," }).",[322,1170,1171],{"class":346},"format",[322,1173,1174],{"class":332},"(sentAt);\n",[15,1176,1177,1183,1184,213,1187,388,1190,388,1193,1196,1197,1200],{},[46,1178,1179,1180,1182],{},"Ein Modul, das ",[94,1181,774],{}," nicht aufrufen kann, gibt einen Schlüssel zurück, keinen Satz."," Die Vokabular-Tabellen unter ",[94,1185,1186],{},"app\u002Futils",[94,1188,1189],{},"deliverabilityRamp",[94,1191,1192],{},"deliverabilityMeasurement",[94,1194,1195],{},"breadcrumbRoutes",", …) sind reine Module ohne Komponenteninstanz. Sie geben deshalb einen Katalogschlüssel zurück — oder ",[94,1198,1199],{},"{ key, params }",", wenn der Satz Zahlen interpoliert —, und wer ihn rendert, macht Worte daraus:",[114,1202,1204],{"className":316,"code":1203,"language":318,"meta":122,"style":122},"type LocalizedText = string | { key: string; params?: Record\u003Cstring, unknown> };\nconst localized = (value: LocalizedText) =>\n  typeof value === 'string' ? t(value) : t(value.key, value.params ?? {});\n",[94,1205,1206,1257,1281],{"__ignoreMap":122},[322,1207,1208,1211,1214,1216,1219,1222,1224,1228,1230,1232,1235,1238,1241,1244,1246,1249,1251,1254],{"class":324,"line":325},[322,1209,1210],{"class":328},"type",[322,1212,1213],{"class":535}," LocalizedText",[322,1215,361],{"class":328},[322,1217,1218],{"class":336}," string",[322,1220,1221],{"class":328}," |",[322,1223,333],{"class":332},[322,1225,1227],{"class":1226},"stnAF","key",[322,1229,552],{"class":328},[322,1231,1218],{"class":336},[322,1233,1234],{"class":332},"; ",[322,1236,1237],{"class":1226},"params",[322,1239,1240],{"class":328},"?:",[322,1242,1243],{"class":535}," Record",[322,1245,787],{"class":332},[322,1247,1248],{"class":336},"string",[322,1250,388],{"class":332},[322,1252,1253],{"class":336},"unknown",[322,1255,1256],{"class":332},"> };\n",[322,1258,1259,1261,1264,1266,1268,1271,1273,1275,1278],{"class":324,"line":353},[322,1260,329],{"class":328},[322,1262,1263],{"class":346}," localized",[322,1265,361],{"class":328},[322,1267,213],{"class":332},[322,1269,1270],{"class":1226},"value",[322,1272,552],{"class":328},[322,1274,1213],{"class":535},[322,1276,1277],{"class":332},") ",[322,1279,1280],{"class":328},"=>\n",[322,1282,1283,1286,1289,1292,1295,1298,1300,1303,1305,1307,1310,1313],{"class":324,"line":597},[322,1284,1285],{"class":328},"  typeof",[322,1287,1288],{"class":332}," value ",[322,1290,1291],{"class":328},"===",[322,1293,1294],{"class":379}," 'string'",[322,1296,1297],{"class":328}," ?",[322,1299,938],{"class":346},[322,1301,1302],{"class":332},"(value) ",[322,1304,552],{"class":328},[322,1306,938],{"class":346},[322,1308,1309],{"class":332},"(value.key, value.params ",[322,1311,1312],{"class":328},"??",[322,1314,1315],{"class":332}," {});\n",[15,1317,1318,1319,1322,1323,1326,1327,213,1330,1333,1334,166],{},"Einen solchen Wert direkt in ein Template zu schreiben malt ",[94,1320,1321],{},"[object Object]"," oder einen rohen Schlüsselpfad vor die Leserin. Jede konsumierende Stelle ist also eine Render-Grenze — auch die Nitro-Routen unter ",[94,1324,1325],{},"server\u002F",", die kein vue-i18n haben und dieselben Schlüssel mit ",[94,1328,1329],{},"localizeEn()",[94,1331,1332],{},"server\u002Futils\u002FlocalizedText.ts",") auf Englisch rendern, für ein Skript, eine Logzeile oder ",[94,1335,1336],{},"curl",[15,1338,1339,1349,1350,1353,1354,1357],{},[46,1340,1341,1342,1345,1346],{},"Registries außerhalb von ",[94,1343,1344],{},"apps\u002Fweb"," verwenden den Namensraum ",[94,1347,1348],{},"sharedPkg.*"," — Vokabulare aus ",[94,1351,1352],{},"packages\u002Fshared"," und Convex-Read-Models halten ihre Schlüssel unter ",[94,1355,1356],{},"sharedPkg.\u003CModulname>.*",", damit sie niemals mit den oben beschriebenen, aus Dateipfaden abgeleiteten Namensräumen kollidieren. Es gibt zwei Muster, gewählt danach, wer die Texte sonst noch liest:",[1359,1360,1361,1383],"ul",{},[519,1362,1363,213,1366,388,1369,1372,1373,1376,1377,1380,1381,166],{},[46,1364,1365],{},"Nur im Web verwendete Texte speichern direkt Schlüssel",[94,1367,1368],{},"operatingModes",[94,1370,1371],{},"snoozePresets",", die Zugangsdaten-Felder von ",[94,1374,1375],{},"sendProviderCatalog","): Das Modul trägt den Schlüssel, die Web-Komponente rendert ",[94,1378,1379],{},"t(key)"," — dieselbe Regel wie für ",[94,1382,1186],{},[519,1384,1385,213,1388,1391,1392,1395,1396,1399,1400,1403,1404,388,1407,1410],{},[46,1386,1387],{},"Texte mit einem Konsumenten außerhalb des Webs behalten ihr Englisch",[94,1389,1390],{},"featureFlags"," — die Setup-CLI gibt sie aus; ",[94,1393,1394],{},"deliverabilityChecklist"," — Convex speichert und verschickt sie; die ",[94,1397,1398],{},"adaptiveDashboard","-Karten — ein ausgeliefertes Read Model): Das Modul bleibt englisch, und das Web löst einen ",[53,1401,1402],{},"abgeleiteten"," Schlüssel auf (",[94,1405,1406],{},"useFeatureCopy()",[94,1408,1409],{},"useDashboardCardCopy()","), mit dem Englisch der Registry als Fallback für Einträge, die kein ausgelieferter Katalog kennen kann — etwa von Plugins geprägte Flags. Ein Katalogtest verklammert beide Kopien des englischen Texts, damit sie nicht auseinanderdriften können.",[103,1412,1414],{"id":1413},"was-extrahiert-ist","Was extrahiert ist",[15,1416,1417,1420],{},[46,1418,1419],{},"Alles."," Die Extraktion landete Oberfläche für Oberfläche und ist abgeschlossen:",[19,1422,1423,1432],{},[22,1424,1425],{},[25,1426,1427,1429],{},[28,1428,424],{},[28,1430,1431],{},"Stand",[38,1433,1434,1444,1453,1466],{},[25,1435,1436,1441],{},[43,1437,1438,1440],{},[94,1439,1344],{}," — Dashboard, Postbox, Zustellung und Admin, Setup- und Desktop-Abläufe, Auth, Willkommen, empfängerseitige Seiten",[43,1442,1443],{},"Extrahiert",[25,1445,1446,1451],{},[43,1447,1448,1450],{},[94,1449,237],{}," — die öffentliche Website",[43,1452,1443],{},[25,1454,1455,1463],{},[43,1456,1457,1459,1460],{},[94,1458,265],{}," — die Rahmenoberfläche dieser Website und die Seiten selbst unter ",[94,1461,1462],{},"content\u002F{en,de}\u002F",[43,1464,1465],{},"Extrahiert und übersetzt",[25,1467,1468,1476],{},[43,1469,1470,1472,1473,1475],{},[94,1471,176],{}," — die eigene Copy der gemeinsamen Schicht (",[94,1474,180],{},")",[43,1477,1443],{},[15,1479,1480,1481,1483],{},"Ein neuer String, der nicht durch ",[94,1482,774],{}," läuft, ist ein Review-Kommentar, kein Folgeticket: Eine Oberfläche ist entweder vollständig extrahiert, oder sie erzeugt einen Satz in zwei Sprachen.",[15,1485,1486,1487,1489,1490,1492],{},"Der Docs-Baum ist die eine Stelle, an der eine Übersetzung berechtigterweise hinterherhinken darf, und er degradiert dort mit Absicht — siehe den Abschnitt „Eine Übersetzung darf hinterherhinken; eine Seite nicht“ weiter oben. Überall sonst halten die Katalog-Guards ",[94,1488,100],{}," und ",[94,1491,757],{}," auf Parität und schlagen bei einem fehlenden Schlüssel fehl, statt eine englische Zeile mitten auf der Seite auftauchen zu lassen.",[168,1494,1496,1497],{"id":1495},"erkennung-die-sprachauswahl-und-html-lang","Erkennung, die Sprachauswahl und ",[94,1498,1499],{},"\u003Chtml lang>",[15,1501,1502,1503,202,1505,552],{},"Die Erkennung der Browsersprache ist in ",[94,1504,1344],{},[46,1506,1507],{},"eingeschaltet",[114,1509,1511],{"className":316,"code":1510,"language":318,"meta":122,"style":122},"detectBrowserLanguage: { useCookie: true, cookieKey: 'owlat-locale' },\n",[94,1512,1513],{"__ignoreMap":122},[322,1514,1515,1518,1521,1524,1526,1529,1531,1534,1536,1539],{"class":324,"line":325},[322,1516,1517],{"class":535},"detectBrowserLanguage",[322,1519,1520],{"class":332},": { ",[322,1522,1523],{"class":535},"useCookie",[322,1525,1018],{"class":332},[322,1527,1528],{"class":336},"true",[322,1530,388],{"class":332},[322,1532,1533],{"class":535},"cookieKey",[322,1535,1018],{"class":332},[322,1537,1538],{"class":379},"'owlat-locale'",[322,1540,594],{"class":332},[15,1542,1543,1544,1547],{},"Eine Besucherin bekommt beim ersten Mal die Locale, nach der ihr Browser fragt. Das Cookie ist die tragende Hälfte: Bei ",[94,1545,1546],{},"no_prefix"," trägt die URL keine Locale, ohne das Cookie würde also jeder Reload die Erkennung erneut ausführen und allen, deren Browser anderer Meinung ist, die gewählte Sprache wieder wegnehmen.",[15,1549,1550,1551,1554,1555,213,1558,1561,1562,1565,1566,1569],{},"Gewählt wird sie in ",[94,1552,1553],{},"app\u002Fcomponents\u002FLanguagePicker.vue",", unter ",[46,1556,1557],{},"Einstellungen",[94,1559,1560],{},"\u002Fdashboard\u002Fpreferences","), neben dem Erscheinungsbild — dieselbe Art von Einstellung: pro Person, pro Gerät, in diesem Browser statt am Konto gespeichert, sodass ein Wechsel auf dem Telefon die Desktop-Sitzung unangetastet lässt. Die Auswahl listet die Locales, mit denen das Modul konfiguriert ist, und schaltet über ",[94,1563,1564],{},"setLocale"," um, was den Zielkatalog lädt, die aktive Locale wechselt und ",[94,1567,1568],{},"owlat-locale"," schreibt. Die Marketing-Website und diese Website haben eigene Umschalter in der Kopfzeile, wo eine präfixierte URL den Wechsel zu einer Navigation macht.",[15,1571,1572,1574,1575,1578,1579,202,1582,1584,1585,1588,1589,1592,1593,1596,1597,1599],{},[94,1573,1499],{}," folgt der aktiven Locale. ",[94,1576,1577],{},"app.head.htmlAttrs.lang"," ist in ",[94,1580,1581],{},"nuxt.config.ts",[46,1583,144],{}," gepinnt — ein dort gesetzter Wert wird in jede Seite eingebacken und würde eine deutsche Leserin auf einem Dokument zurücklassen, das weiterhin ",[94,1586,1587],{},"lang=\"en\""," behauptet, und genau daran wählt ein Screenreader seine Stimme (WCAG 3.1.1). Stattdessen schreibt ",[94,1590,1591],{},"app\u002Fapp.vue"," den Wert aus ",[94,1594,1595],{},"useLocaleHead()",", über einen ",[94,1598,881],{},"-Getter, damit er beim Sprachwechsel neu ausgewertet wird statt beim ersten Rendern einzufrieren:",[114,1601,1603],{"className":316,"code":1602,"language":318,"meta":122,"style":122},"const localeHead = useLocaleHead();\nuseHead(() => ({ htmlAttrs: localeHead.value.htmlAttrs }));\n",[94,1604,1605,1619],{"__ignoreMap":122},[322,1606,1607,1609,1612,1614,1617],{"class":324,"line":325},[322,1608,329],{"class":328},[322,1610,1611],{"class":336}," localeHead",[322,1613,361],{"class":328},[322,1615,1616],{"class":346}," useLocaleHead",[322,1618,350],{"class":332},[322,1620,1621,1623,1626,1628],{"class":324,"line":353},[322,1622,881],{"class":346},[322,1624,1625],{"class":332},"(() ",[322,1627,935],{"class":328},[322,1629,1630],{"class":332}," ({ htmlAttrs: localeHead.value.htmlAttrs }));\n",[15,1632,1633,1634,1636,1637,1640,1641,1643,1644,1646,1647,1649,1650,1489,1653,1656,1657,1659,1660,1663,1664,1666],{},"In ",[94,1635,1344],{}," wird nur ",[94,1638,1639],{},"htmlAttrs"," übernommen: Bei ",[94,1642,1546],{}," teilen sich alle Locales eine URL, die ",[94,1645,251],{},"-Alternates, die ",[94,1648,1595],{}," ebenfalls ausgeben kann, zeigten also alle auf dieselbe Seite. Die Marketing- und die Docs-App übernehmen zusätzlich ",[94,1651,1652],{},"link",[94,1654,1655],{},"meta",", weil die Alternates dort echte URLs sind. Und da ",[94,1658,1344],{}," mit ",[94,1661,1662],{},"ssr: false"," läuft, wird sein ",[94,1665,663],{}," beim Start der App geschrieben, nicht in die statische Shell.",[1668,1669,1670],"style",{},"html pre.shiki code .s7YZ4, html code.shiki .s7YZ4{--shiki-default:#D73A49;--shiki-dark:#F47067}html pre.shiki code .sYgZi, html code.shiki .sYgZi{--shiki-default:#24292E;--shiki-dark:#ADBAC7}html pre.shiki code .sviXB, html code.shiki .sviXB{--shiki-default:#005CC5;--shiki-dark:#6CB6FF}html pre.shiki code .sPO5f, html code.shiki .sPO5f{--shiki-default:#6F42C1;--shiki-dark:#DCBDFB}html pre.shiki code .s-HuK, html code.shiki .s-HuK{--shiki-default:#032F62;--shiki-dark:#96D0FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sOLd2, html code.shiki .sOLd2{--shiki-default:#6F42C1;--shiki-dark:#F69D50}html pre.shiki code .sIAta, html code.shiki .sIAta{--shiki-default:#22863A;--shiki-dark:#8DDB8C}html pre.shiki code .sMOND, html code.shiki .sMOND{--shiki-default:#6F42C1;--shiki-dark:#6CB6FF}html pre.shiki code .snmFh, html code.shiki .snmFh{--shiki-default:#005CC5;--shiki-dark:#8DDB8C}html pre.shiki code .stnAF, html code.shiki .stnAF{--shiki-default:#E36209;--shiki-dark:#F69D50}",{"title":122,"searchDepth":353,"depth":353,"links":1672},[1673,1677,1681,1684,1685],{"id":105,"depth":353,"text":84,"children":1674},[1675,1676],{"id":170,"depth":597,"text":171},{"id":231,"depth":597,"text":232},{"id":259,"depth":353,"text":165,"children":1678},[1679,1680],{"id":407,"depth":597,"text":408},{"id":488,"depth":597,"text":489},{"id":513,"depth":353,"text":514,"children":1682},[1683],{"id":750,"depth":597,"text":751},{"id":765,"depth":353,"text":766},{"id":1413,"depth":353,"text":1414,"children":1686},[1687],{"id":1495,"depth":597,"text":1688},"Erkennung, die Sprachauswahl und \u003Chtml lang>","Wie die Übersetzungen der Owlat-Oberfläche funktionieren: wo die vier Message-Kataloge liegen, wie Sie eine Locale hinzufügen, welche Regeln für übersetzbare Strings gelten und wie die Sprache einer Besucherin erkannt, gewechselt und deklariert wird.","md",{},"\u002Fdeveloper\u002Fui-localization",{"title":6,"description":1689},"3.developer\u002F23.ui-localization","yeb_aF5FAPWeknpBNSMkdbagnO9c8DlkgRrBPQ4ip2o",[1697,1701],{"title":1698,"path":1699,"stem":1700,"children":-1},"Transportsicherheit","\u002Fdeveloper\u002Ftransport-security","3.developer\u002F22.transport-security",{"title":1702,"path":1703,"stem":1704,"children":-1},"Scopes","\u002Fdeveloper\u002Fscopes","3.developer\u002F3.scopes",1786915107718]