From 9d2fedf45c0d27d71fbb02eaffcd669146ed7b2c Mon Sep 17 00:00:00 2001 From: "Amy J. Ko" Date: Sat, 6 Jul 2024 11:27:27 -0700 Subject: [PATCH] Fixed #506. Clarified behavior of localized setting. --- CHANGELOG.md | 1 + .../concepts/BindConceptView.svelte | 4 +- src/components/concepts/ConceptView.svelte | 2 +- .../concepts/SegmentHTMLView.svelte | 2 +- src/components/concepts/TypeView.svelte | 2 +- src/components/editor/EvaluateView.svelte | 2 +- .../editor/ExpressionPlaceholderView.svelte | 9 +++- src/components/editor/Menu.svelte | 9 ++-- src/components/editor/TokenView.svelte | 26 +++++++++--- src/components/palette/ContentEditor.svelte | 16 +++---- src/components/project/Contexts.ts | 3 +- src/components/project/ProjectView.svelte | 42 ++++++++++++------- src/components/project/RootView.svelte | 7 ++-- src/components/widgets/Mode.svelte | 5 ++- src/db/LocalizedSetting.ts | 23 ++++++++-- src/db/Setting.ts | 5 ++- src/db/SettingsDatabase.ts | 6 +-- src/locale/UITexts.ts | 4 +- src/locale/en-US.json | 12 ++++-- src/nodes/Token.ts | 11 +++-- static/locales/es-MX/es-MX.json | 12 ++++-- static/locales/example/example.json | 8 ++-- static/locales/ko-KR/ko-KR.json | 12 ++++-- static/locales/zh-CN/zh-CN.json | 12 ++++-- static/locales/zh-TW/zh-TW.json | 12 ++++-- static/schemas/Locale.json | 14 +++---- 26 files changed, 172 insertions(+), 89 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3729943ef..7567df669 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Dates are in `YYYY-MM-DD` format and versions are in [semantic versioning](http: - [#507](https://github.com/wordplaydev/wordplay/issues/507) Fixed Webpage stream replay bug. - [#216](https://github.com/wordplaydev/wordplay/issues/216) Improved design of view code and copy buttons. - [#397](https://github.com/wordplaydev/wordplay/issues/397) Redesigned home page for clarity and navigability. +- [#506](https://github.com/wordplaydev/wordplay/issues/506) Clarified behavior of localized setting. - Added fade out sequence. - Fixed select all button. diff --git a/src/components/concepts/BindConceptView.svelte b/src/components/concepts/BindConceptView.svelte index 452b67841..d2cfa11d8 100644 --- a/src/components/concepts/BindConceptView.svelte +++ b/src/components/concepts/BindConceptView.svelte @@ -20,11 +20,11 @@ >{#if concept.bind.type}•{#if concept.bind.value}: {/if}{/if} diff --git a/src/components/concepts/ConceptView.svelte b/src/components/concepts/ConceptView.svelte index 871994aaa..e8bdfdeb4 100644 --- a/src/components/concepts/ConceptView.svelte +++ b/src/components/concepts/ConceptView.svelte @@ -78,7 +78,7 @@ {/if}{@const name = variable.names.getPreferredName( $locales.getLocales(), )}{#if name}{/if}{/each}{/if} diff --git a/src/components/concepts/SegmentHTMLView.svelte b/src/components/concepts/SegmentHTMLView.svelte index c0e5f78d8..be40805aa 100644 --- a/src/components/concepts/SegmentHTMLView.svelte +++ b/src/components/concepts/SegmentHTMLView.svelte @@ -59,7 +59,7 @@ {:else}{/if}{:else if segment instanceof ValueRef}{:else if segment instanceof ConceptRef} diff --git a/src/components/concepts/TypeView.svelte b/src/components/concepts/TypeView.svelte index 486ccf5e3..52f544677 100644 --- a/src/components/concepts/TypeView.svelte +++ b/src/components/concepts/TypeView.svelte @@ -35,7 +35,7 @@ concept && (event.key === 'Enter' || event.key === ' ') ? navigate(concept) : undefined} - >{/each} diff --git a/src/components/editor/EvaluateView.svelte b/src/components/editor/EvaluateView.svelte index 30b02fa1f..a245e47d9 100644 --- a/src/components/editor/EvaluateView.svelte +++ b/src/components/editor/EvaluateView.svelte @@ -62,7 +62,7 @@ node={nextBind.withoutValue()} inline elide - localized + localized="symbolic" inert />{#if menuPosition}{:else if inferredType && !(inferredType instanceof UnknownType)}
{/if}{#if caret}{/if} diff --git a/src/components/editor/Menu.svelte b/src/components/editor/Menu.svelte index 1d24c4241..ce4e9f6e5 100644 --- a/src/components/editor/Menu.svelte +++ b/src/components/editor/Menu.svelte @@ -178,10 +178,13 @@ {#if newNode !== undefined} {#if revision.isRemoval()} {:else} - + {/if} {:else} 1 ? newNode : newNode} - localized + localized="symbolic" /> {/if} diff --git a/src/components/editor/TokenView.svelte b/src/components/editor/TokenView.svelte index b07a39cf5..0e926d27c 100644 --- a/src/components/editor/TokenView.svelte +++ b/src/components/editor/TokenView.svelte @@ -35,11 +35,18 @@ ? node.getPlaceholder($root, context, $locales) : undefined; + $: isInCaret = + $caret && + node.getTextLength() > 0 && + ($caret.getTokenExcludingSpace() === node || + ($caret.tokenPrior === node && $caret.atBeginningOfTokenSpace())); + // True if the caret is "on" this token. $: active = + $caret && node.getTextLength() > 0 && - ($caret?.getTokenExcludingSpace() === node || - ($caret?.tokenPrior === node && + ($caret.getTokenExcludingSpace() === node || + ($caret.tokenPrior === node && $caret.atBeginningOfTokenSpace() && $caret.tokenIncludingSpace && $caret.tokenAtHasPrecedingSpace())); @@ -47,11 +54,20 @@ // True if this is the recently added token. $: added = $caret?.addition?.contains(node) ?? false; - // Localize the token's text using the preferred translation. + // If requesed, localize the token's text. // Don't localize the name if the caret is in the name. $: text = - context && $root && localize && $localize - ? node.localized($locales.getLocales(), $root, context) + !isInCaret && + context && + $root && + localize && + ($localize === 'localized' || $localize === 'symbolic') + ? node.localized( + $localize === 'symbolic', + $locales.getLocales(), + $root, + context, + ) : node.getText(); // Prepare the text for rendering by replacing spaces with non-breaking spaces diff --git a/src/components/palette/ContentEditor.svelte b/src/components/palette/ContentEditor.svelte index 12b50ac2e..89314789f 100644 --- a/src/components/palette/ContentEditor.svelte +++ b/src/components/palette/ContentEditor.svelte @@ -27,16 +27,16 @@ value instanceof Evaluate && (value.is( project.shares.output.Phrase, - project.getNodeContext(value) + project.getNodeContext(value), ) || value.is( project.shares.output.Group, - project.getNodeContext(value) + project.getNodeContext(value), ) || value.is( project.shares.output.Shape, - project.getNodeContext(value) - )) + project.getNodeContext(value), + )), ); function editContent(index: number) { @@ -82,7 +82,7 @@ active={editable} action={() => editContent(index)}>{EDIT_SYMBOL} - + {/each}
@@ -96,7 +96,7 @@ project, list, list?.values.length ?? 1 - 1, - 'phrase' + 'phrase', ) : undefined} >+{project.shares.output.Phrase.getNames()[0]}+{project.shares.output.Group.getNames()[0]}+{project.shares.output.Shape.getNames()[0]} | undefined>(LocalizeSymbol); + return getContext | undefined>(LocalizeSymbol); } export const ConceptPathSymbol = Symbol('palette-path'); diff --git a/src/components/project/ProjectView.svelte b/src/components/project/ProjectView.svelte index f7909f0ef..ca58c1e80 100644 --- a/src/components/project/ProjectView.svelte +++ b/src/components/project/ProjectView.svelte @@ -125,6 +125,8 @@ import { AnimationFactorIcons } from '@db/AnimationFactorSetting'; import { COPY_SYMBOL } from '@parser/Symbols'; import CopyButton from './CopyButton.svelte'; + import { toLocaleString } from '@locale/Locale'; + import { default as ModeChooser } from '@components/widgets/Mode.svelte'; export let project: Project; export let original: Project | undefined = undefined; @@ -1404,21 +1406,33 @@ toggle={toggleBlocks} on={$blocks} /> - - l.ui.source.toggle.localized.on, - )} - offLabel={withVariationSelector('🌎')} - offTip={$locales.get( - (l) => - l.ui.source.toggle.localized - .off, + l.ui.dialog.settings.mode + .localized, )} - toggle={(on) => - Settings.setLocalized(on)} - on={$localized} + choice={$localized === 'actual' + ? 0 + : $localized === 'localized' + ? 1 + : 2} + select={(choice) => + Settings.setLocalized( + choice === 0 + ? 'actual' + : choice === 1 + ? 'localized' + : 'symbolic', + )} + modes={[ + '...', + toLocaleString( + $locales.getLocale(), + ), + '😀', + ]} /> {#each VisibleNavigateCommands as command}
🐲
diff --git a/src/components/project/RootView.svelte b/src/components/project/RootView.svelte index 46d4c10f2..36f423f58 100644 --- a/src/components/project/RootView.svelte +++ b/src/components/project/RootView.svelte @@ -25,6 +25,7 @@ import FormattedLiteral from '../../nodes/FormattedLiteral'; import type Caret from '@edit/Caret'; import getPreferredSpaces from '@parser/getPreferredSpaces'; + import type { LocalizedValue } from '@db/LocalizedSetting'; export let node: Node; /** Optional space. To enable preferred space, set flag below. */ @@ -34,7 +35,7 @@ /** If inline, and true, this will be a maximum width */ export let elide = false; /** If true, hides names and docs not in a selected locale */ - export let localized = false; + export let localized: LocalizedValue = 'symbolic'; export let caret: Caret | undefined = undefined; /** Get the root, or make one if it's not a source. */ @@ -58,9 +59,9 @@ let hidden = writable>(new Set()); setContext(HiddenSymbol, hidden); - let localize = writable(localized); + let localize = writable(localized ?? 'symbolic'); setContext(LocalizeSymbol, localize); - $: localize.set(localized); + $: localize.set(localized ?? 'symbolic'); // Update what's hidden. $: { diff --git a/src/components/widgets/Mode.svelte b/src/components/widgets/Mode.svelte index 8efb5c9f6..fe32fd274 100644 --- a/src/components/widgets/Mode.svelte +++ b/src/components/widgets/Mode.svelte @@ -8,10 +8,13 @@ export let choice: number; export let select: (choice: number) => void; export let active = true; + export let labeled = true;
- {descriptions.label} + {#if labeled} + {descriptions.label} + {/if}
{#each modes as mode, index} diff --git a/src/db/LocalizedSetting.ts b/src/db/LocalizedSetting.ts index c3b1cc889..db62fbcfa 100644 --- a/src/db/LocalizedSetting.ts +++ b/src/db/LocalizedSetting.ts @@ -1,9 +1,24 @@ import Setting from './Setting'; -export const LocalizedSetting = new Setting( +export type LocalizedValue = 'actual' | 'localized' | 'symbolic'; + +export const LocalizedSetting = new Setting( 'localized', true, - false, - () => true, - (current, value) => current === value + 'localized', + (value) => + // An old boolean value? Convert to one of the three states. + typeof value === 'boolean' + ? value + ? 'localized' + : 'actual' + : // A string value? Check if it's one of the three states, and default to localized if not. + typeof value === 'string' && + (value === 'actual' || + value === 'localized' || + value === 'symbolic') + ? undefined + : // Some other mystery type? Default to localized. + 'localized', + (current, value) => current === value, ); diff --git a/src/db/Setting.ts b/src/db/Setting.ts index f79272ca3..bf84cde75 100644 --- a/src/db/Setting.ts +++ b/src/db/Setting.ts @@ -18,7 +18,7 @@ export default class Setting { device: boolean, defaultValue: Type, validator: (value: unknown) => Type | undefined, - equal: (current: Type, value: Type) => boolean + equal: (current: Type, value: Type) => boolean, ) { this.key = key; this.device = device; @@ -39,7 +39,8 @@ export default class Setting { try { if (valueString !== null) { const parsed = JSON.parse(valueString); - if (this.validator(parsed)) value = parsed; + const validation = this.validator(parsed); + value = validation; } if (value === undefined) value = this.defaultValue; } catch (_) { diff --git a/src/db/SettingsDatabase.ts b/src/db/SettingsDatabase.ts index 6bd53f20d..dd52a5a2a 100644 --- a/src/db/SettingsDatabase.ts +++ b/src/db/SettingsDatabase.ts @@ -18,7 +18,7 @@ import type { WritingLayout } from '../locale/Scripts'; import type Progress from '../tutorial/Progress'; import Layout from '../components/project/Layout'; import { BlocksSetting } from './BlocksSetting'; -import { LocalizedSetting } from './LocalizedSetting'; +import { LocalizedSetting, type LocalizedValue } from './LocalizedSetting'; import { DarkSetting } from './DarkSetting'; import { doc, getDoc } from 'firebase/firestore'; import { firestore } from './firebase'; @@ -190,8 +190,8 @@ export default class SettingsDatabase { return this.settings.localized.get(); } - setLocalized(on: boolean) { - this.settings.localized.set(this.database, on); + setLocalized(value: LocalizedValue) { + this.settings.localized.set(this.database, value); } /** To serialize to a database */ diff --git a/src/locale/UITexts.ts b/src/locale/UITexts.ts index a053e2cf4..bdcc10f32 100644 --- a/src/locale/UITexts.ts +++ b/src/locale/UITexts.ts @@ -213,8 +213,6 @@ type UITexts = { blocks: ToggleText; /** The glyph chooser expand/collapse toggle */ glyphs: ToggleText; - /** The localized on/off toggle */ - localized: ToggleText; }; button: { /** Output preview button for selecting output for display in output tile */ @@ -604,6 +602,8 @@ type UITexts = { writing: ModeText<[string, string, string]>; /** The space_indicator on/off mode */ space: ModeText<[string, string]>; + /** The localized none/localized/symbolic mode */ + localized: ModeText<[string, string, string]>; }; options: { /** The label for the microphone drop down */ diff --git a/src/locale/en-US.json b/src/locale/en-US.json index 9e5780a86..90ea8555d 100644 --- a/src/locale/en-US.json +++ b/src/locale/en-US.json @@ -4065,10 +4065,6 @@ "on": "hide block backgrounds", "off": "show block backgrounds" }, - "localized": { - "on": "show localized text", - "off": "show all text" - }, "glyphs": { "on": "collapse the matching glyphs", "off": "expand the matching glyphs" @@ -4308,6 +4304,14 @@ "vertical, right to left", "vertical, left to right" ] + }, + "localized": { + "label": "code localization", + "modes": [ + "do not localize code", + "localize code when available", + "localize code but prefer symbols" + ] } }, "options": { diff --git a/src/nodes/Token.ts b/src/nodes/Token.ts index 357faec28..7f5075517 100644 --- a/src/nodes/Token.ts +++ b/src/nodes/Token.ts @@ -153,7 +153,12 @@ export default class Token extends Node { return [getTokenLabel(this, locales), this.getText()]; } - localized(locales: Locale[], root: Root, context: Context) { + localized( + symbolic: boolean, + locales: Locale[], + root: Root, + context: Context, + ) { // Get this token's text let text = this.getText(); @@ -203,9 +208,7 @@ export default class Token extends Node { if (parent) { def = parent.getCorrespondingDefinition(context); if (def) { - text = - def.names.getSymbolicName() ?? - def.names.getPreferredNameString(locales); + text = def.names.getPreferredNameString(locales, symbolic); } } } diff --git a/static/locales/es-MX/es-MX.json b/static/locales/es-MX/es-MX.json index bdb81560e..e9a971f1e 100644 --- a/static/locales/es-MX/es-MX.json +++ b/static/locales/es-MX/es-MX.json @@ -4079,10 +4079,6 @@ "on": "esconder los fondos de los bloques", "off": "mostrar los fondos de los bloques" }, - "localized": { - "on": "mostrar texto localizado", - "off": "mostrar todo el texto" - }, "glyphs": { "on": "colapsar los glifos coincidentes", "off": "expandir los glifos coincidentes" @@ -4324,6 +4320,14 @@ "vertical, de derecha a izquierda", "vertical, de izquierda a derecha" ] + }, + "localized": { + "label": "localización de código", + "modes": [ + "no localizar el código", + "localizar el código cuando esté disponible", + "localizar el código pero preferir símbolos" + ] } }, "options": { diff --git a/static/locales/example/example.json b/static/locales/example/example.json index dfb93b789..538b74da1 100644 --- a/static/locales/example/example.json +++ b/static/locales/example/example.json @@ -2353,10 +2353,6 @@ "on": "$?", "off": "$?" }, - "localized": { - "on": "$?", - "off": "$?" - }, "glyphs": { "on": "$?", "off": "$?" @@ -2579,6 +2575,10 @@ "writing": { "label": "$?", "modes": ["$?", "$?", "$?"] + }, + "localized": { + "label": "$?", + "modes": ["$?", "$?", "$?"] } }, "options": { diff --git a/static/locales/ko-KR/ko-KR.json b/static/locales/ko-KR/ko-KR.json index 21435ecc5..ce6a6cbf0 100644 --- a/static/locales/ko-KR/ko-KR.json +++ b/static/locales/ko-KR/ko-KR.json @@ -2854,10 +2854,6 @@ "on": "$?", "off": "$?" }, - "localized": { - "on": "$?", - "off": "$?" - }, "glyphs": { "on": "$?", "off": "$?" @@ -3080,6 +3076,14 @@ "writing": { "label": "$?", "modes": ["$?", "$?", "$?"] + }, + "localized": { + "label": "코드 현지화", + "modes": [ + "코드를 현지화하지 마세요", + "가능한 경우 코드 현지화", + "코드를 현지화하지만 기호를 선호합니다." + ] } }, "options": { diff --git a/static/locales/zh-CN/zh-CN.json b/static/locales/zh-CN/zh-CN.json index 33c37c705..5472eaf4e 100644 --- a/static/locales/zh-CN/zh-CN.json +++ b/static/locales/zh-CN/zh-CN.json @@ -3909,10 +3909,6 @@ "on": "隐藏块背景", "off": "显示块背景" }, - "localized": { - "on": "显示本地化的文本", - "off": "显示本所有文本" - }, "glyphs": { "on": "折叠匹配的字形", "off": "展开匹配的字形" @@ -4145,6 +4141,14 @@ "垂直,从右到左", "垂直,从左到右" ] + }, + "localized": { + "label": "代码本地化", + "modes": [ + "不本地化代码", + "可用时本地化代码", + "本地化代码但更喜欢符号" + ] } }, "options": { diff --git a/static/locales/zh-TW/zh-TW.json b/static/locales/zh-TW/zh-TW.json index 6b2d98332..5c91e0163 100644 --- a/static/locales/zh-TW/zh-TW.json +++ b/static/locales/zh-TW/zh-TW.json @@ -3890,10 +3890,6 @@ "on": "隱藏區塊背景", "off": "顯示區塊背景" }, - "localized": { - "on": "顯示本地化的文字", - "off": "顯示本所有文字" - }, "glyphs": { "on": "折疊匹配的字形", "off": "展開符合的字形" @@ -4126,6 +4122,14 @@ "垂直,由右到左", "垂直,由左至右" ] + }, + "localized": { + "label": "程式碼本地化", + "modes": [ + "不本地化程式碼", + "本地化可用的程式碼", + "本地化代碼但更喜歡符號" + ] } }, "options": { diff --git a/static/schemas/Locale.json b/static/schemas/Locale.json index e57b9986e..5392e91c4 100644 --- a/static/schemas/Locale.json +++ b/static/schemas/Locale.json @@ -8676,6 +8676,10 @@ "$ref": "#/definitions/ModeText%3C%5Bstring%2Cstring%2Cstring%2Cstring%5D%3E", "description": "The project tile layout mode" }, + "localized": { + "$ref": "#/definitions/ModeText%3C%5Bstring%2Cstring%2Cstring%5D%3E", + "description": "The localized none/localized/symbolic mode" + }, "space": { "$ref": "#/definitions/ModeText%3C%5Bstring%2Cstring%5D%3E", "description": "The space_indicator on/off mode" @@ -8690,7 +8694,8 @@ "animate", "dark", "writing", - "space" + "space", + "localized" ], "type": "object" }, @@ -10877,16 +10882,11 @@ "glyphs": { "$ref": "#/definitions/ToggleText", "description": "The glyph chooser expand/collapse toggle" - }, - "localized": { - "$ref": "#/definitions/ToggleText", - "description": "The localized on/off toggle" } }, "required": [ "blocks", - "glyphs", - "localized" + "glyphs" ], "type": "object" }