Skip to content

0021: Offerwall Localization Vertical Slice

STATUS

Accepted

CONTEXT

Adgem identified a significant revenue opportunity through localization of offerwall content for international markets. The primary driver was working with publisher Shopback who required localized offers in Traditional Chinese and other languages.

The need for dynamic, scalable localization became apparent as manual translation workflows would not be sustainable for growing international business requirements. This led to the decision to implement a comprehensive localization feature as a vertical slice, covering the full stack from data storage to AI-powered translation services.

Business Requirements

  • Support for Traditional Chinese initially (Shopback requirement)
  • Extensible architecture to support additional languages (German, and others)
  • Capability of translating dynamic content using AI services
  • Fallback mechanisms for translation failures
  • Feature flag controlled rollout
  • Minimal impact on existing functionality

Scope of Localization

Based on discovery with Shopback and analysis of offerwall content, the following fields were identified for translation:

Campaign Offerwall Creative: - basic_requirements - offer_instructions

Goal: - description

Campaign: - No fields required for translation

Considered Options

Option 1: Third-Party Translation Service Integration

  • Integration with services like Crowdin and Loom
  • Real-time translation on content delivery
  • Caching layer for translated content

Pros: - Established translation services - Multiple service options - Time to integration - More-streamlined human review process - More granular model selection flexibility

Cons: - Higher cost - Limited customization for domain-specific terminology - Vendor lock-in concerns - Variable quality for specialized content - Selling features that we don't really need

Option 2: OpenAI-Powered Translation Service (Selected)

  • Custom TranslationService using OpenAI API
  • Integration with spatie/laravel-translatable package

Pros: - High-quality, context-aware translations - Language specific prompts to promote better prompt engineering - Can incorporate business rules and tone preferences - Future extensibility for other AI capabilities

Cons: - Dependency on OpenAI service availability - Potential for temperature to introduce variance in translations

DECISION

We chose Option 2: OpenAI-Powered Translation Service with the following architectural approach:

Accessing and Mutating Translatable fields

  • Selected spatie/laravel-translatable package to store and retrieve data. Spatie package was selected over others due to their reputation and maintenance quality
  • Converted targeted fields to JSON format storing translations as {"en": "English text", "zh-TW": "Traditional Chinese text"}
  • Needed to override getTranslation acccessors to allow backwards compatibility (e.g. support both goal description both as a string or as a translation json).

With these changes to the Eloquents model(s) in place, it's easy to update content, even if you don't know that the field is translatable. This

$goal->description = 'foo';
$goal->save();

updates the goal's en key, resulting in {"en": "foo", "zh-TW": "Traditional Chinese text"}.

Similarly, accessing a model is also easy. Just use the accessor like normal:

$goal->description; // returns 'foo'

In both cases, the language that's accessed / mutated is whatever is set in the App::Locale. By default, this in en. But this system makes it easy to service requests in foreign locales; simply set the locale at the beginning of the thread, and that locale will be used for the entirety of the request lifecycle.

App::setLocale('zh-TW');
$goal->description; // returns 'Traditional Chinese text'

Generating Translations

sequenceDiagram participant Translation Trigger participant TranslateCampaignJob participant TranslationService participant OpenAIAPI Translation Trigger->>TranslateCampaignJob: Dispatch TranslateCampaignJob TranslateCampaignJob->>TranslationService: Translate description of each goal TranslationService->>OpenAIAPI: Request translation OpenAIAPI-->>TranslationService: Return translation TranslationService-->>TranslateCampaignJob: Receive translation TranslateCampaignJob->>TranslationService: Translate offer_instructions TranslationService->>OpenAIAPI: Request translation OpenAIAPI-->>TranslationService: Return translation TranslationService-->>TranslateCampaignJob: Receive translation TranslateCampaignJob->>TranslationService: Translate basic_requirements TranslationService->>OpenAIAPI: Request translation OpenAIAPI-->>TranslationService: Return translation TranslationService-->>TranslateCampaignJob: Receive translation

1. Translation Triggers

One of these four actions will trigger a (re)translation - BulkTranslateCampaigns command - TranslateCampaignsForApp command - CampaignController@update - when a campaign is updated in the adgem dashboard and one of the (English) value of one of the translatable fields changes - CampaignController@store - when a campaign is created (via clone or import from Tune) in the adgem dashboard

2. TranslateCampaignJob

  • Queued background job for translating campaign content
  • Input: Campaign ID + target locale(s)
  • Processing: Translates all translatable fields across campaign's offerwall creative and goals

3. TranslationService

  • Wrapper around OpenAI API calls
  • Input: Instructions to translate a string from English to desired language
  • Output: Translated string in target language
  • Preservation of placeholder values (e.g., {attribution_window})
  • Error handling and retry logic
Configurable Features:

NOTES

References

  • CAMP-312: Offerwall Localization Discovery & V1 Implementation (Epic)
  • CAMP-317: Create Feature Flag for Campaign Delivery Localization
  • CAMP-318: Update Goal to be translatable
  • CAMP-327: Feature documentation for localization
  • CAMP-328: Update dynamic translation (Traditional Chinese feedback)
  • CAMP-336: ADR of impact of spatie/laravel-translatable
  • AGPI-1356: Language Localization - Create TranslationService component
  • AGPI-1357: Language Localization - Create TranslateCampaignJob component

Original Author

Ben Giese

Approval Date

08/07/2025

Approved By

Liam Mohebbi, Ron White

APPENDIX

Supported Languages (Initial)

  • English (en) - Source language
  • German (de)
  • Traditional Chinese - Taiwan (zh-TW)
  • Traditional Chinese - Hong Kong(zh-HK)