generaltranslation 9.4.0 → 9.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"internal.cjs","names":["unwrapApiResult","decodeFileContent","DEFAULT_BATCH_SIZE","encodeFileContent","isGTUnindexedSelectElement","VAR_IDENTIFIER","isGTUnindexedSelectElement","VAR_IDENTIFIER","TYPE","traverseIcu","isGTIndexedSelectElement"],"sources":["../src/settings/plurals.ts","../src/locales/getPluralForm.ts","../src/utils/minify.ts","../src/adapter/createGtApi.ts","../src/derive/indexVars.ts","../src/derive/extractVars.ts","../src/derive/condenseVars.ts"],"sourcesContent":["export const pluralForms = [\n 'singular',\n 'plural',\n 'dual',\n 'zero',\n 'one',\n 'two',\n 'few',\n 'many',\n 'other',\n] as const;\nexport type PluralType = (typeof pluralForms)[number];\nexport function isAcceptedPluralForm(form: string): form is PluralType {\n return pluralForms.includes(form as (typeof pluralForms)[number]);\n}\n","import { getCachedPluralRules } from '@generaltranslation/format/internal';\n\nimport { pluralForms, PluralType } from '../settings/plurals';\nimport { libraryDefaultLocale } from '../settings/settings';\n\n/**\n * Given a number and a list of allowed plural forms, return the plural form that best fits the number.\n *\n * @param {number} n - The number to determine the plural form for.\n * @param {PluralType[]} forms - The allowed plural forms.\n * @returns {PluralType} The determined plural form, or an empty string if none fit.\n */\nexport function _getPluralForm(\n n: number,\n forms: readonly PluralType[] = pluralForms,\n locales: string[] = [libraryDefaultLocale]\n): PluralType | '' {\n const pluralRules = getCachedPluralRules(locales);\n const provisionalBranchName = pluralRules.select(n);\n // aliases\n const absN = Math.abs(n);\n // 0\n if (absN === 0 && forms.includes('zero')) return 'zero'; // override\n // 1\n if (absN === 1) {\n if (forms.includes('singular')) return 'singular'; // override\n if (forms.includes('one')) return 'one'; // override\n }\n if (provisionalBranchName === 'one' && forms.includes('singular'))\n return 'singular';\n // 2\n if (absN === 2) {\n if (forms.includes('dual')) return 'dual'; // override\n if (forms.includes('two')) return 'two'; // override\n }\n if (provisionalBranchName === 'two' && forms.includes('dual')) return 'dual';\n // fallbacks\n if (forms.includes(provisionalBranchName)) return provisionalBranchName;\n if (forms.includes('plural')) return 'plural';\n if (forms.includes('other')) return 'other';\n return '';\n}\n","import { VariableTransformationSuffix, VariableType } from '../types';\n\nconst VARIABLE_TRANSFORMATION_SUFFIXES_TO_MINIFIED_NAMES = {\n variable: 'v',\n number: 'n',\n datetime: 'd',\n currency: 'c',\n 'relative-time': 'rt',\n} as const;\n\nexport function minifyVariableType(\n variableType: VariableTransformationSuffix\n): VariableType {\n return VARIABLE_TRANSFORMATION_SUFFIXES_TO_MINIFIED_NAMES[variableType];\n}\n","import {\n createApiClient,\n createBranch,\n DEFAULT_BATCH_SIZE,\n downloadFiles,\n enqueueFileTranslations,\n generateProjectContext,\n getFileInfo,\n getTranslationJobInfo,\n pollJobs,\n processBatches,\n uploadSourceFiles,\n uploadTranslations,\n type ApiClientConfig,\n type AwaitJobsOptions,\n type CreateBranchData,\n type DownloadFilesData,\n type EnqueueFileTranslationsData,\n type GenerateProjectContextData,\n type GetFileInfoData,\n type UploadSourceFilesData,\n type UploadTranslationsData,\n} from '@generaltranslation/api';\nimport {\n resolveAliasLocale,\n resolveCanonicalLocale,\n} from '@generaltranslation/format';\nimport type { CustomMapping } from '@generaltranslation/format/types';\nimport type { DownloadedFile } from '../types-dir/api/downloadFileBatch';\nimport { decodeFileContent, encodeFileContent } from '../utils/base64';\nimport { unwrapApiResult } from '../translate/utils/unwrapApiResult';\n\nexport type GtApiAdapterConfig = ApiClientConfig & {\n customMapping?: CustomMapping;\n};\n\nexport function createGtApiAdapter(defaultConfig?: ApiClientConfig) {\n let client = defaultConfig ? createApiClient(defaultConfig) : undefined;\n let configuredClientConfig = defaultConfig;\n let customMapping: CustomMapping | undefined;\n\n function getClient(): ReturnType<typeof createApiClient> {\n if (!client) {\n throw new Error(\n 'API client not configured — call configureApiClient first'\n );\n }\n return client;\n }\n\n function getClientConfig(): ApiClientConfig {\n if (!configuredClientConfig) {\n throw new Error(\n 'API client not configured — call configureApiClient first'\n );\n }\n return configuredClientConfig;\n }\n\n function configure(config: GtApiAdapterConfig): void {\n const { customMapping: mapping, ...clientConfig } = config;\n client = createApiClient(clientConfig);\n configuredClientConfig = clientConfig;\n customMapping = mapping;\n }\n\n return {\n configure,\n getClient,\n getClientConfig,\n\n resolveAliasLocale(locale: string) {\n return resolveAliasLocale(locale, customMapping);\n },\n\n resolveCanonicalLocale(locale: string) {\n return resolveCanonicalLocale(locale, customMapping);\n },\n\n async createBranch(body: CreateBranchData['body']) {\n return unwrapApiResult(await createBranch({ body, client: getClient() }));\n },\n\n async queryFileData(body: GetFileInfoData['body']) {\n const result = unwrapApiResult(\n await getFileInfo({\n body: {\n ...body,\n translatedFiles: body.translatedFiles?.map((file) => ({\n ...file,\n locale: resolveCanonicalLocale(file.locale, customMapping),\n })),\n },\n client: getClient(),\n })\n );\n return {\n ...result,\n translatedFiles: result.translatedFiles.map((file) => ({\n ...file,\n locale: resolveAliasLocale(file.locale, customMapping),\n })),\n sourceFiles: result.sourceFiles.map((file) => ({\n ...file,\n sourceLocale: resolveAliasLocale(file.sourceLocale, customMapping),\n locales: file.locales.map((locale) =>\n resolveAliasLocale(locale, customMapping)\n ),\n })),\n };\n },\n\n async downloadFileBatch(files: DownloadFilesData['body']) {\n const request = async (batch: DownloadFilesData['body']) =>\n unwrapApiResult(\n await downloadFiles({\n body: batch.map((file) => ({\n ...file,\n locale: file.locale\n ? resolveCanonicalLocale(file.locale, customMapping)\n : undefined,\n })),\n client: getClient(),\n })\n );\n const responses = await processBatches(files, async (batch) => [\n await request(batch),\n ]);\n return {\n files: responses.flatMap((response) =>\n response.files.map(\n (file): DownloadedFile => ({\n ...file,\n ...(file.locale && {\n locale: resolveAliasLocale(file.locale, customMapping),\n }),\n data: decodeFileContent(file.data, file.fileFormat),\n // OpenAPI currently types metadata as an open object; the API emits\n // JSON values here, matching DownloadedFile's public contract.\n metadata: file.metadata as DownloadedFile['metadata'],\n })\n )\n ),\n count: responses.reduce((count, response) => count + response.count, 0),\n pending: responses.flatMap((response) => response.pending ?? []),\n };\n },\n\n async setupProject(\n files: GenerateProjectContextData['body']['files'],\n options: Omit<GenerateProjectContextData['body'], 'files'> = {}\n ) {\n return unwrapApiResult(\n await generateProjectContext({\n body: {\n files: files.map(({ branchId, fileId, versionId }) => ({\n branchId,\n fileId,\n versionId,\n })),\n locales: options.locales?.map((locale) =>\n resolveCanonicalLocale(locale, customMapping)\n ),\n force: options.force,\n },\n client: getClient(),\n })\n );\n },\n\n async enqueueFiles(\n files: EnqueueFileTranslationsData['body']['files'],\n options: {\n sourceLocale?: string;\n targetLocales: string[];\n modelProvider?: string;\n force?: boolean;\n }\n ) {\n const targetLocales = options.targetLocales.map((locale) =>\n resolveCanonicalLocale(locale, customMapping)\n );\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await enqueueFileTranslations({\n body: {\n files: batch.map(\n ({\n branchId,\n fileId,\n versionId,\n fileName,\n transformFormat,\n }) => ({\n branchId,\n fileId,\n versionId,\n fileName,\n transformFormat,\n })\n ),\n targetLocales,\n sourceLocale: options.sourceLocale\n ? resolveCanonicalLocale(options.sourceLocale, customMapping)\n : undefined,\n // Consumers intentionally accept custom model-provider strings beyond\n // the OpenAPI enum; preserve the existing wire behavior at this boundary.\n modelProvider:\n options.modelProvider as EnqueueFileTranslationsData['body']['modelProvider'],\n force: options.force,\n },\n client: getClient(),\n })\n );\n const jobData =\n 'jobData' in response ? response.jobData : response.data;\n return Object.entries(jobData);\n });\n\n return {\n jobData: Object.fromEntries(result),\n locales: targetLocales,\n message: `Successfully enqueued ${result.length} file translation jobs in ${Math.ceil(files.length / DEFAULT_BATCH_SIZE)} batch(es)`,\n };\n },\n\n async uploadSourceFiles(\n files: Array<{\n source: UploadSourceFilesData['body']['data'][number]['source'];\n }>,\n options: { sourceLocale: string }\n ) {\n const sourceLocale = resolveCanonicalLocale(\n options.sourceLocale,\n customMapping\n );\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadSourceFiles({\n body: {\n data: batch.map(({ source }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n locale: resolveCanonicalLocale(source.locale, customMapping),\n },\n })),\n sourceLocale,\n },\n client: getClient(),\n })\n );\n return response.uploadedFiles;\n });\n\n return { uploadedFiles: result };\n },\n\n async awaitJobs(jobIds: readonly string[], options?: AwaitJobsOptions) {\n return pollJobs(\n jobIds,\n async (pendingJobIds, signal) =>\n unwrapApiResult(\n await getTranslationJobInfo({\n body: { jobIds: pendingJobIds },\n client: getClient(),\n signal,\n })\n ),\n options\n );\n },\n\n async uploadTranslations(\n files: UploadTranslationsData['body']['data'],\n options: { sourceLocale: string }\n ) {\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadTranslations({\n body: {\n data: batch.map(({ source, translations }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n },\n translations: translations.map((translation) => ({\n ...translation,\n locale: resolveCanonicalLocale(\n translation.locale,\n customMapping\n ),\n content: encodeFileContent(\n translation.content,\n translation.fileFormat\n ),\n })),\n })),\n sourceLocale: resolveCanonicalLocale(\n options.sourceLocale,\n customMapping\n ),\n },\n client: getClient(),\n })\n );\n return response.uploadedFiles;\n });\n\n return { uploadedFiles: result };\n },\n };\n}\n\nexport type GtApiAdapter = ReturnType<typeof createGtApiAdapter>;\n","import { VAR_IDENTIFIER } from './utils/constants';\nimport { traverseIcu } from './utils/traverseIcu';\nimport { GTUnindexedSelectElement } from './utils/types';\nimport { isGTUnindexedSelectElement } from './utils/traverseHelpers';\nimport type { IcuMessage } from '@generaltranslation/format/types';\n\ntype Location = {\n start: number;\n end: number;\n otherStart: number;\n otherEnd: number;\n};\n\n/**\n * Given an ICU string adds identifiers to each _gt_ placeholder\n * indexVars('Hello {_gt_} {_gt_} World') => 'Hello {_gt_1_} {_gt_2_} World'\n */\nexport function indexVars(icuString: IcuMessage): string {\n // Check if the string contains _gt_\n if (!icuString.includes(VAR_IDENTIFIER)) {\n return icuString;\n }\n\n // Record the location of the variable\n const variableLocations: Location[] = [];\n function visitor(child: GTUnindexedSelectElement): void {\n variableLocations.push({\n start: child.location?.start.offset ?? 0,\n end: child.location?.end.offset ?? 0,\n otherStart: child.options.other.location?.start.offset ?? 0,\n otherEnd: child.options.other.location?.end.offset ?? 0,\n });\n }\n\n // Find all variable identifiers.\n traverseIcu({\n icuString,\n shouldVisit: isGTUnindexedSelectElement,\n visitor,\n options: { recurseIntoVisited: false, captureLocation: true },\n });\n\n // Index each variable and collapse the other option.\n const result = [];\n let current = 0;\n for (let i = 0; i < variableLocations.length; i++) {\n const { start, end, otherStart, otherEnd } = variableLocations[i];\n // Before the variable\n result.push(icuString.slice(current, start));\n // Replace the variable with the new identifier (+1 is for the curly brace)\n result.push(icuString.slice(start, start + VAR_IDENTIFIER.length + 1));\n\n // Add the new identifier.\n result.push(String(i + 1));\n // After the variable\n result.push(icuString.slice(start + VAR_IDENTIFIER.length + 1, otherStart));\n // Before the other option\n result.push('{}');\n // The other option\n result.push(icuString.slice(otherEnd, end));\n current = end;\n }\n result.push(icuString.slice(current, icuString.length));\n\n return result.join('');\n}\n","import { VAR_IDENTIFIER } from './utils/constants';\nimport { isGTUnindexedSelectElement } from './utils/traverseHelpers';\nimport { traverseIcu } from './utils/traverseIcu';\nimport { GTUnindexedSelectElement } from './utils/types';\n/**\n * Given an unindexed ICU string, extracts all the _gt_ variables and an indexed mapping of the variable to the values\n *\n * extractVars('Hello {_gt_, select, other {World}}') => { _gt_1: 'World' }\n *\n * @param {string} icuString - The ICU string to extract variables from.\n * @returns {Record<string, string>} A mapping of the variable to the value.\n */\nexport function extractVars(icuString: string): Record<string, string> {\n // Check if the string contains _gt_\n if (!icuString.includes(VAR_IDENTIFIER)) {\n return {};\n }\n\n // Extract all the _gt_# variables\n let index = 1;\n const variables: Record<string, string> = {};\n function visitor(child: GTUnindexedSelectElement): void {\n variables[child.value + index] = child.options.other.value.length\n ? child.options.other.value[0]?.value\n : '';\n index += 1;\n }\n\n traverseIcu({\n icuString,\n shouldVisit: isGTUnindexedSelectElement,\n visitor,\n options: { recurseIntoVisited: false },\n });\n\n return variables;\n}\n","import { printAST, TYPE, type ArgumentElement } from '@generaltranslation/icu';\nimport { traverseIcu } from './utils/traverseIcu';\nimport { VAR_IDENTIFIER } from './utils/constants';\nimport { GTIndexedSelectElement } from './utils/types';\nimport { isGTIndexedSelectElement } from './utils/traverseHelpers';\ninterface GTIndexedArgumentElement extends ArgumentElement {\n value: `${typeof VAR_IDENTIFIER}${number}`;\n}\n\nconst CONTAINS_INDEXED_GT_REGEX = new RegExp(`${VAR_IDENTIFIER}\\\\d+`);\n\n/**\n * Given an indexed ICU string, condenses any select to an argument\n * Unindexed _gt_ source strings and indexed _gt_# translation strings\n * are mutually exclusive.\n * indexVars('Hello {_gt_1, select, other {World}}') => 'Hello {_gt_1}'\n * @param {string} icuString - The ICU string to condense.\n * @returns {string} The condensed ICU string.\n */\nexport function condenseVars(icuString: string): string {\n // Check if the string contains an indexed _gt_ identifier.\n if (!CONTAINS_INDEXED_GT_REGEX.test(icuString)) {\n return icuString;\n }\n\n // Replace with argument\n function visitor(child: GTIndexedSelectElement): void {\n (child as unknown as GTIndexedArgumentElement).type = TYPE.argument;\n Reflect.deleteProperty(child, 'options');\n }\n\n const ast = traverseIcu({\n icuString,\n shouldVisit: isGTIndexedSelectElement,\n visitor,\n options: { recurseIntoVisited: false },\n });\n\n // Serialize\n return printAST(ast);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"internal.cjs","names":["unwrapApiResult","decodeFileContent","DEFAULT_BATCH_SIZE","encodeFileContent","isGTUnindexedSelectElement","VAR_IDENTIFIER","isGTUnindexedSelectElement","VAR_IDENTIFIER","TYPE","traverseIcu","isGTIndexedSelectElement"],"sources":["../src/settings/plurals.ts","../src/locales/getPluralForm.ts","../src/utils/minify.ts","../src/adapter/createGtApi.ts","../src/derive/indexVars.ts","../src/derive/extractVars.ts","../src/derive/condenseVars.ts"],"sourcesContent":["export const pluralForms = [\n 'singular',\n 'plural',\n 'dual',\n 'zero',\n 'one',\n 'two',\n 'few',\n 'many',\n 'other',\n] as const;\nexport type PluralType = (typeof pluralForms)[number];\nexport function isAcceptedPluralForm(form: string): form is PluralType {\n return pluralForms.includes(form as (typeof pluralForms)[number]);\n}\n","import { getCachedPluralRules } from '@generaltranslation/format/internal';\n\nimport { pluralForms, PluralType } from '../settings/plurals';\nimport { libraryDefaultLocale } from '../settings/settings';\n\n/**\n * Given a number and a list of allowed plural forms, return the plural form that best fits the number.\n *\n * @param {number} n - The number to determine the plural form for.\n * @param {PluralType[]} forms - The allowed plural forms.\n * @returns {PluralType} The determined plural form, or an empty string if none fit.\n */\nexport function _getPluralForm(\n n: number,\n forms: readonly PluralType[] = pluralForms,\n locales: string[] = [libraryDefaultLocale]\n): PluralType | '' {\n const pluralRules = getCachedPluralRules(locales);\n const provisionalBranchName = pluralRules.select(n);\n // aliases\n const absN = Math.abs(n);\n // 0\n if (absN === 0 && forms.includes('zero')) return 'zero'; // override\n // 1\n if (absN === 1) {\n if (forms.includes('singular')) return 'singular'; // override\n if (forms.includes('one')) return 'one'; // override\n }\n if (provisionalBranchName === 'one' && forms.includes('singular'))\n return 'singular';\n // 2\n if (absN === 2) {\n if (forms.includes('dual')) return 'dual'; // override\n if (forms.includes('two')) return 'two'; // override\n }\n if (provisionalBranchName === 'two' && forms.includes('dual')) return 'dual';\n // fallbacks\n if (forms.includes(provisionalBranchName)) return provisionalBranchName;\n if (forms.includes('plural')) return 'plural';\n if (forms.includes('other')) return 'other';\n return '';\n}\n","import { VariableTransformationSuffix, VariableType } from '../types';\n\nconst VARIABLE_TRANSFORMATION_SUFFIXES_TO_MINIFIED_NAMES = {\n variable: 'v',\n number: 'n',\n datetime: 'd',\n currency: 'c',\n 'relative-time': 'rt',\n} as const;\n\nexport function minifyVariableType(\n variableType: VariableTransformationSuffix\n): VariableType {\n return VARIABLE_TRANSFORMATION_SUFFIXES_TO_MINIFIED_NAMES[variableType];\n}\n","import {\n createApiClient,\n createBranch,\n DEFAULT_BATCH_SIZE,\n downloadFiles,\n enqueueFileTranslations,\n generateProjectContext,\n getFileInfo,\n getTranslationJobInfo,\n pollJobs,\n processBatches,\n uploadSourceFiles,\n uploadTranslations,\n type ApiClientConfig,\n type AwaitJobsOptions,\n type CreateBranchData,\n type DownloadFilesData,\n type EnqueueFileTranslationsData,\n type GenerateProjectContextData,\n type GetFileInfoData,\n type UploadSourceFilesData,\n type UploadTranslationsData,\n} from '@generaltranslation/api';\nimport {\n resolveAliasLocale,\n resolveCanonicalLocale,\n standardizeLocale,\n} from '@generaltranslation/format';\nimport type { CustomMapping } from '@generaltranslation/format/types';\nimport type { DownloadedFile } from '../types-dir/api/downloadFileBatch';\nimport { decodeFileContent, encodeFileContent } from '../utils/base64';\nimport { unwrapApiResult } from '../translate/utils/unwrapApiResult';\n\nexport type GtApiAdapterConfig = ApiClientConfig & {\n customMapping?: CustomMapping;\n};\n\nexport function createGtApiAdapter(defaultConfig?: ApiClientConfig) {\n let client = defaultConfig ? createApiClient(defaultConfig) : undefined;\n let configuredClientConfig = defaultConfig;\n let customMapping: CustomMapping | undefined;\n\n // Mapping resolves aliases; standardization also canonicalizes configured\n // spellings such as en-us before they cross the service boundary.\n function resolveServiceLocale(locale: string): string {\n return standardizeLocale(resolveCanonicalLocale(locale, customMapping));\n }\n\n function getClient(): ReturnType<typeof createApiClient> {\n if (!client) {\n throw new Error(\n 'API client not configured — call configureApiClient first'\n );\n }\n return client;\n }\n\n function getClientConfig(): ApiClientConfig {\n if (!configuredClientConfig) {\n throw new Error(\n 'API client not configured — call configureApiClient first'\n );\n }\n return configuredClientConfig;\n }\n\n function configure(config: GtApiAdapterConfig): void {\n const { customMapping: mapping, ...clientConfig } = config;\n client = createApiClient(clientConfig);\n configuredClientConfig = clientConfig;\n customMapping = mapping;\n }\n\n return {\n configure,\n getClient,\n getClientConfig,\n\n resolveAliasLocale(locale: string) {\n return resolveAliasLocale(locale, customMapping);\n },\n\n resolveCanonicalLocale(locale: string) {\n return resolveServiceLocale(locale);\n },\n\n async createBranch(body: CreateBranchData['body']) {\n return unwrapApiResult(await createBranch({ body, client: getClient() }));\n },\n\n async queryFileData(body: GetFileInfoData['body']) {\n const result = unwrapApiResult(\n await getFileInfo({\n body: {\n ...body,\n translatedFiles: body.translatedFiles?.map((file) => ({\n ...file,\n locale: resolveServiceLocale(file.locale),\n })),\n },\n client: getClient(),\n })\n );\n return {\n ...result,\n translatedFiles: result.translatedFiles.map((file) => ({\n ...file,\n locale: resolveAliasLocale(file.locale, customMapping),\n })),\n sourceFiles: result.sourceFiles.map((file) => ({\n ...file,\n sourceLocale: resolveAliasLocale(file.sourceLocale, customMapping),\n locales: file.locales.map((locale) =>\n resolveAliasLocale(locale, customMapping)\n ),\n })),\n };\n },\n\n async downloadFileBatch(files: DownloadFilesData['body']) {\n const request = async (batch: DownloadFilesData['body']) =>\n unwrapApiResult(\n await downloadFiles({\n body: batch.map((file) => ({\n ...file,\n locale: file.locale\n ? resolveServiceLocale(file.locale)\n : undefined,\n })),\n client: getClient(),\n })\n );\n const responses = await processBatches(files, async (batch) => [\n await request(batch),\n ]);\n return {\n files: responses.flatMap((response) =>\n response.files.map(\n (file): DownloadedFile => ({\n ...file,\n ...(file.locale && {\n locale: resolveAliasLocale(file.locale, customMapping),\n }),\n data: decodeFileContent(file.data, file.fileFormat),\n // OpenAPI currently types metadata as an open object; the API emits\n // JSON values here, matching DownloadedFile's public contract.\n metadata: file.metadata as DownloadedFile['metadata'],\n })\n )\n ),\n count: responses.reduce((count, response) => count + response.count, 0),\n pending: responses.flatMap((response) => response.pending ?? []),\n };\n },\n\n async setupProject(\n files: GenerateProjectContextData['body']['files'],\n options: Omit<GenerateProjectContextData['body'], 'files'> = {}\n ) {\n return unwrapApiResult(\n await generateProjectContext({\n body: {\n files: files.map(({ branchId, fileId, versionId }) => ({\n branchId,\n fileId,\n versionId,\n })),\n locales: options.locales?.map((locale) =>\n resolveServiceLocale(locale)\n ),\n force: options.force,\n },\n client: getClient(),\n })\n );\n },\n\n async enqueueFiles(\n files: EnqueueFileTranslationsData['body']['files'],\n options: {\n sourceLocale?: string;\n targetLocales: string[];\n modelProvider?: string;\n force?: boolean;\n }\n ) {\n const targetLocales = options.targetLocales.map((locale) =>\n resolveServiceLocale(locale)\n );\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await enqueueFileTranslations({\n body: {\n files: batch.map(\n ({\n branchId,\n fileId,\n versionId,\n fileName,\n transformFormat,\n }) => ({\n branchId,\n fileId,\n versionId,\n fileName,\n transformFormat,\n })\n ),\n targetLocales,\n sourceLocale: options.sourceLocale\n ? resolveServiceLocale(options.sourceLocale)\n : undefined,\n // Consumers intentionally accept custom model-provider strings beyond\n // the OpenAPI enum; preserve the existing wire behavior at this boundary.\n modelProvider:\n options.modelProvider as EnqueueFileTranslationsData['body']['modelProvider'],\n force: options.force,\n },\n client: getClient(),\n })\n );\n const jobData =\n 'jobData' in response ? response.jobData : response.data;\n return Object.entries(jobData);\n });\n\n return {\n jobData: Object.fromEntries(result),\n locales: targetLocales,\n message: `Successfully enqueued ${result.length} file translation jobs in ${Math.ceil(files.length / DEFAULT_BATCH_SIZE)} batch(es)`,\n };\n },\n\n async uploadSourceFiles(\n files: Array<{\n source: UploadSourceFilesData['body']['data'][number]['source'];\n }>,\n options: { sourceLocale: string }\n ) {\n const sourceLocale = resolveServiceLocale(options.sourceLocale);\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadSourceFiles({\n body: {\n data: batch.map(({ source }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n locale: resolveServiceLocale(source.locale),\n },\n })),\n sourceLocale,\n },\n client: getClient(),\n })\n );\n return response.uploadedFiles;\n });\n\n return { uploadedFiles: result };\n },\n\n async awaitJobs(jobIds: readonly string[], options?: AwaitJobsOptions) {\n return pollJobs(\n jobIds,\n async (pendingJobIds, signal) =>\n unwrapApiResult(\n await getTranslationJobInfo({\n body: { jobIds: pendingJobIds },\n client: getClient(),\n signal,\n })\n ),\n options\n );\n },\n\n async uploadTranslations(\n files: UploadTranslationsData['body']['data'],\n options: { sourceLocale: string }\n ) {\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadTranslations({\n body: {\n data: batch.map(({ source, translations }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n locale: resolveServiceLocale(source.locale),\n },\n translations: translations.map((translation) => ({\n ...translation,\n locale: resolveServiceLocale(translation.locale),\n content: encodeFileContent(\n translation.content,\n translation.fileFormat\n ),\n })),\n })),\n sourceLocale: resolveServiceLocale(options.sourceLocale),\n },\n client: getClient(),\n })\n );\n return response.uploadedFiles;\n });\n\n return { uploadedFiles: result };\n },\n };\n}\n\nexport type GtApiAdapter = ReturnType<typeof createGtApiAdapter>;\n","import { VAR_IDENTIFIER } from './utils/constants';\nimport { traverseIcu } from './utils/traverseIcu';\nimport { GTUnindexedSelectElement } from './utils/types';\nimport { isGTUnindexedSelectElement } from './utils/traverseHelpers';\nimport type { IcuMessage } from '@generaltranslation/format/types';\n\ntype Location = {\n start: number;\n end: number;\n otherStart: number;\n otherEnd: number;\n};\n\n/**\n * Given an ICU string adds identifiers to each _gt_ placeholder\n * indexVars('Hello {_gt_} {_gt_} World') => 'Hello {_gt_1_} {_gt_2_} World'\n */\nexport function indexVars(icuString: IcuMessage): string {\n // Check if the string contains _gt_\n if (!icuString.includes(VAR_IDENTIFIER)) {\n return icuString;\n }\n\n // Record the location of the variable\n const variableLocations: Location[] = [];\n function visitor(child: GTUnindexedSelectElement): void {\n variableLocations.push({\n start: child.location?.start.offset ?? 0,\n end: child.location?.end.offset ?? 0,\n otherStart: child.options.other.location?.start.offset ?? 0,\n otherEnd: child.options.other.location?.end.offset ?? 0,\n });\n }\n\n // Find all variable identifiers.\n traverseIcu({\n icuString,\n shouldVisit: isGTUnindexedSelectElement,\n visitor,\n options: { recurseIntoVisited: false, captureLocation: true },\n });\n\n // Index each variable and collapse the other option.\n const result = [];\n let current = 0;\n for (let i = 0; i < variableLocations.length; i++) {\n const { start, end, otherStart, otherEnd } = variableLocations[i];\n // Before the variable\n result.push(icuString.slice(current, start));\n // Replace the variable with the new identifier (+1 is for the curly brace)\n result.push(icuString.slice(start, start + VAR_IDENTIFIER.length + 1));\n\n // Add the new identifier.\n result.push(String(i + 1));\n // After the variable\n result.push(icuString.slice(start + VAR_IDENTIFIER.length + 1, otherStart));\n // Before the other option\n result.push('{}');\n // The other option\n result.push(icuString.slice(otherEnd, end));\n current = end;\n }\n result.push(icuString.slice(current, icuString.length));\n\n return result.join('');\n}\n","import { VAR_IDENTIFIER } from './utils/constants';\nimport { isGTUnindexedSelectElement } from './utils/traverseHelpers';\nimport { traverseIcu } from './utils/traverseIcu';\nimport { GTUnindexedSelectElement } from './utils/types';\n/**\n * Given an unindexed ICU string, extracts all the _gt_ variables and an indexed mapping of the variable to the values\n *\n * extractVars('Hello {_gt_, select, other {World}}') => { _gt_1: 'World' }\n *\n * @param {string} icuString - The ICU string to extract variables from.\n * @returns {Record<string, string>} A mapping of the variable to the value.\n */\nexport function extractVars(icuString: string): Record<string, string> {\n // Check if the string contains _gt_\n if (!icuString.includes(VAR_IDENTIFIER)) {\n return {};\n }\n\n // Extract all the _gt_# variables\n let index = 1;\n const variables: Record<string, string> = {};\n function visitor(child: GTUnindexedSelectElement): void {\n variables[child.value + index] = child.options.other.value.length\n ? child.options.other.value[0]?.value\n : '';\n index += 1;\n }\n\n traverseIcu({\n icuString,\n shouldVisit: isGTUnindexedSelectElement,\n visitor,\n options: { recurseIntoVisited: false },\n });\n\n return variables;\n}\n","import { printAST, TYPE, type ArgumentElement } from '@generaltranslation/icu';\nimport { traverseIcu } from './utils/traverseIcu';\nimport { VAR_IDENTIFIER } from './utils/constants';\nimport { GTIndexedSelectElement } from './utils/types';\nimport { isGTIndexedSelectElement } from './utils/traverseHelpers';\ninterface GTIndexedArgumentElement extends ArgumentElement {\n value: `${typeof VAR_IDENTIFIER}${number}`;\n}\n\nconst CONTAINS_INDEXED_GT_REGEX = new RegExp(`${VAR_IDENTIFIER}\\\\d+`);\n\n/**\n * Given an indexed ICU string, condenses any select to an argument\n * Unindexed _gt_ source strings and indexed _gt_# translation strings\n * are mutually exclusive.\n * indexVars('Hello {_gt_1, select, other {World}}') => 'Hello {_gt_1}'\n * @param {string} icuString - The ICU string to condense.\n * @returns {string} The condensed ICU string.\n */\nexport function condenseVars(icuString: string): string {\n // Check if the string contains an indexed _gt_ identifier.\n if (!CONTAINS_INDEXED_GT_REGEX.test(icuString)) {\n return icuString;\n }\n\n // Replace with argument\n function visitor(child: GTIndexedSelectElement): void {\n (child as unknown as GTIndexedArgumentElement).type = TYPE.argument;\n Reflect.deleteProperty(child, 'options');\n }\n\n const ast = traverseIcu({\n icuString,\n shouldVisit: isGTIndexedSelectElement,\n visitor,\n options: { recurseIntoVisited: false },\n });\n\n // Serialize\n return printAST(ast);\n}\n"],"mappings":"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"}
package/dist/internal.mjs CHANGED
@@ -2,7 +2,7 @@ import { a as defaultCacheUrl, c as formatDiagnosticErrorDetails, i as defaultBa
2
2
  import { a as isGTUnindexedSelectElement, c as decode, d as encodeFileContent, f as isSupportedFileFormatTransform, i as isGTIndexedSelectElement, l as decodeFileContent, n as declareVar, o as VAR_IDENTIFIER, p as API_VERSION, r as decodeVars, s as traverseIcu, t as derive, u as encode } from "./derive-CTzR56T_.mjs";
3
3
  import { t as isVariable } from "./isVariable-8-Wy5FnX.mjs";
4
4
  import { DEFAULT_BATCH_SIZE, createApiClient, createBranch, downloadFiles, enqueueFileTranslations, generateProjectContext, getFileInfo, getTranslationJobInfo, pollJobs, processBatches, uploadSourceFiles, uploadTranslations } from "@generaltranslation/api";
5
- import { resolveAliasLocale, resolveCanonicalLocale } from "@generaltranslation/format";
5
+ import { resolveAliasLocale, resolveCanonicalLocale, standardizeLocale } from "@generaltranslation/format";
6
6
  import { TYPE, printAST } from "@generaltranslation/icu";
7
7
  import { getCachedPluralRules } from "@generaltranslation/format/internal";
8
8
  //#region src/settings/plurals.ts
@@ -66,6 +66,9 @@ function createGtApiAdapter(defaultConfig) {
66
66
  let client = defaultConfig ? createApiClient(defaultConfig) : void 0;
67
67
  let configuredClientConfig = defaultConfig;
68
68
  let customMapping;
69
+ function resolveServiceLocale(locale) {
70
+ return standardizeLocale(resolveCanonicalLocale(locale, customMapping));
71
+ }
69
72
  function getClient() {
70
73
  if (!client) throw new Error("API client not configured — call configureApiClient first");
71
74
  return client;
@@ -88,7 +91,7 @@ function createGtApiAdapter(defaultConfig) {
88
91
  return resolveAliasLocale(locale, customMapping);
89
92
  },
90
93
  resolveCanonicalLocale(locale) {
91
- return resolveCanonicalLocale(locale, customMapping);
94
+ return resolveServiceLocale(locale);
92
95
  },
93
96
  async createBranch(body) {
94
97
  return unwrapApiResult(await createBranch({
@@ -102,7 +105,7 @@ function createGtApiAdapter(defaultConfig) {
102
105
  ...body,
103
106
  translatedFiles: body.translatedFiles?.map((file) => ({
104
107
  ...file,
105
- locale: resolveCanonicalLocale(file.locale, customMapping)
108
+ locale: resolveServiceLocale(file.locale)
106
109
  }))
107
110
  },
108
111
  client: getClient()
@@ -124,7 +127,7 @@ function createGtApiAdapter(defaultConfig) {
124
127
  const request = async (batch) => unwrapApiResult(await downloadFiles({
125
128
  body: batch.map((file) => ({
126
129
  ...file,
127
- locale: file.locale ? resolveCanonicalLocale(file.locale, customMapping) : void 0
130
+ locale: file.locale ? resolveServiceLocale(file.locale) : void 0
128
131
  })),
129
132
  client: getClient()
130
133
  }));
@@ -148,14 +151,14 @@ function createGtApiAdapter(defaultConfig) {
148
151
  fileId,
149
152
  versionId
150
153
  })),
151
- locales: options.locales?.map((locale) => resolveCanonicalLocale(locale, customMapping)),
154
+ locales: options.locales?.map((locale) => resolveServiceLocale(locale)),
152
155
  force: options.force
153
156
  },
154
157
  client: getClient()
155
158
  }));
156
159
  },
157
160
  async enqueueFiles(files, options) {
158
- const targetLocales = options.targetLocales.map((locale) => resolveCanonicalLocale(locale, customMapping));
161
+ const targetLocales = options.targetLocales.map((locale) => resolveServiceLocale(locale));
159
162
  const result = await processBatches(files, async (batch) => {
160
163
  const response = unwrapApiResult(await enqueueFileTranslations({
161
164
  body: {
@@ -167,7 +170,7 @@ function createGtApiAdapter(defaultConfig) {
167
170
  transformFormat
168
171
  })),
169
172
  targetLocales,
170
- sourceLocale: options.sourceLocale ? resolveCanonicalLocale(options.sourceLocale, customMapping) : void 0,
173
+ sourceLocale: options.sourceLocale ? resolveServiceLocale(options.sourceLocale) : void 0,
171
174
  modelProvider: options.modelProvider,
172
175
  force: options.force
173
176
  },
@@ -183,14 +186,14 @@ function createGtApiAdapter(defaultConfig) {
183
186
  };
184
187
  },
185
188
  async uploadSourceFiles(files, options) {
186
- const sourceLocale = resolveCanonicalLocale(options.sourceLocale, customMapping);
189
+ const sourceLocale = resolveServiceLocale(options.sourceLocale);
187
190
  return { uploadedFiles: await processBatches(files, async (batch) => {
188
191
  return unwrapApiResult(await uploadSourceFiles({
189
192
  body: {
190
193
  data: batch.map(({ source }) => ({ source: {
191
194
  ...source,
192
195
  content: encodeFileContent(source.content, source.fileFormat),
193
- locale: resolveCanonicalLocale(source.locale, customMapping)
196
+ locale: resolveServiceLocale(source.locale)
194
197
  } })),
195
198
  sourceLocale
196
199
  },
@@ -212,15 +215,16 @@ function createGtApiAdapter(defaultConfig) {
212
215
  data: batch.map(({ source, translations }) => ({
213
216
  source: {
214
217
  ...source,
215
- content: encodeFileContent(source.content, source.fileFormat)
218
+ content: encodeFileContent(source.content, source.fileFormat),
219
+ locale: resolveServiceLocale(source.locale)
216
220
  },
217
221
  translations: translations.map((translation) => ({
218
222
  ...translation,
219
- locale: resolveCanonicalLocale(translation.locale, customMapping),
223
+ locale: resolveServiceLocale(translation.locale),
220
224
  content: encodeFileContent(translation.content, translation.fileFormat)
221
225
  }))
222
226
  })),
223
- sourceLocale: resolveCanonicalLocale(options.sourceLocale, customMapping)
227
+ sourceLocale: resolveServiceLocale(options.sourceLocale)
224
228
  },
225
229
  client: getClient()
226
230
  })).uploadedFiles;
@@ -1 +1 @@
1
- {"version":3,"file":"internal.mjs","names":[],"sources":["../src/settings/plurals.ts","../src/locales/getPluralForm.ts","../src/utils/minify.ts","../src/adapter/createGtApi.ts","../src/derive/indexVars.ts","../src/derive/extractVars.ts","../src/derive/condenseVars.ts"],"sourcesContent":["export const pluralForms = [\n 'singular',\n 'plural',\n 'dual',\n 'zero',\n 'one',\n 'two',\n 'few',\n 'many',\n 'other',\n] as const;\nexport type PluralType = (typeof pluralForms)[number];\nexport function isAcceptedPluralForm(form: string): form is PluralType {\n return pluralForms.includes(form as (typeof pluralForms)[number]);\n}\n","import { getCachedPluralRules } from '@generaltranslation/format/internal';\n\nimport { pluralForms, PluralType } from '../settings/plurals';\nimport { libraryDefaultLocale } from '../settings/settings';\n\n/**\n * Given a number and a list of allowed plural forms, return the plural form that best fits the number.\n *\n * @param {number} n - The number to determine the plural form for.\n * @param {PluralType[]} forms - The allowed plural forms.\n * @returns {PluralType} The determined plural form, or an empty string if none fit.\n */\nexport function _getPluralForm(\n n: number,\n forms: readonly PluralType[] = pluralForms,\n locales: string[] = [libraryDefaultLocale]\n): PluralType | '' {\n const pluralRules = getCachedPluralRules(locales);\n const provisionalBranchName = pluralRules.select(n);\n // aliases\n const absN = Math.abs(n);\n // 0\n if (absN === 0 && forms.includes('zero')) return 'zero'; // override\n // 1\n if (absN === 1) {\n if (forms.includes('singular')) return 'singular'; // override\n if (forms.includes('one')) return 'one'; // override\n }\n if (provisionalBranchName === 'one' && forms.includes('singular'))\n return 'singular';\n // 2\n if (absN === 2) {\n if (forms.includes('dual')) return 'dual'; // override\n if (forms.includes('two')) return 'two'; // override\n }\n if (provisionalBranchName === 'two' && forms.includes('dual')) return 'dual';\n // fallbacks\n if (forms.includes(provisionalBranchName)) return provisionalBranchName;\n if (forms.includes('plural')) return 'plural';\n if (forms.includes('other')) return 'other';\n return '';\n}\n","import { VariableTransformationSuffix, VariableType } from '../types';\n\nconst VARIABLE_TRANSFORMATION_SUFFIXES_TO_MINIFIED_NAMES = {\n variable: 'v',\n number: 'n',\n datetime: 'd',\n currency: 'c',\n 'relative-time': 'rt',\n} as const;\n\nexport function minifyVariableType(\n variableType: VariableTransformationSuffix\n): VariableType {\n return VARIABLE_TRANSFORMATION_SUFFIXES_TO_MINIFIED_NAMES[variableType];\n}\n","import {\n createApiClient,\n createBranch,\n DEFAULT_BATCH_SIZE,\n downloadFiles,\n enqueueFileTranslations,\n generateProjectContext,\n getFileInfo,\n getTranslationJobInfo,\n pollJobs,\n processBatches,\n uploadSourceFiles,\n uploadTranslations,\n type ApiClientConfig,\n type AwaitJobsOptions,\n type CreateBranchData,\n type DownloadFilesData,\n type EnqueueFileTranslationsData,\n type GenerateProjectContextData,\n type GetFileInfoData,\n type UploadSourceFilesData,\n type UploadTranslationsData,\n} from '@generaltranslation/api';\nimport {\n resolveAliasLocale,\n resolveCanonicalLocale,\n} from '@generaltranslation/format';\nimport type { CustomMapping } from '@generaltranslation/format/types';\nimport type { DownloadedFile } from '../types-dir/api/downloadFileBatch';\nimport { decodeFileContent, encodeFileContent } from '../utils/base64';\nimport { unwrapApiResult } from '../translate/utils/unwrapApiResult';\n\nexport type GtApiAdapterConfig = ApiClientConfig & {\n customMapping?: CustomMapping;\n};\n\nexport function createGtApiAdapter(defaultConfig?: ApiClientConfig) {\n let client = defaultConfig ? createApiClient(defaultConfig) : undefined;\n let configuredClientConfig = defaultConfig;\n let customMapping: CustomMapping | undefined;\n\n function getClient(): ReturnType<typeof createApiClient> {\n if (!client) {\n throw new Error(\n 'API client not configured — call configureApiClient first'\n );\n }\n return client;\n }\n\n function getClientConfig(): ApiClientConfig {\n if (!configuredClientConfig) {\n throw new Error(\n 'API client not configured — call configureApiClient first'\n );\n }\n return configuredClientConfig;\n }\n\n function configure(config: GtApiAdapterConfig): void {\n const { customMapping: mapping, ...clientConfig } = config;\n client = createApiClient(clientConfig);\n configuredClientConfig = clientConfig;\n customMapping = mapping;\n }\n\n return {\n configure,\n getClient,\n getClientConfig,\n\n resolveAliasLocale(locale: string) {\n return resolveAliasLocale(locale, customMapping);\n },\n\n resolveCanonicalLocale(locale: string) {\n return resolveCanonicalLocale(locale, customMapping);\n },\n\n async createBranch(body: CreateBranchData['body']) {\n return unwrapApiResult(await createBranch({ body, client: getClient() }));\n },\n\n async queryFileData(body: GetFileInfoData['body']) {\n const result = unwrapApiResult(\n await getFileInfo({\n body: {\n ...body,\n translatedFiles: body.translatedFiles?.map((file) => ({\n ...file,\n locale: resolveCanonicalLocale(file.locale, customMapping),\n })),\n },\n client: getClient(),\n })\n );\n return {\n ...result,\n translatedFiles: result.translatedFiles.map((file) => ({\n ...file,\n locale: resolveAliasLocale(file.locale, customMapping),\n })),\n sourceFiles: result.sourceFiles.map((file) => ({\n ...file,\n sourceLocale: resolveAliasLocale(file.sourceLocale, customMapping),\n locales: file.locales.map((locale) =>\n resolveAliasLocale(locale, customMapping)\n ),\n })),\n };\n },\n\n async downloadFileBatch(files: DownloadFilesData['body']) {\n const request = async (batch: DownloadFilesData['body']) =>\n unwrapApiResult(\n await downloadFiles({\n body: batch.map((file) => ({\n ...file,\n locale: file.locale\n ? resolveCanonicalLocale(file.locale, customMapping)\n : undefined,\n })),\n client: getClient(),\n })\n );\n const responses = await processBatches(files, async (batch) => [\n await request(batch),\n ]);\n return {\n files: responses.flatMap((response) =>\n response.files.map(\n (file): DownloadedFile => ({\n ...file,\n ...(file.locale && {\n locale: resolveAliasLocale(file.locale, customMapping),\n }),\n data: decodeFileContent(file.data, file.fileFormat),\n // OpenAPI currently types metadata as an open object; the API emits\n // JSON values here, matching DownloadedFile's public contract.\n metadata: file.metadata as DownloadedFile['metadata'],\n })\n )\n ),\n count: responses.reduce((count, response) => count + response.count, 0),\n pending: responses.flatMap((response) => response.pending ?? []),\n };\n },\n\n async setupProject(\n files: GenerateProjectContextData['body']['files'],\n options: Omit<GenerateProjectContextData['body'], 'files'> = {}\n ) {\n return unwrapApiResult(\n await generateProjectContext({\n body: {\n files: files.map(({ branchId, fileId, versionId }) => ({\n branchId,\n fileId,\n versionId,\n })),\n locales: options.locales?.map((locale) =>\n resolveCanonicalLocale(locale, customMapping)\n ),\n force: options.force,\n },\n client: getClient(),\n })\n );\n },\n\n async enqueueFiles(\n files: EnqueueFileTranslationsData['body']['files'],\n options: {\n sourceLocale?: string;\n targetLocales: string[];\n modelProvider?: string;\n force?: boolean;\n }\n ) {\n const targetLocales = options.targetLocales.map((locale) =>\n resolveCanonicalLocale(locale, customMapping)\n );\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await enqueueFileTranslations({\n body: {\n files: batch.map(\n ({\n branchId,\n fileId,\n versionId,\n fileName,\n transformFormat,\n }) => ({\n branchId,\n fileId,\n versionId,\n fileName,\n transformFormat,\n })\n ),\n targetLocales,\n sourceLocale: options.sourceLocale\n ? resolveCanonicalLocale(options.sourceLocale, customMapping)\n : undefined,\n // Consumers intentionally accept custom model-provider strings beyond\n // the OpenAPI enum; preserve the existing wire behavior at this boundary.\n modelProvider:\n options.modelProvider as EnqueueFileTranslationsData['body']['modelProvider'],\n force: options.force,\n },\n client: getClient(),\n })\n );\n const jobData =\n 'jobData' in response ? response.jobData : response.data;\n return Object.entries(jobData);\n });\n\n return {\n jobData: Object.fromEntries(result),\n locales: targetLocales,\n message: `Successfully enqueued ${result.length} file translation jobs in ${Math.ceil(files.length / DEFAULT_BATCH_SIZE)} batch(es)`,\n };\n },\n\n async uploadSourceFiles(\n files: Array<{\n source: UploadSourceFilesData['body']['data'][number]['source'];\n }>,\n options: { sourceLocale: string }\n ) {\n const sourceLocale = resolveCanonicalLocale(\n options.sourceLocale,\n customMapping\n );\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadSourceFiles({\n body: {\n data: batch.map(({ source }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n locale: resolveCanonicalLocale(source.locale, customMapping),\n },\n })),\n sourceLocale,\n },\n client: getClient(),\n })\n );\n return response.uploadedFiles;\n });\n\n return { uploadedFiles: result };\n },\n\n async awaitJobs(jobIds: readonly string[], options?: AwaitJobsOptions) {\n return pollJobs(\n jobIds,\n async (pendingJobIds, signal) =>\n unwrapApiResult(\n await getTranslationJobInfo({\n body: { jobIds: pendingJobIds },\n client: getClient(),\n signal,\n })\n ),\n options\n );\n },\n\n async uploadTranslations(\n files: UploadTranslationsData['body']['data'],\n options: { sourceLocale: string }\n ) {\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadTranslations({\n body: {\n data: batch.map(({ source, translations }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n },\n translations: translations.map((translation) => ({\n ...translation,\n locale: resolveCanonicalLocale(\n translation.locale,\n customMapping\n ),\n content: encodeFileContent(\n translation.content,\n translation.fileFormat\n ),\n })),\n })),\n sourceLocale: resolveCanonicalLocale(\n options.sourceLocale,\n customMapping\n ),\n },\n client: getClient(),\n })\n );\n return response.uploadedFiles;\n });\n\n return { uploadedFiles: result };\n },\n };\n}\n\nexport type GtApiAdapter = ReturnType<typeof createGtApiAdapter>;\n","import { VAR_IDENTIFIER } from './utils/constants';\nimport { traverseIcu } from './utils/traverseIcu';\nimport { GTUnindexedSelectElement } from './utils/types';\nimport { isGTUnindexedSelectElement } from './utils/traverseHelpers';\nimport type { IcuMessage } from '@generaltranslation/format/types';\n\ntype Location = {\n start: number;\n end: number;\n otherStart: number;\n otherEnd: number;\n};\n\n/**\n * Given an ICU string adds identifiers to each _gt_ placeholder\n * indexVars('Hello {_gt_} {_gt_} World') => 'Hello {_gt_1_} {_gt_2_} World'\n */\nexport function indexVars(icuString: IcuMessage): string {\n // Check if the string contains _gt_\n if (!icuString.includes(VAR_IDENTIFIER)) {\n return icuString;\n }\n\n // Record the location of the variable\n const variableLocations: Location[] = [];\n function visitor(child: GTUnindexedSelectElement): void {\n variableLocations.push({\n start: child.location?.start.offset ?? 0,\n end: child.location?.end.offset ?? 0,\n otherStart: child.options.other.location?.start.offset ?? 0,\n otherEnd: child.options.other.location?.end.offset ?? 0,\n });\n }\n\n // Find all variable identifiers.\n traverseIcu({\n icuString,\n shouldVisit: isGTUnindexedSelectElement,\n visitor,\n options: { recurseIntoVisited: false, captureLocation: true },\n });\n\n // Index each variable and collapse the other option.\n const result = [];\n let current = 0;\n for (let i = 0; i < variableLocations.length; i++) {\n const { start, end, otherStart, otherEnd } = variableLocations[i];\n // Before the variable\n result.push(icuString.slice(current, start));\n // Replace the variable with the new identifier (+1 is for the curly brace)\n result.push(icuString.slice(start, start + VAR_IDENTIFIER.length + 1));\n\n // Add the new identifier.\n result.push(String(i + 1));\n // After the variable\n result.push(icuString.slice(start + VAR_IDENTIFIER.length + 1, otherStart));\n // Before the other option\n result.push('{}');\n // The other option\n result.push(icuString.slice(otherEnd, end));\n current = end;\n }\n result.push(icuString.slice(current, icuString.length));\n\n return result.join('');\n}\n","import { VAR_IDENTIFIER } from './utils/constants';\nimport { isGTUnindexedSelectElement } from './utils/traverseHelpers';\nimport { traverseIcu } from './utils/traverseIcu';\nimport { GTUnindexedSelectElement } from './utils/types';\n/**\n * Given an unindexed ICU string, extracts all the _gt_ variables and an indexed mapping of the variable to the values\n *\n * extractVars('Hello {_gt_, select, other {World}}') => { _gt_1: 'World' }\n *\n * @param {string} icuString - The ICU string to extract variables from.\n * @returns {Record<string, string>} A mapping of the variable to the value.\n */\nexport function extractVars(icuString: string): Record<string, string> {\n // Check if the string contains _gt_\n if (!icuString.includes(VAR_IDENTIFIER)) {\n return {};\n }\n\n // Extract all the _gt_# variables\n let index = 1;\n const variables: Record<string, string> = {};\n function visitor(child: GTUnindexedSelectElement): void {\n variables[child.value + index] = child.options.other.value.length\n ? child.options.other.value[0]?.value\n : '';\n index += 1;\n }\n\n traverseIcu({\n icuString,\n shouldVisit: isGTUnindexedSelectElement,\n visitor,\n options: { recurseIntoVisited: false },\n });\n\n return variables;\n}\n","import { printAST, TYPE, type ArgumentElement } from '@generaltranslation/icu';\nimport { traverseIcu } from './utils/traverseIcu';\nimport { VAR_IDENTIFIER } from './utils/constants';\nimport { GTIndexedSelectElement } from './utils/types';\nimport { isGTIndexedSelectElement } from './utils/traverseHelpers';\ninterface GTIndexedArgumentElement extends ArgumentElement {\n value: `${typeof VAR_IDENTIFIER}${number}`;\n}\n\nconst CONTAINS_INDEXED_GT_REGEX = new RegExp(`${VAR_IDENTIFIER}\\\\d+`);\n\n/**\n * Given an indexed ICU string, condenses any select to an argument\n * Unindexed _gt_ source strings and indexed _gt_# translation strings\n * are mutually exclusive.\n * indexVars('Hello {_gt_1, select, other {World}}') => 'Hello {_gt_1}'\n * @param {string} icuString - The ICU string to condense.\n * @returns {string} The condensed ICU string.\n */\nexport function condenseVars(icuString: string): string {\n // Check if the string contains an indexed _gt_ identifier.\n if (!CONTAINS_INDEXED_GT_REGEX.test(icuString)) {\n return icuString;\n }\n\n // Replace with argument\n function visitor(child: GTIndexedSelectElement): void {\n (child as unknown as GTIndexedArgumentElement).type = TYPE.argument;\n Reflect.deleteProperty(child, 'options');\n }\n\n const ast = traverseIcu({\n icuString,\n shouldVisit: isGTIndexedSelectElement,\n visitor,\n options: { recurseIntoVisited: false },\n });\n\n // Serialize\n return printAST(ast);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"internal.mjs","names":[],"sources":["../src/settings/plurals.ts","../src/locales/getPluralForm.ts","../src/utils/minify.ts","../src/adapter/createGtApi.ts","../src/derive/indexVars.ts","../src/derive/extractVars.ts","../src/derive/condenseVars.ts"],"sourcesContent":["export const pluralForms = [\n 'singular',\n 'plural',\n 'dual',\n 'zero',\n 'one',\n 'two',\n 'few',\n 'many',\n 'other',\n] as const;\nexport type PluralType = (typeof pluralForms)[number];\nexport function isAcceptedPluralForm(form: string): form is PluralType {\n return pluralForms.includes(form as (typeof pluralForms)[number]);\n}\n","import { getCachedPluralRules } from '@generaltranslation/format/internal';\n\nimport { pluralForms, PluralType } from '../settings/plurals';\nimport { libraryDefaultLocale } from '../settings/settings';\n\n/**\n * Given a number and a list of allowed plural forms, return the plural form that best fits the number.\n *\n * @param {number} n - The number to determine the plural form for.\n * @param {PluralType[]} forms - The allowed plural forms.\n * @returns {PluralType} The determined plural form, or an empty string if none fit.\n */\nexport function _getPluralForm(\n n: number,\n forms: readonly PluralType[] = pluralForms,\n locales: string[] = [libraryDefaultLocale]\n): PluralType | '' {\n const pluralRules = getCachedPluralRules(locales);\n const provisionalBranchName = pluralRules.select(n);\n // aliases\n const absN = Math.abs(n);\n // 0\n if (absN === 0 && forms.includes('zero')) return 'zero'; // override\n // 1\n if (absN === 1) {\n if (forms.includes('singular')) return 'singular'; // override\n if (forms.includes('one')) return 'one'; // override\n }\n if (provisionalBranchName === 'one' && forms.includes('singular'))\n return 'singular';\n // 2\n if (absN === 2) {\n if (forms.includes('dual')) return 'dual'; // override\n if (forms.includes('two')) return 'two'; // override\n }\n if (provisionalBranchName === 'two' && forms.includes('dual')) return 'dual';\n // fallbacks\n if (forms.includes(provisionalBranchName)) return provisionalBranchName;\n if (forms.includes('plural')) return 'plural';\n if (forms.includes('other')) return 'other';\n return '';\n}\n","import { VariableTransformationSuffix, VariableType } from '../types';\n\nconst VARIABLE_TRANSFORMATION_SUFFIXES_TO_MINIFIED_NAMES = {\n variable: 'v',\n number: 'n',\n datetime: 'd',\n currency: 'c',\n 'relative-time': 'rt',\n} as const;\n\nexport function minifyVariableType(\n variableType: VariableTransformationSuffix\n): VariableType {\n return VARIABLE_TRANSFORMATION_SUFFIXES_TO_MINIFIED_NAMES[variableType];\n}\n","import {\n createApiClient,\n createBranch,\n DEFAULT_BATCH_SIZE,\n downloadFiles,\n enqueueFileTranslations,\n generateProjectContext,\n getFileInfo,\n getTranslationJobInfo,\n pollJobs,\n processBatches,\n uploadSourceFiles,\n uploadTranslations,\n type ApiClientConfig,\n type AwaitJobsOptions,\n type CreateBranchData,\n type DownloadFilesData,\n type EnqueueFileTranslationsData,\n type GenerateProjectContextData,\n type GetFileInfoData,\n type UploadSourceFilesData,\n type UploadTranslationsData,\n} from '@generaltranslation/api';\nimport {\n resolveAliasLocale,\n resolveCanonicalLocale,\n standardizeLocale,\n} from '@generaltranslation/format';\nimport type { CustomMapping } from '@generaltranslation/format/types';\nimport type { DownloadedFile } from '../types-dir/api/downloadFileBatch';\nimport { decodeFileContent, encodeFileContent } from '../utils/base64';\nimport { unwrapApiResult } from '../translate/utils/unwrapApiResult';\n\nexport type GtApiAdapterConfig = ApiClientConfig & {\n customMapping?: CustomMapping;\n};\n\nexport function createGtApiAdapter(defaultConfig?: ApiClientConfig) {\n let client = defaultConfig ? createApiClient(defaultConfig) : undefined;\n let configuredClientConfig = defaultConfig;\n let customMapping: CustomMapping | undefined;\n\n // Mapping resolves aliases; standardization also canonicalizes configured\n // spellings such as en-us before they cross the service boundary.\n function resolveServiceLocale(locale: string): string {\n return standardizeLocale(resolveCanonicalLocale(locale, customMapping));\n }\n\n function getClient(): ReturnType<typeof createApiClient> {\n if (!client) {\n throw new Error(\n 'API client not configured — call configureApiClient first'\n );\n }\n return client;\n }\n\n function getClientConfig(): ApiClientConfig {\n if (!configuredClientConfig) {\n throw new Error(\n 'API client not configured — call configureApiClient first'\n );\n }\n return configuredClientConfig;\n }\n\n function configure(config: GtApiAdapterConfig): void {\n const { customMapping: mapping, ...clientConfig } = config;\n client = createApiClient(clientConfig);\n configuredClientConfig = clientConfig;\n customMapping = mapping;\n }\n\n return {\n configure,\n getClient,\n getClientConfig,\n\n resolveAliasLocale(locale: string) {\n return resolveAliasLocale(locale, customMapping);\n },\n\n resolveCanonicalLocale(locale: string) {\n return resolveServiceLocale(locale);\n },\n\n async createBranch(body: CreateBranchData['body']) {\n return unwrapApiResult(await createBranch({ body, client: getClient() }));\n },\n\n async queryFileData(body: GetFileInfoData['body']) {\n const result = unwrapApiResult(\n await getFileInfo({\n body: {\n ...body,\n translatedFiles: body.translatedFiles?.map((file) => ({\n ...file,\n locale: resolveServiceLocale(file.locale),\n })),\n },\n client: getClient(),\n })\n );\n return {\n ...result,\n translatedFiles: result.translatedFiles.map((file) => ({\n ...file,\n locale: resolveAliasLocale(file.locale, customMapping),\n })),\n sourceFiles: result.sourceFiles.map((file) => ({\n ...file,\n sourceLocale: resolveAliasLocale(file.sourceLocale, customMapping),\n locales: file.locales.map((locale) =>\n resolveAliasLocale(locale, customMapping)\n ),\n })),\n };\n },\n\n async downloadFileBatch(files: DownloadFilesData['body']) {\n const request = async (batch: DownloadFilesData['body']) =>\n unwrapApiResult(\n await downloadFiles({\n body: batch.map((file) => ({\n ...file,\n locale: file.locale\n ? resolveServiceLocale(file.locale)\n : undefined,\n })),\n client: getClient(),\n })\n );\n const responses = await processBatches(files, async (batch) => [\n await request(batch),\n ]);\n return {\n files: responses.flatMap((response) =>\n response.files.map(\n (file): DownloadedFile => ({\n ...file,\n ...(file.locale && {\n locale: resolveAliasLocale(file.locale, customMapping),\n }),\n data: decodeFileContent(file.data, file.fileFormat),\n // OpenAPI currently types metadata as an open object; the API emits\n // JSON values here, matching DownloadedFile's public contract.\n metadata: file.metadata as DownloadedFile['metadata'],\n })\n )\n ),\n count: responses.reduce((count, response) => count + response.count, 0),\n pending: responses.flatMap((response) => response.pending ?? []),\n };\n },\n\n async setupProject(\n files: GenerateProjectContextData['body']['files'],\n options: Omit<GenerateProjectContextData['body'], 'files'> = {}\n ) {\n return unwrapApiResult(\n await generateProjectContext({\n body: {\n files: files.map(({ branchId, fileId, versionId }) => ({\n branchId,\n fileId,\n versionId,\n })),\n locales: options.locales?.map((locale) =>\n resolveServiceLocale(locale)\n ),\n force: options.force,\n },\n client: getClient(),\n })\n );\n },\n\n async enqueueFiles(\n files: EnqueueFileTranslationsData['body']['files'],\n options: {\n sourceLocale?: string;\n targetLocales: string[];\n modelProvider?: string;\n force?: boolean;\n }\n ) {\n const targetLocales = options.targetLocales.map((locale) =>\n resolveServiceLocale(locale)\n );\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await enqueueFileTranslations({\n body: {\n files: batch.map(\n ({\n branchId,\n fileId,\n versionId,\n fileName,\n transformFormat,\n }) => ({\n branchId,\n fileId,\n versionId,\n fileName,\n transformFormat,\n })\n ),\n targetLocales,\n sourceLocale: options.sourceLocale\n ? resolveServiceLocale(options.sourceLocale)\n : undefined,\n // Consumers intentionally accept custom model-provider strings beyond\n // the OpenAPI enum; preserve the existing wire behavior at this boundary.\n modelProvider:\n options.modelProvider as EnqueueFileTranslationsData['body']['modelProvider'],\n force: options.force,\n },\n client: getClient(),\n })\n );\n const jobData =\n 'jobData' in response ? response.jobData : response.data;\n return Object.entries(jobData);\n });\n\n return {\n jobData: Object.fromEntries(result),\n locales: targetLocales,\n message: `Successfully enqueued ${result.length} file translation jobs in ${Math.ceil(files.length / DEFAULT_BATCH_SIZE)} batch(es)`,\n };\n },\n\n async uploadSourceFiles(\n files: Array<{\n source: UploadSourceFilesData['body']['data'][number]['source'];\n }>,\n options: { sourceLocale: string }\n ) {\n const sourceLocale = resolveServiceLocale(options.sourceLocale);\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadSourceFiles({\n body: {\n data: batch.map(({ source }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n locale: resolveServiceLocale(source.locale),\n },\n })),\n sourceLocale,\n },\n client: getClient(),\n })\n );\n return response.uploadedFiles;\n });\n\n return { uploadedFiles: result };\n },\n\n async awaitJobs(jobIds: readonly string[], options?: AwaitJobsOptions) {\n return pollJobs(\n jobIds,\n async (pendingJobIds, signal) =>\n unwrapApiResult(\n await getTranslationJobInfo({\n body: { jobIds: pendingJobIds },\n client: getClient(),\n signal,\n })\n ),\n options\n );\n },\n\n async uploadTranslations(\n files: UploadTranslationsData['body']['data'],\n options: { sourceLocale: string }\n ) {\n const result = await processBatches(files, async (batch) => {\n const response = unwrapApiResult(\n await uploadTranslations({\n body: {\n data: batch.map(({ source, translations }) => ({\n source: {\n ...source,\n content: encodeFileContent(source.content, source.fileFormat),\n locale: resolveServiceLocale(source.locale),\n },\n translations: translations.map((translation) => ({\n ...translation,\n locale: resolveServiceLocale(translation.locale),\n content: encodeFileContent(\n translation.content,\n translation.fileFormat\n ),\n })),\n })),\n sourceLocale: resolveServiceLocale(options.sourceLocale),\n },\n client: getClient(),\n })\n );\n return response.uploadedFiles;\n });\n\n return { uploadedFiles: result };\n },\n };\n}\n\nexport type GtApiAdapter = ReturnType<typeof createGtApiAdapter>;\n","import { VAR_IDENTIFIER } from './utils/constants';\nimport { traverseIcu } from './utils/traverseIcu';\nimport { GTUnindexedSelectElement } from './utils/types';\nimport { isGTUnindexedSelectElement } from './utils/traverseHelpers';\nimport type { IcuMessage } from '@generaltranslation/format/types';\n\ntype Location = {\n start: number;\n end: number;\n otherStart: number;\n otherEnd: number;\n};\n\n/**\n * Given an ICU string adds identifiers to each _gt_ placeholder\n * indexVars('Hello {_gt_} {_gt_} World') => 'Hello {_gt_1_} {_gt_2_} World'\n */\nexport function indexVars(icuString: IcuMessage): string {\n // Check if the string contains _gt_\n if (!icuString.includes(VAR_IDENTIFIER)) {\n return icuString;\n }\n\n // Record the location of the variable\n const variableLocations: Location[] = [];\n function visitor(child: GTUnindexedSelectElement): void {\n variableLocations.push({\n start: child.location?.start.offset ?? 0,\n end: child.location?.end.offset ?? 0,\n otherStart: child.options.other.location?.start.offset ?? 0,\n otherEnd: child.options.other.location?.end.offset ?? 0,\n });\n }\n\n // Find all variable identifiers.\n traverseIcu({\n icuString,\n shouldVisit: isGTUnindexedSelectElement,\n visitor,\n options: { recurseIntoVisited: false, captureLocation: true },\n });\n\n // Index each variable and collapse the other option.\n const result = [];\n let current = 0;\n for (let i = 0; i < variableLocations.length; i++) {\n const { start, end, otherStart, otherEnd } = variableLocations[i];\n // Before the variable\n result.push(icuString.slice(current, start));\n // Replace the variable with the new identifier (+1 is for the curly brace)\n result.push(icuString.slice(start, start + VAR_IDENTIFIER.length + 1));\n\n // Add the new identifier.\n result.push(String(i + 1));\n // After the variable\n result.push(icuString.slice(start + VAR_IDENTIFIER.length + 1, otherStart));\n // Before the other option\n result.push('{}');\n // The other option\n result.push(icuString.slice(otherEnd, end));\n current = end;\n }\n result.push(icuString.slice(current, icuString.length));\n\n return result.join('');\n}\n","import { VAR_IDENTIFIER } from './utils/constants';\nimport { isGTUnindexedSelectElement } from './utils/traverseHelpers';\nimport { traverseIcu } from './utils/traverseIcu';\nimport { GTUnindexedSelectElement } from './utils/types';\n/**\n * Given an unindexed ICU string, extracts all the _gt_ variables and an indexed mapping of the variable to the values\n *\n * extractVars('Hello {_gt_, select, other {World}}') => { _gt_1: 'World' }\n *\n * @param {string} icuString - The ICU string to extract variables from.\n * @returns {Record<string, string>} A mapping of the variable to the value.\n */\nexport function extractVars(icuString: string): Record<string, string> {\n // Check if the string contains _gt_\n if (!icuString.includes(VAR_IDENTIFIER)) {\n return {};\n }\n\n // Extract all the _gt_# variables\n let index = 1;\n const variables: Record<string, string> = {};\n function visitor(child: GTUnindexedSelectElement): void {\n variables[child.value + index] = child.options.other.value.length\n ? child.options.other.value[0]?.value\n : '';\n index += 1;\n }\n\n traverseIcu({\n icuString,\n shouldVisit: isGTUnindexedSelectElement,\n visitor,\n options: { recurseIntoVisited: false },\n });\n\n return variables;\n}\n","import { printAST, TYPE, type ArgumentElement } from '@generaltranslation/icu';\nimport { traverseIcu } from './utils/traverseIcu';\nimport { VAR_IDENTIFIER } from './utils/constants';\nimport { GTIndexedSelectElement } from './utils/types';\nimport { isGTIndexedSelectElement } from './utils/traverseHelpers';\ninterface GTIndexedArgumentElement extends ArgumentElement {\n value: `${typeof VAR_IDENTIFIER}${number}`;\n}\n\nconst CONTAINS_INDEXED_GT_REGEX = new RegExp(`${VAR_IDENTIFIER}\\\\d+`);\n\n/**\n * Given an indexed ICU string, condenses any select to an argument\n * Unindexed _gt_ source strings and indexed _gt_# translation strings\n * are mutually exclusive.\n * indexVars('Hello {_gt_1, select, other {World}}') => 'Hello {_gt_1}'\n * @param {string} icuString - The ICU string to condense.\n * @returns {string} The condensed ICU string.\n */\nexport function condenseVars(icuString: string): string {\n // Check if the string contains an indexed _gt_ identifier.\n if (!CONTAINS_INDEXED_GT_REGEX.test(icuString)) {\n return icuString;\n }\n\n // Replace with argument\n function visitor(child: GTIndexedSelectElement): void {\n (child as unknown as GTIndexedArgumentElement).type = TYPE.argument;\n Reflect.deleteProperty(child, 'options');\n }\n\n const ast = traverseIcu({\n icuString,\n shouldVisit: isGTIndexedSelectElement,\n visitor,\n options: { recurseIntoVisited: false },\n });\n\n // Serialize\n return printAST(ast);\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { l as defaultTimeout, r as unwrapApiResult, s as createDiagnosticMessage
2
2
  import { t as ApiError } from "./ApiError-CUKcz3YS.mjs";
3
3
  import { t as hashSource } from "./id-X2zyx5Jk.mjs";
4
4
  import { createApiClient, translate } from "@generaltranslation/api";
5
- import { LocaleConfig, determineLocale, getRegionProperties, isValidLocale, requiresTranslation, resolveAliasLocale, resolveCanonicalLocale, standardizeLocale } from "@generaltranslation/format";
5
+ import { LocaleConfig, getRegionProperties, isValidLocale, requiresTranslation, resolveAliasLocale, resolveCanonicalLocale } from "@generaltranslation/format";
6
6
  //#region src/logging/errors.ts
7
7
  const GT_SOURCE = "GT";
8
8
  const translationTimeoutError = (timeout) => createDiagnosticMessage({
@@ -410,23 +410,23 @@ var GTRuntime = class {
410
410
  this.setConfig(params);
411
411
  }
412
412
  setConfig({ apiKey, devApiKey, sourceLocale, targetLocale, locales, projectId, customMapping, baseUrl }) {
413
+ const effectiveCustomMapping = customMapping ?? this.customMapping;
413
414
  if (apiKey) this.apiKey = apiKey;
414
415
  if (devApiKey) this.devApiKey = devApiKey;
415
416
  if (projectId) this.projectId = projectId;
416
417
  if (sourceLocale) {
417
- this.sourceLocale = standardizeLocale(sourceLocale);
418
- if (!isValidLocale(this.sourceLocale, customMapping)) throw new Error(invalidLocaleError(this.sourceLocale));
418
+ this.sourceLocale = sourceLocale;
419
+ if (!isValidLocale(this.sourceLocale, effectiveCustomMapping)) throw new Error(invalidLocaleError(this.sourceLocale));
419
420
  }
420
421
  if (targetLocale) {
421
- this.targetLocale = standardizeLocale(targetLocale);
422
- if (!isValidLocale(this.targetLocale, customMapping)) throw new Error(invalidLocaleError(this.targetLocale));
422
+ this.targetLocale = targetLocale;
423
+ if (!isValidLocale(this.targetLocale, effectiveCustomMapping)) throw new Error(invalidLocaleError(this.targetLocale));
423
424
  }
424
425
  if (locales) {
425
426
  const result = [];
426
427
  const invalidLocales = [];
427
428
  locales.forEach((locale) => {
428
- const standardizedLocale = standardizeLocale(locale);
429
- if (isValidLocale(standardizedLocale)) result.push(standardizedLocale);
429
+ if (isValidLocale(locale, effectiveCustomMapping)) result.push(locale);
430
430
  else invalidLocales.push(locale);
431
431
  });
432
432
  if (invalidLocales.length > 0) throw new Error(invalidLocalesError(invalidLocales));
@@ -443,6 +443,24 @@ var GTRuntime = class {
443
443
  customMapping: this.customMapping
444
444
  });
445
445
  }
446
+ /** Convert app identity only where a GT service expects a language code. */
447
+ resolveServiceLocale(locale) {
448
+ return this.standardizeLocale(this.resolveCanonicalLocale(locale));
449
+ }
450
+ /**
451
+ * Recover configured spelling without negotiating an unrelated dialect.
452
+ * When several identities use the same service code and there is no request
453
+ * context to disambiguate them, the first configured identity wins.
454
+ */
455
+ resolveServiceResponseLocale(locale) {
456
+ const canonical = this.standardizeLocale(locale);
457
+ return [
458
+ ...this.locales ?? [],
459
+ this.sourceLocale,
460
+ this.targetLocale,
461
+ ...Object.keys(this.customMapping ?? {})
462
+ ].find((candidate) => candidate && this.resolveServiceLocale(candidate) === canonical) ?? locale;
463
+ }
446
464
  _getTranslationConfig() {
447
465
  return {
448
466
  baseUrl: this.baseUrl,
@@ -489,8 +507,8 @@ var GTRuntime = class {
489
507
  gtInstanceLogger.error(error);
490
508
  throw new Error(error);
491
509
  }
492
- targetLocale = this.resolveCanonicalLocale(targetLocale);
493
- const sourceLocale = this.resolveCanonicalLocale(options?.sourceLocale || this.sourceLocale || "en");
510
+ targetLocale = this.resolveServiceLocale(targetLocale);
511
+ const sourceLocale = this.resolveServiceLocale(options?.sourceLocale || this.sourceLocale || "en");
494
512
  return (await _translateMany([source], {
495
513
  ...options,
496
514
  targetLocale,
@@ -506,8 +524,8 @@ var GTRuntime = class {
506
524
  gtInstanceLogger.error(error);
507
525
  throw new Error(error);
508
526
  }
509
- targetLocale = this.resolveCanonicalLocale(targetLocale);
510
- const sourceLocale = this.resolveCanonicalLocale(options?.sourceLocale || this.sourceLocale || "en");
527
+ targetLocale = this.resolveServiceLocale(targetLocale);
528
+ const sourceLocale = this.resolveServiceLocale(options?.sourceLocale || this.sourceLocale || "en");
511
529
  return await _translateMany(sources, {
512
530
  ...options,
513
531
  targetLocale,
@@ -832,7 +850,7 @@ var GTRuntime = class {
832
850
  */
833
851
  determineLocale(locales, approvedLocales = this.locales || [], customMapping = this.customMapping) {
834
852
  if (customMapping === this.customMapping) return this.localeConfig.determineLocale(locales, approvedLocales ?? []);
835
- return determineLocale(locales, approvedLocales, customMapping);
853
+ return new LocaleConfig({ customMapping }).determineLocale(locales, approvedLocales ?? []);
836
854
  }
837
855
  /**
838
856
  * Gets the text direction for a given locale code.
@@ -953,4 +971,4 @@ var GTRuntime = class {
953
971
  //#endregion
954
972
  export { gtInstanceLogger as a, translationRequestFailedError as c, fetchLogger as i, translationTimeoutError as l, validateResponse as n, noSourceLocaleProvidedError as o, fetchWithTimeout as r, noTargetLocaleProvidedError as s, GTRuntime as t };
955
973
 
956
- //# sourceMappingURL=runtime-BiKgjDUI.mjs.map
974
+ //# sourceMappingURL=runtime-Bcp4F2ME.mjs.map